初心者がSlack+Hubot(+Heroku)でPHPマニュアルをスクレイピングする(前編)

ツイッターボットを諦め伺かでランダムトークさせていた自分が簡単と評判なSlack+Hubotに挑みました。

[後編](http://qiita.com/khsk/items/23491309f93796bededc)

* 前編ではスクレイピングしません。
* 初心者とありますが、Slack、Hubot、Heroku、スクレイピング、デプロイ？、Git、あたりが初体験です。
* Node.js、CoffeeScriptも未経験。javascriptとjQueryがPHPと一緒に少しだけ。
* PHPタグをつけていますがスクレイピング対象がPHPマニュアルなだけでPHPは書きません。
* 実際に作成しながら並行で記事を書いているのでとても冗長です。

## Slack Hubot Heroku 連携(割愛)
SlackとHubotの連携は溢れるほどあるので割愛します。
基本はどっかの記事通りにすれば大丈夫です。自分はつまみ食いで作りました。
注意する点としては

* Hubotにyeomanを使う
* Slack連携が簡略化され、Herokuに登録するのはHUBOT_SLACK_TOKENだけでOK
* Heroku+Hubotにredisは必須ではない→クレジットカードの登録不要

ぐらいです。(とっても有用ですが)古い記事も多いのでちゅうい。
Windows環境でしたがWindows用の記事もありました。\*感謝\*
redisはデータの永続化に使うらしいですが、動かすだけなら無くても大丈夫そうです。

##PHPマニュアルを検索した結果のURLを表示する

Hubotの連携に成功するも何を作ればいいかわからなかったので、一番利用しているPHPのマニュアル検索をSlackからしてみます。

スクレイピングはまったくわかりませんが、SlackにはURLからプレビューを表示する機能があるみたいです。
目的のドキュメントのURLを返すことができればOKでしょう！

###検索方法を取得する
といっても普段の検索を開発ツールで覗くだけです
arrayで検索
![検索.JPG](https://qiita-image-store.s3.amazonaws.com/0/62354/1d67923e-136b-646d-bdbd-f0731c98bc5c.jpeg)

恐らく
http://php.net/manual-lookup.php?pattern=array&scope=quickref
から
http://php.net/manual/ja/book.array.php
が得られます！
`pattern=` に検索文字列を入力するといいんでしょう。
表示言語の判定はよくわからなかったのですが、直近の言語が反映されるようです。cookieとかでしょうか。
検索エンジンからの検索でうっかり英語のページを踏むことも多いので、できれば日本語がいいです。
ということで`&lang=ja`を勝手に追加。根拠は"それっぽい"。だけど英語のページを開いた直後でも日本語のページに飛ばされました。
http://php.net/manual-lookup.php?pattern=array&scope=quickref&lang=ja

##Hubotにスクリプトを追加する
CoffeeScriptがわからなくてもコピペで作れます。

###検索キーワードの取得
```coffeescript:検索キーワードの取得
module.exports = (robot) ->
	robot.hear /php man (.+)$/, (msg) ->
		msg.send msg.match[1]
```
```bash:検索キーワードの取得
Hubot> php man array
array
Hubot>
```
正規表現はよくわかりませんが、取れました。ちょっと(|)とかを増やしたら失敗したので素直なコマンドに。

###検索
続いてこのキーワードを先ほどのURLの`pattern`に入れてGETします。
Node.jsには`request`という便利なパッケージがあるらしいですが、
ここまでで既に頭がフットーしそうだよおっっなのでHubotで使えるらしい機能でGETします。

最初はbodyが空で焦りましたが、console.logで目的のURLを発見。

```coffeescript:検索のGET
module.exports = (robot) ->
	robot.hear /php man (.+)$/, (msg) ->
		baseUrl = "http://php.net/manual-lookup.php?lang=ja&scope=quickref&pattern="
		baseUrl += msg.match[1]
		robot.http(baseUrl).get() (err, res, body) ->
			msg.send res.headers.location
```

```bash:検索のGET
Hubot> php man array
Hubot> http://php.net/manual/ja/book.array.php
Hubot>
```
やったか！？

```bash:検索失敗
Hubot> php man arry
Hubot> undefined
```
いやまだだ！

未定義の場合の動作はわかりませんが、ifで分岐しておきます。
ちょろっと調べると値の有無が`?`で判定できる。便利。

```coffeescript:未定義はNot_Found
module.exports = (robot) ->
	robot.hear /php man (.+)$/, (msg) ->
		baseUrl = "http://php.net/manual-lookup.php?lang=ja&scope=quickref&pattern="
		baseUrl += msg.match[1]
		robot.http(baseUrl).get() (err, res, body) ->
			if res.headers.location?
				msg.send res.headers.location
			else
				msg.send "のっとふぁうんど"
```

早くSlackで見たいのでデプロイしちゃいます。


##Slackで動作確認

まずはCLIで確認しなかったarryから
![notfound.JPG](https://qiita-image-store.s3.amazonaws.com/0/62354/068d5b87-02d8-5cc5-cf24-4e31936d74aa.jpeg)


続いて正しい検索

![found....JPG](https://qiita-image-store.s3.amazonaws.com/0/62354/8da5fa69-10db-067e-320f-9094bcdcfb2e.jpeg)

…プレビューでない…

## 追記：車輪の再発明報告

あるとは思っていましたが、調べていなかったスクリプト集から目的のスクリプトを発見しました。

[Hubot Script Catalog](http://hubot-script-catalog.herokuapp.com/)
から[PHPで調べればすぐ出ます。](https://github.com/github/hubot-scripts/blob/master/src/scripts/phpdoc.coffee)

しかもこのスクリプト、Hubot標準搭載。
URLのenをjaに変更すればすぐに使えそうです。
やりたかったことも簡潔に集約されてますね。

動作は確認していませんが、

* 関数にしか対応していない
* 関数名の完全一致にしか対応していない

ように見えます。
(前編に書くのもなんですが)自作したものの利点は上記の反対になります。
逆に検索を行っていないので動作としてはphpdocの方がかなり早いと思います。

今回の練習はphpdocの拡張と捉えて自尊心を保ちましょう…