これは岩手県立大学 Advent Calendar 2016の25日目の記事です。
#はじめに
岩手県立大学 修士1年のfkskです.
諸用でWebスクレイピングしてて,ちょうどいいので備忘録がてらまとめたものを投稿します.
Goutteとかいういい感じ(そう)なライブラリがあったので,これを使わせていただこうかなと思います.
##そもそもGoutteとは
端的にいうと,Goutte(グット)は,PHP製のWebスクレイピングのライブラリで,スクレイピング目的だけではなく,ブラウザを操作することでテストにも使われるみたいです.
また,主要機能もSymfonyのコンポーネントで構成されており,生みの親はSymfonyプロジェクトリーダーのFabien Potencier氏です.
##動作環境
いらないかもですが一応.
- PHP 7.1.0
- Goutte 3.2
- CentOS7
###Goutteの導入
composerでちょろっとインストールするのが吉です.
$php composer.phar require fabpot/goutte
#使ってみる
##html情報の取得
手始めにWikipediaのページをスクレイピングしてみましょう.
以下のようにすればそのページのhtml情報は取ってこれます.
require 'vendor/autoload.php';
use Goutte\Client;
$client = new Client();
$url = 'https://ja.wikipedia.org/';
$crawler = $client->request('GET',$url);
$html = $crawler->html();
print_r($html);
request()でHTTPリクエストして,html()でHTMLを取得すると行った感じですね.
簡単です.
ちなみにここでtext()を使うと,htmlタグが抜けたテキストがとれます.
##取得する箇所の絞込み
といっても,返ってくるのはそのページの全html情報なので,
いらない情報を削ぎ落とすというか,抽出する箇所を指定したいものですよね.
その作業も簡単で,Wikipediaのinfobox(記事上右横の要約みたいなやつ)の情報だけ欲しいときは以下のようになります.
//岩手県立大学の例
require 'vendor/autoload.php';
use Goutte\Client;
$client = new Client();
$url = 'https://ja.wikipedia.org/wiki/岩手県立大学';
$crawler = $client->request('GET',$url);
$crawler->filter('table.infobox tr')->each(function($element){
if(count($element->filter('th')) && count($element->filter('td'))){
$th = $element->filter('th')->text();
$td = $element->filter('td')->text();
echo $th.":".$td."\n";
}
});
今回欲しい情報は,html()で見てみると,table(class="infobox")の中の,
そのまた各trの中のth,tdのテキストとなります.
ここから抽出するには,filter()にtable.infobox tr
を入れてあげればOKです.
このようにCSSのノリでいけます(idだったらtable#infobox tr
みたいな).
あとはeach()とクロージャで,またfilter()なり使って各tr要素から情報をもぎとっていきましょう.
ただ,クロージャの中でfilterする前に,th,tdに値があるか確認しないとエラー吐くのでそこは注意してください.
##フォームに値入れてサブミットした結果を取得
ただ指定したページの情報を取得するだけではなく,そのフォームに値を入れてサブミットした場合,
どんなものが表示されるのかも取得することができます(冒頭出たテストの話ではこの部分を使うっぽい).
これも簡単で,取得するには以下のようになります.
//topページから岩手県立大学の検索結果を取得
require 'vendor/autoload.php';
use Goutte\Client;
$client = new Client();
$url = 'https://ja.wikipedia.org/';
$crawler = $client->request('GET',$url);
$form = $crawler->selectButton('fulltext')->form();
$searchParameters = ['search' => '岩手県立大学'];
$crawler = $client->submit($form, $searchParameters);
$html = $crawler->html();
print_r($html);
これに至っては,入力されるフィールドと,送信ボタンのinputタグを見つければもう勝ちですね.
具体的に言えば,
- selectButton()で送信ボタンのnameに当たる値(上では'fulltext')を利用
- 入力されるフィールドのname('search')と,入力したい値('岩手県立大学')の組合せの配列を作る
- submit()で1,2を利用
これで取ってこれます.
##リンク踏んだ結果を取得
さっきの検索結果では,候補が数件表示され,候補名がリンクになってます.
候補の中から岩手県立大学を選択するとして,その結果が欲しいときは
以下をさっきのsubmit()後に追加すれば良きです.
$link = $crawler->selectLink('岩手県立大学')->link();
$crawler = $client->click($link);
#まとめ
以上のものを使えば,必要最低限のことはできる気がします.
今回は特に紹介しませんでしたが,imgタグのsrcもとれたりするので,気になったら調べてみるのも良いかもしれません.
ただ,上手く取得できないページもあるので,各々対策を考えねばなりません.スクレイピング面倒です.
ちなみにWikipediaの記事を大量にスクレイピングするとしょっぴかれるので気をつけてください.DBPedia使いましょう.
#さいごに
アドベントカレンダーの最終日にしては軽い内容だったかもしれませんし,
誤字脱字説明不足様々あるかもですが,ちょっと疲れたのでここまでにします.
みなさん今年もお疲れ様でした〜
#参考サイトさま