プログラマでありたい

おっさんになっても、プログラマでありつづけたい

Google PlayからAndroidアプリのランキングを取得する

 前回、手軽にAppStoreからiOSアプリのランキングを取得する方法を紹介しました。Androidの場合は、どうしたら良いのでしょう?幾つか方法を考えてみます。対象は売上トップのAndroidアプリとして、URLは次の通りです。
https://play.google.com/store/apps/collection/topgrossing?hl=ja

  1. import.io + Google スプレッドシートのあわせ技
  2. Google スプレッドシートのIMPORTXML関数で何とかする
  3. Google Apps Scriptで頑張る
  4. みんな大好きExcelを使う

import.io + Google スプレッドシートのあわせ技



 まず試すのが、import.ioとGoogle スプレッドシートのあわせ技です。これで実現できれば、一番ラクです。

import.ioでログインし、New ExtractorでURLを指定します。すると下記のように、自動的に項目を抽出してくれます。
f:id:dkfj:20161008101245p:plain

ただ、何か辺です。どう見ても日本のランキングには見えません。恐らくIPアドレスを元に実行元の国のランキングを出しているっぽいです。残念です。

 ちなみに、取得結果をGoogle スプレッドシートに吐き出すのは簡単です。作成したEcxtactorからIntegrateタグを選び、Google Sheetsを選ぶとImportData形式の関数を吐き出してくれます。それをスプレッドシートに貼るだけです。

f:id:dkfj:20161008101257p:plain

 簡単なので、国内のデータが取れないのが残念です。
※別解として、AWSのAPI Gatewayを日本に用意して、HTTP Proxyとして返すという手はあるかも。

Google スプレッドシートのIMPORTXML関数で何とかする


 それでは、次にGoogle スプレッドシートのImportXML関数です。先程の実行元IPがあるので、そもそもGoogle スプレッドシートがどこで実行されているか確認する必要があります。httpサーバーを立ててアクセスし、ログからIPアドレスを取得します。その結果を、IPアドレスの素性が解るサイトで検索します。

f:id:dkfj:20161008105657p:plain

 見事にアメリカのカリフォルニアからのアクセスです。残念ながら、何とかなりませんでした。こちらも、Proxy的なモノを用意してとかなら何とか出来るかもしれませんが、一般的では無くなるので、止めておきます。

Google Apps Scriptで頑張る


 次に、Google Apps Scriptで頑張れるか確認してみます。前回と同様に、IPアドレスの素性を調べます。

f:id:dkfj:20161008110017p:plain

 今度は、アメリカのヴァージニア州でした。こちらは、GAEで動いているんだなと、変に納得してしまいます。と言う事で、Google Apps Scriptでも頑張れませんでした。

みんな大好きExcelを使う



 クラウド上のサービスが駄目なら、ローカルから実行すれば良いじゃないか。ということで、みんな大好きなExcelを使ってみましょう。Excelから外部データを取得するには、大きく2つの手段があります。

1. WebService関数を使う
2. VBA+IEでスクレイピング機能

 まず簡単なWebService関数を使ってみましょう。この関数は、URLを指定するだけというお手軽な関数です。

f:id:dkfj:20161008113245p:plain

 エラーが出ています。この関数の弱点として、文字数制限があります。元々Excelのセルの制限に、32,767文字というものがあります。それに引きづられて、関数の取得できる文字列のMaxも32,767文字に制限されています。最近のHTMLだと、殆どの場合が超えてしまいます。RSSとか取得するには、良いんですけどね。今回は使えません。残念。

 仕方がないので、VBA+IEで行ってみましょう。処理の概要としては、VBAからInternetExplorerを立ち上げ、HTMLElementCollectionで必要な部分のHTML要素を抜き出すという方法です。この方法の詳細は、こちらをご参照ください。

Excel VBA+IEでのスクレイピング


 取得方法としては、"card no-rationale square-cover apps small"というclass名指定するとランキングのリストが取得します。そこから、子のオブジェクトを指定するという形になります。その結果をシートに保存します。面倒くさいですね。

Option Explicit
Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)

Private objIE As InternetExplorer

Sub main()
    Set objIE = New InternetExplorer
    Dim url
    Dim baseUrl
    
    baseUrl = "https://play.google.com"
    url = baseUrl & "/store/apps/collection/topgrossing?hl=ja"
    objIE.Visible = True
    objIE.Navigate2 (url)
    
    '読み込み完了待ち
    While objIE.readyState <> READYSTATE_COMPLETE Or objIE.Busy = True
        DoEvents
        Sleep 100
    Wend
    Sleep 100
    
    Dim objDoc As HTMLElementCollection
    Set objDoc = objIE.document
    Dim element As IHTMLElement
    Dim title
    Dim path
    Dim row
    row = 1
    
    For Each element In objDoc.getElementsByClassName("card no-rationale square-cover apps small")
        title = element.Children(0).Children(2).Children(1).innerText
        path = element.Children(0).Children(2).Children(1).getAttribute("href")
    
        Worksheets(1).Cells(row, 1) = title
        Worksheets(1).Cells(row, 2) = baseUrl & path
        
        row = row + 1
    Next element
    
    objIE.Quit
    Set objIE = Nothing
