やること
ログインが必要なサイトにログインして、ログイン後のページでcsvファイルダウンロードを自動で行う。
自分について
- スクレイピングといえば、javascriptでやる人
- casperかnode.jsのcheerio-httpcliを使うことがほとんど
使うライブラリ
Goutte
Goutteの準備
ここ参照。
composerが使えれば、composerで。
使えない場合、phpのバージョンに合わせてpharファイルをダウンロードしときます。
呼び出しは下記のとおりです。
require_once __DIR__ . "/goutte-v2.0.4.phar"; // pharを使用する場合
// require_once __DIR__ . "/vendor/autoload.php"; // composerを使用する場合
use Goutte\Client;
Goutteが使用している技術とドキュメント
SymfonyのBrowserKit, CssSelector, DomCrawler使用しています。
DomCrawler
また、Guzzleのhttpクライアントも使用しているのでこの2つのドキュメントを参照してください。
Guzzle
Goutteを使用してスクレイピングの流れ
ページの取得はインスタンス化したGuzzleHttp\Clientで対象URLを呼び出します。
まずはログインページを取得します。
$client = new Client();
$login_page = $client->request('GET', 'https://hoge.com/login/');
これで$login_pageにhtml情報が入ったDomCrawlerが入ります。
その後、DOM要素の取得ははcssセレクタかxpathが使えます。
書き慣れているので、cssセレクタ記法を採用しました。
次はログインフォームを取得します。
$login_form = $login_page->filter('form')->form();
かんたんですね。
で、ログインフォームからログインをします。
さっき取得したフォームに必要な入力情報をinput要素のname属性を設定し、
submit()を呼び出すことでログインが可能です。
$login_form['input_id_name'] = 'your_id';
$login_form['input_password_name'] = 'your_password';
$client->submit($login_form);
ログイン後サイト内のページ遷移はrequest()を使用し、
必要なページに遷移しましょう。
ダウンロードはaタグ取得をcssセレクタで、その後取得したaタグからhrefを抽出することで、
ダウンロードリンクが取得できます。
$download_hrefs = $after_login_page->filter('a')->extract('href');
上記は例になります。
そのまま使用するとページ内のaタグをすべて取得しますので、ページに合わせてcssセレクタを変更してください。
今回はcsvだったので、取得したcsvダウンロードリンクをリクエストした結果を
SplFileObjectでcsvファイルを作成しました。
$count = 0;
foreach ($download_hrefs as $href) {
$client->request('GET', $href);
$response_content = $client->getInternalResponse()->getContent();
$file = new SplFileObject('./'.$count++'.csv', 'w'); // ファイル名は適当
$file->fwrite($response_content);
// 連続アクセスしないようにする
sleep(2);
}
今回は使用しなかったのですが、requestのsinkオプションを使用することで、
ダウンロードも可能なようです。
sinkオプション
使ってみた感じ
要素がないとエラーが起きて処理が止まる。
PHP Fatal error: Uncaught exception 'InvalidArgumentException' with message 'The current node list is empty.'
セレクタが合っているかを確認した後、
Fatal Errorが心臓に悪いので、count()で要素存在チェックをしましょう。
$hoge = $page->filter('hoge');
if ($hoge->count()) {
echo($hoge->text());
} else {
echo 'kara';
}
動的ページのスクレイピングは難しそう?
今回は静的ページだったのですが、同期処理のphpで使えるんでしょうか・・・
php縛りだったので、Goutteにしましたが、
使い慣れているjavascriptと比較して特に優位性見つからなかったので、
状況によって使い分けるようにします。