Goutte使ってスクレイピングしたのでまとめてみる

これは岩手県立大学 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情報は取ってこれます．

```php:getHtml.php
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（記事上右横の要約みたいなやつ）の情報だけ欲しいときは以下のようになります．

```php:getInfobox.php
//岩手県立大学の例
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に値があるか確認しないとエラー吐くのでそこは注意してください．
##フォームに値入れてサブミットした結果を取得
ただ指定したページの情報を取得するだけではなく，そのフォームに値を入れてサブミットした場合，
どんなものが表示されるのかも取得することができます（冒頭出たテストの話ではこの部分を使うっぽい）．
これも簡単で，取得するには以下のようになります．

```php:getResult.php
//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タグを見つければもう勝ちですね．
具体的に言えば，

1. selectButton()で送信ボタンのnameに当たる値(上では'fulltext')を利用
1. 入力されるフィールドのname('search')と，入力したい値('岩手県立大学')の組合せの配列を作る
1. submit()で1,2を利用

これで取ってこれます．

##リンク踏んだ結果を取得
さっきの検索結果では，候補が数件表示され，候補名がリンクになってます．
候補の中から岩手県立大学を選択するとして，その結果が欲しいときは
以下をさっきのsubmit()後に追加すれば良きです．

```
$link = $crawler->selectLink('岩手県立大学')->link();
$crawler = $client->click($link);
```
#まとめ
以上のものを使えば，必要最低限のことはできる気がします．
今回は特に紹介しませんでしたが，imgタグのsrcもとれたりするので，気になったら調べてみるのも良いかもしれません．
ただ，上手く取得できないページもあるので，各々対策を考えねばなりません．スクレイピング面倒です．
ちなみにWikipediaの記事を大量にスクレイピングすると[しょっぴかれる](https://ja.wikipedia.org/wiki/Wikipedia:%E3%83%87%E3%83%BC%E3%82%BF%E3%83%99%E3%83%BC%E3%82%B9%E3%83%80%E3%82%A6%E3%83%B3%E3%83%AD%E3%83%BC%E3%83%89)ので気をつけてください．DBPedia使いましょう．

#さいごに
アドベントカレンダーの最終日にしては軽い内容だったかもしれませんし，
誤字脱字説明不足様々あるかもですが，ちょっと疲れたのでここまでにします．
みなさん今年もお疲れ様でした〜

#参考サイトさま
- [GoutteとPHPUnitでレガシーなPHPアプリケーションをテストする](http://www.karakaram.com/php-functional-test-using-goutte)
- [Goutte, a simple PHP Web Scraper](http://goutte.readthedocs.io/en/latest/)
- [Goutte スクレイピング解析時のスニペットメモ](http://reafo.net/?p=896)
- [PHP7でWebページをスクレイピング(Goutte)](http://tech-blog.shucream.net/entry/2016/03/05/180420)