End Sub

取得結果は、次のような形になります。
f:id:dkfj:20161008132611p:plain

まとめ


 まさかのExcelを使う羽目になってしまいました。クラウド上のWebサービスは便利なのですが、実行元の制限ができません。クライアント側のIPアドレスによって、国を判別するという処理には極めて弱くなります。AWSのAPI GatewayのHTTP Proxyを使うとか、回避方法は色々あるのですが本筋ではないので省略します。とりあえずIPアドレスを元に判別という処理は、なくしてほしいですねと勝手な願いで終わりとさせて頂きます。

See Also:
AppStoreからiOSアプリのランキングを取得する
環境構築レスでAmazonの商品レビューを取得する
Google スプレッドシートの関数でWebからデータを取得する

AppStoreからiOSアプリのランキングを取得する

 スマホアプリの人気の動向を知りたい場合は、AppleのAppStoreとGoogle Playを見ると思います。今回は、それを自動的に取得する方法を紹介します。

AppStoreのRSS Feed GeneratorからURL取得



 AppStoreのランキングは、RSS Feedで配信されています。また、いつから存在するのか解らないのですが、このRSS Feedを生成するGeneratorサイトがあり、任意の国/カテゴリー/データ種別用のRSSを指定できるようになっています。

f:id:dkfj:20161007073726p:plain

RSS Generator

例えば、日本での有料のiOSアプリのトップ25を取得する場合は、次のようなURLとなります。
https://itunes.apple.com/jp/rss/topgrossingapplications/limit=25/genre=6015/xml


 取得できるXMLは、次のような形です。
f:id:dkfj:20161007074216p:plain

Google スプレッドシートで取得する



 それでは、取得したデータをGoogle スプレッドシート取得してみましょう。Google スプレッドシートには、幾つか外部データを取得するセル関数が存在します。今回は、ImportFeed関数が良いでしょう。関数の詳細については、この辺りを見てください。


Google スプレッドシートの関数でWebからデータを取得する

 ImportFeedの構文は、次のようになっています。

IMPORTFEED(URL, [クエリ], [見出し], [アイテム数])

 必須はURLのみで、後はオプションです。まずは、URLのみでの取得をしてみましょう。
f:id:dkfj:20161008092711p:plain

 デフォルトでは、Title,Author,URL,Summaryの4つの項目を取得します。しかし、このデータの場合はSummaryが大きすぎて見づらいです。そこで、項目指定で取得することにします。項目は、引数"クエリ"で指定します。欲しい値は、TitleとURLです。その場合、"items title"と"items url"といったように指定します。

=IMPORTFEED("https://itunes.apple.com/jp/rss/topgrossingapplications/limit=25/genre=6015/xml","items title","true")
=IMPORTFEED("https://itunes.apple.com/jp/rss/topgrossingapplications/limit=25/genre=6015/xml","items url","true")


※本当は、1つの関数で取得したいのですが、複数項目を指定する方法が解りませんでした。誰か教えてください。

 A1,A2のセルに上の二つの関数を並べると、次のような形になります。スッキリ!!
f:id:dkfj:20161008093831p:plain

まとめ



 AppStoreのランキングについては、RSSで配信されているので簡単に取得できます。一方で、Google PlayについてはRSSが提供されていません。次回、どうやったら楽に取れるか考えてみます。

See Also:
環境構築レスでAmazonの商品レビューを取得する
Google スプレッドシートの関数でWebからデータを取得する

環境構築レスでAmazonの商品レビューを取得する

 世の中、ひょんなことから思いもかけないようなデータが必要になる場合があります。そんな時に備えて、クローラー/スクレイピングのノウハウを持っているのは当たり前の時代です。(大嘘)
 そんな訳で、Webから簡単にデータを取ってくる方法を紹介します。取得する為に、サーバーやクライアントPCの実行環境を構築すると言った瞬間、8割の人が去っていきます。そこで、環境構築レスでデータを収拾する方法を考えてみます。また、ちょっと癖があるAmazonの商品レビューを例に考えてみます。

 今回の対象は、この2冊の本のデータを取得するとしましょう。
Amazon Web Services パターン別構築・運用ガイド
Rubyによるクローラー開発技法

ポイントとしては、次のとおりです。

  • 複数の本を引数指定で取ってこれるようにしたい
  • レビュー数が10件以上あるので改ページが必要。

 取得は、出来るだけ楽にしたいです。その為、サーバの構築といったことはなく出来るだけ誰でも使えるような環境を考えています。

  1. GoogleスプレットシートのImportXML関数を利用する
  2. ImportIOを利用する
  3. Google Apps Scriptを利用する
  4. AWS Lambdaを利用する

