84
69

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Goとgoqueryでスクレイピング

Last updated at Posted at 2017-11-20

一億番煎じ:tea:記事でございます:pensive:
最近一億番煎じというフレーズがマイブームになりつつある:raised_hands:
自分の整理のための記事ですが、コメントとかいいねしてくれたら泣いて喜びます:joy:

公式
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)を使います。

NewDocumentを使う
doc, err := goquery.NewDocument("対象のURL")
if err != nil {
    panic(err)
}

これで対象のURLからGetでドキュメントを取得してくれます。

Postなどリスエストをカスタマイズして取得

ページによってはPostパラメータを付けなければならないとか、リクエストヘッダーを弄りたいということがあります。
その場合は、まずnet/httpnet/urlを使ってレスポンスを取得し、それをfunc NewDocumentFromResponse(res *http.Response) (*Document, error)に渡してやります。

NewDocumentFromResponseを使う
// パラメータを作る
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)でドキュメントを取得することもできます。

Readerを使う
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はドキュメントに対してもセレクションに対しても使えます。
セレクタについては↓らへんを見たらいいんじゃないでしょうか(雑)
セレクタの種類

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がたくさんありますが、どれか一つ覚えておけば言語が変わっても使えるという安心感があります:blossom:
Goは始めたばかりですが、goqueryに関してはあまり詰まること無く使えました:confetti_ball:
この記事では扱ってないですが、ノードやクラスを追加したりもできるみたいだし、あるHTMLを元に別のHTMLを生成するみたいなこともできそうですね:eyes:

84
69
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
84
69

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?