LoginSignup
18

More than 5 years have passed since last update.

Goutteを使ってログインしてスクレイピングする

Posted at

やること

ログインが必要なサイトにログインして、ログイン後のページで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と比較して特に優位性見つからなかったので、
状況によって使い分けるようにします。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18