GoogleスプレットシートのImportXML関数を利用する


 お手軽という点でGoogleスプレットシートがまず考えられるのですが、今回の用途では、残念ながら使えません。何故なら、Amazonさんの方で対策されていて、データが返ってこないからです。下記は、curlでImportXML関数の
ユーザーエージェントを指定した場合です。200 O.K.が返ってくるもののデータは返してくれません。Amazonさんも色々あって困っているのでしょう。察してあげてください。

$ curl --head -H 'User-Agent: Mozilla/5.0 (compatible; GoogleDocs; apps-spreadsheets; +http://docs.google.com)' https://www.amazon.co.jp/product-reviews/4797382570/ref=cm_cr_getr_d_show_all?pageNumber=1

HTTP/1.1 200 OK
Server: Server
Date: Sun, 02 Oct 2016 03:44:39 GMT
Content-Type: text/html;charset=UTF-8
Content-Length: 336708
Connection: keep-alive
X-Frame-Options: SAMEORIGIN
cache-control: no-cache
pragma: no-cache
expires: -1
Content-Language: en-US
Vary: Accept-Encoding,User-Agent
Set-Cookie: session-id=351-5722232-0993809; Domain=.amazon.co.jp; Expires=Tue, 01-Jan-2036 08:00:01 GMT; Path=/
Set-Cookie: session-id-time=2082787201l; Domain=.amazon.co.jp; Expires=Tue, 01-Jan-2036 08:00:01 GMT; Path=/

 ということでGoogle スプレッドシートのセル関数は諦めます。
使い方については、こんな感じです。ちょっとしたことに、便利ですよ。

Google スプレッドシートの関数でWebからデータを取得する

ImportIOを利用する



 次にImportIOを利用する場合です。これは、良くもあり悪くもありです。サインアップして、Create New Extractorで新規の抽出を作成を開始します。この時は、URLを指定するだけでほぼ望みどおりのデータを取得できます。

f:id:dkfj:20161002124947p:plain

 1つの商品だけを取得する場合は、これでも良いかもしれません。問題点としては、複数のURLを取得する場合です。ImportIOの場合、同じサイト・構造のURLであれば複数のURLを指定できます。ただし、設定で指定する必要があります。また、吐き出されるデータは、全てのURLの収拾結果を1つのレスポンスで返すという形になります。その為、データを受けた方で更に切り分け処理が必要となります。また、改ページ等の対応も必要となります。
 ImportIOの有料版を利用すると解決出来ることが増えるのですが、$240/月からとなるのでかなりハードルが高いんですよね。

Google Apps Scriptを利用する



 Google スプレッドシートのセル関数がダメだとしたら、Google Apps Script(GAS)も考えてみましょう。GASのデータ取得の場合は、UrlFetchAppが便利です。Googleスプレッドシートで問題となったユーザーエージェントは、次のような形になります。

Mozilla/5.0 (compatible; Google-Apps-Script)

 これでアクセスすると、Amazon CAPTCHAが出てきて人間かどうか疑われます。GASでこれをクリアーしようとすると、哲学的に大変になります。

<html class=""a-no-js"" lang=""jp""><!--<![endif]--><head>
<meta http-equiv=""content-type"" content=""text/html; charset=Shift_JIS"">
<meta charset=""utf-8"">
<meta http-equiv=""X-UA-Compatible"" content=""IE=edge,chrome=1"">
<title dir=""ltr"">Amazon CAPTCHA</title>
<meta name=""viewport"" content=""width=device-width"">
<link rel=""stylesheet"" href=""https://images-na.ssl-images-amazon.com/images/G/01/AUIClients/AmazonUI-3c913031596ca78a3768f4e934b1cc02ce238101.secure.min._V1_.css"">

 Google Apps ScriptのUrlFetchAppは、ヘッダー情報も送れるのでユーザーエージェントの偽装ができます。

  // 1.HTMLの取得
  var url = "https://www.amazon.co.jp/product-reviews/4797382570/ref=cm_cr_getr_d_show_all?pageNumber=1";

  var postheader = {
    "useragent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36",
    "accept":"gzip",
    "timeout":"20000"
  }
  
  var parameters = {
    "method":"get",
    "muteHttpExceptions": true,
    "headers": postheader
  }
  
  var response = UrlFetchApp.fetch(url,parameters);
  //var content = response.getContentText("UTF-8");
  var content = response.getContentText();

 ここまでは順調ですが、GASを利用時の最大の問題点があります。デフォルトの機能では、XPath指定でのデータ取得が出来ません。サードパーティ製のツールを使うか、正規表現で抽出する必要があります。これが、超絶面倒くさいです。色々な方が検討しているのですが、HTMLをXML形式に変換して扱うのがベターのようです。ただし、問題点としては全てのHTMLが上手くXMLに変換できる訳ではないという点です。幾つか試行錯誤した所、Xml.parseして更にXmlService.parseすると比較的成功率は上がります。なんだ、このノウハウは。。。
 また無事、XML形式にしたとしてもエレメント操作をするのは非常に面倒くさいです。ということで、idやclass、或いはAttribute指定で取得する関数を作るのが吉です。この辺りのブログを参考にさせて頂きました。

