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

※ 追記
ぞくへんかきました
[PHP と Goutte ではじめる超絶簡単クローラー入門 ログイン編](http://qiita.com/mojibakeo/items/be68498764909a66f126)

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


# 導入

- composer つかおう(提案)
	- composer インストールしてないひとはいますぐググろう(きっと Qiita にも記事あるよ！)

```sh
mkdir crawler && cd crawler
composer require fabpot/goutte
touch app.php

```

# 使い方
- さきほどこっそり touch した app.php にクローラをかいていこう
- 今回は[Class Doctrine\DBAL\Schema\AbstractSchemaManager | Database Abstraction Layer](http://www.doctrine-project.org/api/dbal/2.4/class-Doctrine.DBAL.Schema.AbstractSchemaManager.html)からメソッドの一覧を ~~ぶっこぬいて~~ 拾い上げてみます

# リクエストなげる
```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
<?php

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

# 余計なものたくさんあるからもっと絞り込んだほうがよさげ
- こんな物量のスクレイピングにパフォーマンスとか気にする必要ないでしょ


```php
<?php

// 前略
$crawler->filter('.name code a')->each(function($name) { 
  echo $name->text() . "\n";
});
```

```dump
__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
<?php

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

```
- よいのでは

```dump
__construct
getDatabasePlatform
tryMethod
listDatabases
listSequences
listTableColumns
listTableIndexes
tablesExist
listTableNames
filterAssetNames
getFilterSchemaAssetsExpression
listTables
listTableDetails
listViews
listTableForeignKeys
dropDatabase
/// 以下略
```

# 最終的なコード
```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);

$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
<?php

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

```