一億番煎じ記事でございます
最近一億番煎じというフレーズがマイブームになりつつある
自分の整理のための記事ですが、コメントとかいいねしてくれたら泣いて喜びます
公式
https://github.com/PuerkitoBio/goquery
GoDoc
https://godoc.org/github.com/PuerkitoBio/goquery
概要とかインストールとか
公式Githubに書いてあるとおりですが、jQuery的にスクレイピングやクローリングができるライブラリです。
インストールはgetで。glideを使いたければそれでも。
$ go get github.com/PuerkitoBio/goquery
ドキュメントを取得
なにはともかくドキュメントを取得しましょう。
Getで取得
ごく普通のページはfunc NewDocument(url string) (*Document, error)
を使います。
doc, err := goquery.NewDocument("対象のURL")
if err != nil {
panic(err)
}
これで対象のURLからGetでドキュメントを取得してくれます。
Postなどリスエストをカスタマイズして取得
ページによってはPostパラメータを付けなければならないとか、リクエストヘッダーを弄りたいということがあります。
その場合は、まずnet/http
とnet/url
を使ってレスポンスを取得し、それをfunc NewDocumentFromResponse(res *http.Response) (*Document, error)
に渡してやります。
// パラメータを作る
values := url.Values{}
values.Add("key", "value")
...
// リクエストを作る
// 例えばPOSTでパラメータつけてUser-Agentを指定する
req, err := http.NewRequest("POST", "対象のURL", strings.NewReader(values.Encode()))
if err != nil {
panic(err)
}
req.Header.Add("User-Agent", "Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1")
// リスエスト投げてレスポンスを得る
client := &http.Client{}
resp, err := client.Do(req)
// レスポンスをNewDocumentFromResponseに渡してドキュメントを得る
doc, err := goquery.NewDocumentFromResponse(resp)
if err != nil {
panic(err)
}
ここらへんgoqueryはサポートしてないんだなーと思ったりもしましたが、下手にサポートして制限があるよりかは一切手を出さないから好きにやってね、の方がいいような気もします。
Readerから取得
あんまり頻繁にページアクセスするのは申し訳ないと思うときは、一旦HTMLをローカルにダウンロードし、ローカルのHTMLからfunc NewDocumentFromReader(r io.Reader) (*Document, error)
でドキュメントを取得することもできます。
fileInfos, _ := ioutil.ReadFile("HTMLのファイルパス")
stringReader := strings.NewReader(string(fileInfos))
doc, err := goquery.NewDocumentFromReader(stringReader)
if err != nil {
panic(err)
}
セレクションを取得
ドキュメントが取得できたら、そこからほしいデータがあるタグをなり塊なりをfunc (s *Selection) Find(selector string) *Selection
で取得しましょう。
Find
はドキュメントに対してもセレクションに対しても使えます。
セレクタについては↓らへんを見たらいいんじゃないでしょうか(雑)
セレクタの種類
// ドキュメントから
selection := doc.Find("div#some_id > div.some_class")
// セレクションから更にセレクションを取得
innerSeceltion := selection.Find("a")
// セレクションが複数ある場合はEachで回せます
innerSeceltion.Each(func(index int, s *goquery.Selection) {
// なんかする
})
セレクションをたどる
以下などがあります。一通りできますね!(雑)
func (s *Selection) Children() *Selection
func (s *Selection) First() *Selection
func (s *Selection) Last() *Selection
func (s *Selection) Next() *Selection
func (s *Selection) Parent() *Selection
func (s *Selection) Prev() *Selection
func (s *Selection) Siblings() *Selection
データを抜く
目的のセレクションに到達したら、ほしいデータを抜き取りましょう。
以下が使えそうな関数です。
func (s *Selection) Attr(attrName string) (val string, exists bool)
func (s *Selection) AttrOr(attrName, defaultValue string) string
func (s *Selection) Html() (ret string, e error)
func (s *Selection) Text() string
// セレクションより下のタグ入りの文字列を取得
html, err := selection.Html()
// セレクションより下の全てのテキストを取得
text := selection.Text()
// 属性を取得、existsはその属性が存在するか
attr, exists := selection.Attr("href")
// 属性が存在しない場合はdefaultValueを返す
attrWithDefault := selection.AttrOr("src", "default")
おわりに
~queryがたくさんありますが、どれか一つ覚えておけば言語が変わっても使えるという安心感があります
Goは始めたばかりですが、goqueryに関してはあまり詰まること無く使えました
この記事では扱ってないですが、ノードやクラスを追加したりもできるみたいだし、あるHTMLを元に別のHTMLを生成するみたいなこともできそうですね