Google Script Api で Webサイトスクレイピング - shohu33's diary
HTML/XMLをパースする - 技術のメモ帳

function myFunction() {
  // 1.HTMLの取得
  var url = "https://www.amazon.co.jp/product-reviews/4797382570/ref=cm_cr_getr_d_show_all?pageNumber=1";

  var postheader = {
    "useragent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36",
    "timeout":"50000"
  }
  
  var parameters = {
    "method":"get",
    "muteHttpExceptions": true,
    "headers": postheader
  }

  var content = UrlFetchApp.fetch(url, parameters).getContentText();
  Logger.log(content);
  var doc = Xml.parse(content, true);
  var bodyHtml = doc.html.body.toXmlString();
  doc = XmlService.parse(bodyHtml);
  var root = doc.getRootElement();

  // 2. シートの用意
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet=ss.getSheetByName("sheet1");
  writeSpreadsheet(sheet, 1, 1, '評価');
  writeSpreadsheet(sheet, 1, 2, 'レビュー日');
  writeSpreadsheet(sheet, 1, 3, 'レビュー内容');

  // 3. レビューリストの取得
  var reviewList = getElementsByClassName(root, 'a-section review');
  var row = 2;
  for each(var review in reviewList) {
    // 4. 個々のレビュー要素の抜き出し
    var rate = getElementByAttribute(review, 'data-hook', 'review-star-rating' ); //評価(レート)
    var review_date = getElementByAttribute(review, 'data-hook', 'review-date' ); //レビュー日
    var review_body = getElementByAttribute(review, 'data-hook', 'review-body' ); //レビュー内容
    
    // 5. シートに記載
    writeSpreadsheet(sheet, row, 1, rate.getValue());
    writeSpreadsheet(sheet, row, 2, review_date.getValue());
    writeSpreadsheet(sheet, row, 3, review_body.getValue());
    row++;
  }
}

function writeSpreadsheet(sheet, row, column, value) {
  sheet.getRange(row, column).setValue(value);
}

function getElementByAttribute(element, attributeToFind, valueToFind) {
  var descendants = element.getDescendants();
  for (var i in descendants) {
    var elem = descendants[i].asElement();
    if ( elem != null) {
      var e = elem.getAttribute(attributeToFind);
      if ( e != null && e.getValue() == valueToFind) return elem;
    }
  }
}

function getElementById(element, idToFind) {
  var descendants = element.getDescendants();
  for (var i in descendants) {
    var elem = descendants[i].asElement();
    if ( elem != null) {
      var id = elem.getAttribute('id');
      if ( id != null && id.getValue() == idToFind) return elem;
    }
  }
}

function getElementsByClassName(element, classToFind) {
  var data = [], descendants = element.getDescendants();
  descendants.push(element);
  for (var i in descendants) {
    var elem = descendants[i].asElement();
    if (elem != null) {
      var classes = elem.getAttribute('class');
      if (classes != null) {
        classes = classes.getValue();
        if (classes == classToFind) {
          data.push(elem);
        } else {
          classes = classes.split(' ');
          for (var j in classes) {
            if (classes[j] == classToFind) {
              data.push(elem);
              break;
            }
          }
        }
      }
    }
  }
  return data;
}

function getElementsByTagName(element, tagName) {
  var data = [], descendants = element.getDescendants();
  for(var i in descendants) {
    var elem = descendants[i].asElement();
    if ( elem != null && elem.getName() == tagName) data.push(elem);
  }
  return data;
}

 複数のURL指定とか、10件以上のコメント取得については、力尽きたので別エントリーで書きます。記録するシート別けて、総レビュー数からページ数を算出するだけなので、比較的簡単には作れます。
※これ誰か、エレガントに書いてくれませんかね。。。

 実行結果は、こんな感じです。なかなかいい感じでまとめられると思います。ただ、この行数を書けと言われると、ヤダと言う人が多いかもしれません。
f:id:dkfj:20161004005401p:plain

AWS Lambdaを利用する



 Lambdaを使う場合は、Node.jsかPythonを利用したらさっくりと書けます。例によって力尽きたので、取得部分だけ書きます。保存は、DynamoDBでも利用したら楽だと思います。

'use strict';
let client = require('cheerio-httpcli');
client.headers['User-Agent'] = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36';

