PHP と Goutte ではじめる超絶簡単クローラー入門

  • 126
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

※ 追記
ぞくへんかきました
PHP と Goutte ではじめる超絶簡単クローラー入門 ログイン編

Goutte とは

  • PHP で書かれてるスクレイピングライブラリ
  • CSS セレクタでかける
  • jQuery になじみのあるみんなには簡単すぎる

導入

  • composer つかおう(提案)
    • composer インストールしてないひとはいますぐググろう(きっと Qiita にも記事あるよ!)
mkdir crawler && cd crawler
composer require fabpot/goutte
touch app.php

使い方

リクエストなげる

// app.php
<?php

require_once __DIR__ . '/vendor/autoload.php';

$cli = new Goutte\Client();
$url = 'http://www.doctrine-project.org/api/dbal/2.4/class-Doctrine.DBAL.Schema.AbstractSchemaManager.html';
$crawler = $cli->request('GET', $url);

td.name に __construct とかいるのでこのへんを find する

  • こういうのは html みて規則を感じ取ろう
    • 習うより慣れろ 案件
<?php

// 前略
$crawler->filter('.name')->each(function($name) { // jQuery 脳で find しそうになる気持ちをぐっとこらえよう!
  echo $name->text(); // これだけで .name の中身が echo されるよ!かんたん!
});

余計なものたくさんあるからもっと絞り込んだほうがよさげ

  • こんな物量のスクレイピングにパフォーマンスとか気にする必要ないでしょ
<?php

// 前略
$crawler->filter('.name code a')->each(function($name) { 
  echo $name->text() . "\n";
});
__construct
Doctrine\DBAL\Connection
getDatabasePlatform
tryMethod
listDatabases
listSequences
Doctrine\DBAL\Schema\Sequence
listTableColumns
// 以下省略

なんてこった!それっぽくとれたとおもったら邪魔なやつがいるぜ!

  • 引数の型指定にはられてるリンクまでひろってしまった!
  • まぁいろんな方法があるとは思うのですが、今回のケースであればたとえば __construct なら
    • メソッド名の href: source-class-Doctrine.DBAL.Schema.AbstractSchemaManager.html#57-66
    • 引数型指定の href: class-Doctrine.DBAL.Connection.html
  • めんどくさいので href で判定してしまおう!
    • source-class からはじまってたらメソッド名ぽいのでこれで判定できるよね

ヤる

  • $name->attr(attrName) で attribute しゅとくできるよ
  • つまりこういうこと
<?php

// 前略
$href = $name->attr('href');
if (preg_match('/^source/' , $href)) { // source からはじまるものだけにしぼりこむ
  echo $name->text();
}

  • よいのでは
__construct
getDatabasePlatform
tryMethod
listDatabases
listSequences
listTableColumns
listTableIndexes
tablesExist
listTableNames
filterAssetNames
getFilterSchemaAssetsExpression
listTables
listTableDetails
listViews
listTableForeignKeys
dropDatabase
/// 以下略

最終的なコード

<?php

require_once __DIR__ . '/vendor/autoload.php';

$cli = new Goutte\Client();
$url = 'http://www.doctrine-project.org/api/dbal/2.4/class-Doctrine.DBAL.Schema.AbstractSchemaManager.html';
$crawler = $cli->request('GET', $url);

$crawler->filter('.name code a')->each(function($name) {
    $href = $name->attr('href');
    if (preg_match('/^source/' , $href)) {
        echo $name->text() . "\n";
    }
});

まとめ

  • クローラこんなに簡単につくれるけど悪いことにつかっちゃだめだよ!
  • dom 構造の規則が見えるようになるとさくさくいける
    • 習うより慣れろ(2回目)

番外編: よくある質問

  • Q: filter したときに例外かえってきて生きるのが辛いです
  • A: 例外吐くのは空の場合なので if ($hoge->count() === 0) でブロックしてから each するとよいでしょう
<?php

// 略
$crawler->filter('.name')->each(function($name) {
    $anchors = $name->filter('a');
    if ($anchors->count() === 0) {
        return;
    }
    $anchors->each(function($anchor) {
        echo $anchor->text() . "\n";
    });
});