exports.handler = (event, context, callback) => {
  client.fetch('https://www.amazon.co.jp/product-reviews/4797382570/ref=cm_cr_getr_d_show_all?pageNumber=1', { q: 'node.js' }, function (err, $, res) {
    console.log(res.headers);
    console.log($('title').text());
    let list = '';
    let reviewList = $("div[class='a-section review']");
    reviewList.each( function (idx) {
      let review = $(this);
      console.log(review.find("span[data-hook='rate']").text());
      console.log(review.find("span[data-hook='review-date']").text());
      console.log(review.find("span[data-hook='review-body']").text());
    });
    callback(null, review);
  });
};

 ほぼcheerio-httpcliの使い方だけの問題です。lambdaのアップロード手順とかは、この辺りみてください。ブラウザだけでも頑張れば何とかなるけど、基本的にはクライアント側にnode.jsをインストールして、cheerio-httpcliも取ってこないといけないので、非エンジニアにはハードル高いですね。
AWS Lambda+Node.jsのモジュールcheerio-httpcliでWebスクレピングをする

まとめ



 個人的には、Lambdaが一番ラクです。でも、Lambdaの場合は、AWSアカウント作成とかIAM関係のところとか、万人向けかというと残念ながらそうでもないです。悩ましいですね。そして冒頭で2つのURL使うとか言いながら、放置しておりました。また次回、Google Apps Script編で詳しく書きます。

データを集める技術 最速で作るスクレイピング&クローラー (Informatics&IDEA)

データを集める技術 最速で作るスクレイピング&クローラー (Informatics&IDEA)

Rubyによるクローラー開発技法 巡回・解析機能の実装と21の運用例

Rubyによるクローラー開発技法 巡回・解析機能の実装と21の運用例

Google スプレッドシートの関数でWebからデータを取得する

 Excel買うのはちょっと高いなぁと思っている時に重宝するのが、Google スプレッドシートです。ブラウザがあればどこでも使えて嬉しく、あのデータあのパソコンに入ってるのにとか、そういったことから開放されます。さらに他の人との共有も簡単なので、使い所沢山あります。
 そんなGoogle スプレッドシートですが、Googleならではというような機能もあります。その1つがImport系のセル関数です。幾つかあるのですが、Webからデータを収拾できるものが幾つかあります。地味だけど便利なので、簡単に紹介してみます。

Import関数



関数名 概要
IMPORTXML XML, HTML, CSV, TSV,RSS/Atom XMLフィードなど、構造化データからデータをインポート
IMPORTHTML HTML ページ内の表やリストからデータをインポート
IMPORTFEED RSS, Atom フィードをインポート
IMPORTDATA 指定したURLのデータを、.csv形式または .tsv形式でインポート

 表をみてもらうと解るように、取得できるデータ種別が重複する部分があります。一方で、使い方としては少しづつ異なっているので、順番に見ていきましょう。

ImportXML



 個人的には、これを使う機会が一番多いです。関数名としてはXMLですが、構造化データを扱う関数となっています。構造化データというのは、それぞれの項目に意味を与えられたデータとなります。XMLやRSS,Atomであれば、それぞれの要素名・データというペアで出てきますよね。またCSV,TSVにしても、列ごとに項目名が与えられ行はその塊という形になっています。またHTMLも名前の一部がmarkup languageとなっているように、構造化データです。HTMLを取れるということで重宝します。

ImportXMLの使い方

ImportXMLの使い方は簡単です。取得先のURLと取得する部分(XPath_query)を指定するだけです。

構文

IMPORTXML(URL, XPath_query)

使用例

IMPORTXML("https://en.wikipedia.org/wiki/Moon_landing", "//a/@href")

 上記サンプルは、WikiPediaからリンク先一覧を取得しています。

f:id:dkfj:20161002115320p:plain

 現実的にこの関数を使う時は、HTMLを取得対象とすることが多いと思います。何故ならWeb上のデータの殆どがHTML形式で提供されているからです。そこでポイントになるのが、XPathの書き方です。方法については色々ありますが、Chromeの機能を利用するのが一番ラクです。取得したい場所を選んだ上で、検証→Copy→Copy XPathで取得できます。こんな形で出てくるので、

//*[@id="cm_cr-review_list"]

ダブルコーテーションをシングルコーテーションに置き換えて利用します。

ImportHTML



 ImportHTMLは、HTMLページ内の表やリストからデータをインポートします。単純にHTMLを取得するのではなく、その中のテーブルかリストを取得するという、素直じゃないやつです。

ImportHTMLの使い方

取得先のURLと抽出するタグのタイプ(table or list)、出現順を指定します。一つ目のテーブル/リストを取得したい場合は、最後のindexは省略可能です。

構文

IMPORTHTML(URL, query, index)

使用例

IMPORTHTML("http://en.wikipedia.org/wiki/Demographics_of_India","table",4)

 取得例は、次のような形です。
f:id:dkfj:20161002120636p:plain

 関数名からは予想できないようなものが取得できるので最初は面食らいますが、意味が解ると便利です。

ImportFEED



 ImportFEEDは、RSSフィードやAtomフィードをインポートします。ImportXMLでも実現できるのですが、RSSやAtomフィードに特化している分、余計な事を考えなくても欲しいデータが取れるようになっています。

ImportFEEDの使い方

取得先のURLとオプションを指定してます。オプションの一つ目のクエリは、取得するデータの指定です。デフォルトがfeedになっていて、通常の場合変更する必要はありません。見出しは、一番上の行に見出し行をつけるかどうかで、デフォルトでは付けないようになっています。最後のアイテム数は、取得するアイテム数です。無指定の場合は、全て取得します。

構文

IMPORTFEED(URL, [クエリ], [見出し], [アイテム数])

使用例

IMPORTFEED("http://news.google.com/?output=atom")

f:id:dkfj:20161002121020p:plain

ImportDATA



 最後にImportDATAです。これは、CSVやTSVを取得します。何気にスプレッドシートで、他のCSVを扱うのは難しかったので、この機能は中々便利です。一方でCSVでデータ提供している所は、あまり無かったりします。

ImportDATAの使い方

取得先のURLを指定するだけという潔さです。

構文

IMPORTDATA(URL)

使用例

IMPORTDATA("http://www.census.gov/2010census/csv/pop_change.csv")

f:id:dkfj:20161002121842p:plain

まとめ



 プログラマという人種は、わりとすぐにプログラムを書いて解決しようとしてしまいます。一方で、既に提供されている機能で実現できるのであれば、それを使うに越したことはないです。ケースバイケースで考えてみましょう。
 ちなみに上記の関数からアクセスした場合のユーザーエージェントは、次のようになっています。サイト側でブロックされている場合があるので、ご注意を

Mozilla/5.0 (compatible; GoogleDocs; apps-spreadsheets; +http://docs.google.com)

See Also:
環境構築レスでAmazonの商品レビューを取得する


データを集める技術 最速で作るスクレイピング&クローラー (Informatics&IDEA)

データを集める技術 最速で作るスクレイピング&クローラー (Informatics&IDEA)

Rubyによるクローラー開発技法 巡回・解析機能の実装と21の運用例

Rubyによるクローラー開発技法 巡回・解析機能の実装と21の運用例

IFTTTで雑にエゴサーチして通知する

 クローラー本を出していますが、可能であればプログラミング・レスで楽にしたいと思っています。そんな時にお勧めのツールが、IFTTTです。IFTTTは、説明不要かもしれませんが、Webサービス同士を連携するアプリです。今のご時世、サービス同士を組み合わせるだけで殆どのことが出来るのです。
 ということで、IFTTTとその他のサービスを利用してエゴサーチの仕組みを作ってみましょう。エゴサーチとは、自分の名前や自社の商品など検索することの俗語です。ご多分にもれず、私も自分の本のエゴサーチに勤しんでいます。今回、エゴサーチの収拾元としては、GoogleとTwitterとします。

IFTTT側の仕組み



 まずエゴサーチの仕組みの構築です。Twitterの場合は、単純に検索結果で新規のものの抽出です。Googleのものも検索結果の新着を使うのですが、これをWebサービスでどう実現するかが課題です。お勧めなのが、Google Alertです。Google Alertは、予め決めておいたキーワードが出てきたら通知するという素晴らしいサービスです。昔からあり、コンセプトも良いのですが何故かマイナーなサービスです。
 データの収拾元が決まったことで、IFTTT側の構成を考えてみましょう。今回は通知するだけではなく、可能であれば蓄積したいと思います。そこで、Googleスプレッドシートに保存していくことにします。通知が必要であれば、IFTTTのモバイルアプリを入れてAcitonをIF Notificationsに指定すれば大丈夫です。全体像をまとめると次のような図になります。

f:id:dkfj:20160927161253p:plain

Googleアラートの設定



 Google Alertの問題点は通知方法です。デフォルトはEメールです。が、メールで送られても扱いづらいです。もう1つの通知方法としては、RSSがあります。これが意外に使えます。設定は簡単で、キーワードを入力し、オプションで頻度を"その都度"にし、配信先を"RSS"とするだけです。

f:id:dkfj:20160927161548p:plain
f:id:dkfj:20160927161751p:plain

IFTTT側の設定 Googleアラート編



 IFTTTは、Google Alertの通知とTwitter検索を別々に設定します。まず、Google Alertです。先に設定したアラートから、RSSのURLをコピーしておきます。そして、IFTTTで新規のレシピの作成をします。まずレシピのthisにあたる"Choose Trigger Channel "ですが、チャンネルとしてRSSを指定します。

f:id:dkfj:20160928081159p:plain

次にRSSで"New feed item"を選びます
f:id:dkfj:20160928081402p:plain

RSSのURLを入力します。
f:id:dkfj:20160928081418p:plain

今度はthat側である"Choose Action Channel "の設定です。Google Driveを選びます。
f:id:dkfj:20160928081436p:plain

詳細設定で、"Add row to spreadsheet"を選び新規の行を追加するようにします。
f:id:dkfj:20160928081452p:plain


 これでレシピの作成は完了です。こんな感じでデータが蓄積されていきます。

f:id:dkfj:20160929141620p:plain

IFTTT側の設定 Twitter検索編



 次は、Twitterの検索です。こちらは、Googleアラートの設定よりも簡単です。IFTTT側にTwitterのトリガーのパターンがあるので、それを利用します。初回利用時は、Twitterとのアカウント連携が必要になります。内容を確認して、許可を与えてください。

f:id:dkfj:20160929141955p:plain

 "New tweet from search"を利用し、検索条件を設定します。
f:id:dkfj:20160929142002p:plain
f:id:dkfj:20160929142008p:plain

 アクション側は、先程のGoogleアラートと同様に設定します。さっくりと簡単です。

まとめ



 上記の検索を、自分でプログラムで組もうと思うとそれなりに大変です。これが、Webサービスを組み合わせることにより、15分程度で実現できるようになっています。また拡張性も優れていて、例えばもう少し細かくコントロールしたいのであれば、受けての方をGoogle Apps Scriptで取得するといったことも考えられます。アイデア次第でいろいろ出来るので、ぜひ試してみてください。

データを集める技術

データを集める技術

Rubyによるクローラー開発技法 巡回・解析機能の実装と21の運用例

Rubyによるクローラー開発技法 巡回・解析機能の実装と21の運用例

AWS本とクローラー本のKindle版がお買い得になりました。

 予定をとっくに過ぎているのに原稿が書けません。そんな秋の夜長ですが、自分が書いた本がKindle版で割引率が拡大しています。結構お得感が出ているので紹介しておきます。
 Kindel本は、改訂版が出た時に無料でアップデートできるという特典があります。技術書の寿命はせいぜい2年くらいですが、改訂で上手く生きながらえる場合もあるので、個人的には最近技術書を買う場合はKindle版しか買っていないです。

Rubyによるクローラー開発技法



 編集者も何故売れるのか解らないと言っていたクローラー本です。発売して2年半経ちますが、まだ読まれているようで、ブログやTwitterで感想かいてくれる人が今でもチラホラいます。著者としては嬉しい限りです。取得先のサイトの構成が変わっていることも多く、そのままでは動かないサンプルも多くなっていますが、枯れたツールを使っているので取得自体は同じようにできるはずです。
 この本のKindel版の割引率は高く、定価3,218円のところが30%引き(965円)の2,253円。さらに20%ポイント還元なので、実質1,803円となっています。紙の方もこれくらいの価格だと、もう少し試してみようという人も増えるのではないかなぁと思います。

Rubyによるクローラー開発技法 巡回・解析機能の実装と21の運用例

Rubyによるクローラー開発技法 巡回・解析機能の実装と21の運用例

Amazon Web Services パターン別構築・運用ガイド



 発売して1年半が経ちましたが、今も着々と売れているAWS本です。内容的には、少し古くなっているところがあるので、多少手直ししたいところです。ただ、EC2やRDSなどの仮想インスタンス、VPCなどのネットワークを中心に扱っているので、基本的な所は変わっていません。ということで、今でも充分役にたつと思います。
 紙の本が3,672円ですが、Kindle版は20%割引(734円)の2,938円です。わりと常時20%ポイント還元セールしているので、実質2,351円で購入できます。定価が高いので、結構お買い得感がでています。

Amazon Web Services パターン別構築・運用ガイド  一番大切な知識と技術が身につく

Amazon Web Services パターン別構築・運用ガイド  一番大切な知識と技術が身につく

  • 作者: NRIネットコム株式会社,佐々木拓郎,林晋一郎,小西秀和,佐藤瞬
  • 出版社/メーカー: SBクリエイティブ
  • 発売日: 2015/03/25
  • メディア: Kindle版
  • この商品を含むブログを見る

Amazon Web Services クラウドネイティブ・アプリケーション開発技法



 ノリノリで書いて収拾がつかなくなったのが、この本です。ページ数が多くて分厚く高くなりすぎたという点と、AWS側の進化が早すぎてAPI Gateway,Lambda,Cognitoの変化に涙しています。あと、SDK周りのバージョンアップも。ただ、わりと実用的な本になっているので、この本片手に写経して貰えれば今後のシステム開発の流れというのが垣間見れるのではないかなと思います。
 この本も、同様にKindle版が割引されています。定価3,974円が、20%割引(794円)の3,180円。さらに20%ポイント還元で実質2,544円となっています。

Amazon Web Services クラウドネイティブ・アプリケーション開発技法 一番大切な知識と技術が身につく

Amazon Web Services クラウドネイティブ・アプリケーション開発技法 一番大切な知識と技術が身につく

  • 作者: 佐々木拓郎,佐藤瞬,石川修,高柳怜士,佐藤雄也,岸本勇貴
  • 出版社/メーカー: SBクリエイティブ
  • 発売日: 2016/04/20
  • メディア: Kindle版
  • この商品を含むブログを見る

感想



 お前が言うなと言われそうですが、PDFの作り方を、画像ベースではなくテキストベースに変えて欲しいです。検索できない技術書というのは、やっぱり悲しいし、困っている人が多いようです。根本のところは、技術書の流通量とコストの問題ですが、何とか打破できないですかねぇ。

家賃補助がある場合のマンション購入考

 たまに呟いていますが、マンションの内覧が好きです。正確に言うと、内覧をしながらその物件の10年後、20年後の価値を考え、購入するとどれくらいの利回りになるのかと妄想するのが好きです。そういう意味で、値付けパターンが単純な新築より、中古マンションをめぐるのが好きです。
 内覧の際に考えるのが、2つの観点です。1つは利回りで、もう一つはキャッシュ・フローです。無料の不動産情報誌とか読んでいると、簡単なローンシミュレーションなどは載っているのですが、それだけでは足りないように思えます。ということで、私の思考シミュレーションをまとめてみます。また家賃補助というサラリーマン的な観点も考慮してみます。ちなみに個人的な考え方なので、突っ込みどころは満載です。

キャッシュフローから考える


 キャッシュフローとはお金の流れです。手元に入ってくるお金と出て行くお金を差し引いたものと考えてください。住宅に関するキャッシュフローを考える上で、仮に現在の家賃が13万円として、同等+αの住宅を購入しようとしたら4,000万円だったしましょう。フルローン・ボーナス返済なし・35年返済だと、毎月112,914円返済することになります。計算の単純化の為に11万円としましょう。ただし、ここに共益費や修繕費、固定資産税などがかかってきます。共益費と修繕費は全期間を通して月3万円と仮定し、固定資産税は年10万円と仮定すると、月8万3千円今日が必要になります。合計すると19万円強となります。キャッシュフロー的には、賃貸の場合より悪化します。
 ここまで書くと、マンションは最後に部屋が残るので資産価値があるという意見が出てきます。では、資産価値を含めて、次は利回りを考えてみましょう。

利回りから考える


 マンションの購入の際に考える利回りとは何でしょうか?究極的には、Exit(売却)を前提に購入金額から売却金額と経費(税金・共益/修繕費)を差し引いたものでしょう。しかしまぁ、一般的にいうと大幅なマイナスになります。そこで、自分が住んでいる分を他人に貸していると仮定して、周辺相場の家賃を参考に、それを収入と考えてみましょう。

購入金額:4000万
売却金額:2000万
居住期間:35年間
共益/修繕費合計:1,260万(3万円/月と仮定)
固定資産税合計:350万(10万円/年と仮定)
家賃合計:5,460万(13万円/月と仮定)

計算式 2,000万 + 5,460万 - 4,000万 - 1,260万 - 350万 = 1,850万

仮定ばかりで突っ込みどころ満載ですが、35年間住んだとしたら1,850万円のプラスですね。
家賃分を考えずにいると、単純に3,610万円のマイナスです。
単純に賃貸の場合の賃料総計は5,460万なので、2000万弱くらいは有利になっていますね。
(補修費が掛からないという前提ですが)

家賃補助について考える


 上記のこと検討すると、35年という長期スパンであれば購入の方が有利になります。しかし、購入の場合でも部屋の中の修繕費費というのは必要なので実際のところはもう少しコストが掛かってきます。一方で賃貸に比べると、購入の方が住宅の満足度は上げやすいというのも事実です。
 ただし、サラリーマン的に考えると、もう一つのファクターがある場合があります。それが、家賃補助です。家賃補助とは、マイホームの人は貰えないけど賃貸の人には補助してもらえるという、謎のシステムです。何故って合理的な説明は難しいですが、家賃補助があるという所は未だに多いと思います。
 正確にいうと家賃補助のシステムについても、補助分が税金掛かったり掛からなかったりと色々あります。今回は単純化して、月5万円の補助があると仮定します。すると、どうなるのでしょうか?家賃合計が5,460万から3,360万円になります。その差、2,000万円。上記の賃貸のメリット分を吸収する形となります。これを考えると、どちらを選んでも一緒というのが元日なんですね。
※今回は35年間で、部屋の価値が半分になると前提を置いています。これが値段が落ちない場合もあるし、1,000万円でも売れない場合もあるというのが分譲マンションの怖い所なのですね。ちなみに地方では、35年経つと全く売れません。

まとめ


 上記のようなことを考えると、それほど有利な物件というのが出てこなくなります。地味に家賃補助って大きいんですよね。結果、買わなくなっちゃいます。元々同じところに35年住む気もないですし、フルローンを前提にする気もありません。10年間というスケールで考えると別の結果がでる場合もあります。ということで、さっくりどこかを買うこともあるとは思いますが、考え方の一例として紹介だけしておきます。まぁ家ってのは、その人を取り巻く状況によって何が有利ってのは千差万別なので、自分なりの考え方持つとよいですよという話です