LoginSignup
28
15

More than 5 years have passed since last update.

golangでagoutiとgoqueryを使ってスクレイピングする

Last updated at Posted at 2018-06-26

jsを使うサイトをスクレイピングしたいと思って調べた結果、pythonを使う記事は日本語でたくさんあったが、goを使ったものはあまり見かけなかったのでメモを作成。
※以下は2018年6月下旬時点の情報

準備

agoutiのインストール

Web Driverのインストール

  • Chrome用をインストール
$ brew install chromedriver
  • selenium-server-standaloneもインストール
$ brew install selenium-server-standalone

agoutiのインストール

$ go get github.com/sclevine/agouti

goqueryのインストール

$ go get github.com/PuerkitoBio/goquery

Document

前提

自分の場合は、ブラウザを動かして

1. ブラウザを操作して狙った情報を出す
2. その結果をクロールする
(3. 再び別の情報を出す)

の3段階をループしたかったので、以下のようなコードを書いた。

1. ブラウザを操作して狙った情報を出す

サンプルコード

  • ブラウザを起動して目的のページを開く
sample.go
url = "https://example.com" // urlを指定
driver := agouti.ChromeDriver() // ドライバの起動

err := driver.Start() 
if err != nil {
  log.Printf("Failed to start driver: %v", err)
  }
defer driver.Stop()

page, err := driver.NewPage(agouti.Browser("chrome")) // クロームを起動。page型の返り値(セッション)を返す。
if err != nil {
  log.Printf("Failed to open page: %v", err)
  }

err = page.Navigate(url) // 指定したurlにアクセスする
if err != nil {
  log.Printf("Failed to navigate: %v", err)
  }
  • 目的の場所をクリックして狙った情報を出す(例:セレクトボックスをクリックしてその中の選択肢のすべてを取る)
sample.go
curContentsDom, err := page.HTML()
  if err != nil {
    log.Printf("Failed to get html: %v", err)
    }

readerCurContents := strings.NewReader(curContentsDom)
contentsDom, _ := goquery.NewDocumentFromReader(readerCurContents) // 現状ブラウザで開いているページのDOMを取得
listDom := contentsDom.Find(" selector ").Children() // selector  部分にセレクトボックスのセレクタを入れる。セレクトボックス内の子要素を全部取得
listLen := listDom.Length() // セレクトボックスの子要素の個数を取得

for i:= 1; i <= listLen ; i++ {
  iStr := strconv.Itoa(i)
  page.Find(" selector > option:nth-child(" + iStr + ")").Click() // セレクタの属性(ここではoption)のバリューで繰り返しクリックする
  time.Sleep(2 * time.Second) //適宜ブラウザが反応するための間を取る
  }

2. その結果をクロールする

サンプルコード

  • 以下のコードは上記のfor iteration内で実施
sample.go
curContentsDom, err := page.HTML()
  if err != nil {
    log.Printf("Failed to get html: %v", err)
    }

readerCurContents := strings.NewReader(curContentsDom)
contentsDom, _ := goquery.NewDocumentFromReader(readerCurContents) // ページ内容が変化しているので再取得

contentsDom.Find(" selector ").Each(func(_ int, s *goquery.Selection) {  // 繰り返し取得したい部分までのセレクタを入れる
  data := s.Find(" selector ").Text() // テキスト要素を取得したい場合
  link, _ := s.Find(" selector ").Attr("href") // アンカーリンク要素を取得したい場合
  alt, _ := s.Find(" selector ").Attr("alt") // alt要素を取得したい場合

  time.Sleep(1*time.Second) //サーバに負荷を与えないように。
})

(3. 再び別の情報を出す)

  • 1.内のforループ内で処理。

よく使いそうなagoutiのメソッド

method.go
func (s *Page) Find(selector string) *Selection // Page型のメソッド。セレクタを入れるとそのセレクタの箇所を特定して Selection型を返す

func (s *Selection) Click() error // Selection型のメソッド。引数のSelectionのすべての要素をクリックする。返り値のerrと、for文のcontinue処理を組み合わせて使える

func (s *Selection) DoubleClick() error // Selection型のメソッド。引数のSelectionのすべての要素をダブルクリックする。

func (p *Page) Refresh() error // Page型のメソッド。ページ全体をリロードする
  • 私は使わなかったが、ブラウザの戻る、進む、マウス操作もできるので、一通りのブラウジングの再現はできそう。

終わりに

英語Documentsしか自分は見つけられなかったので、agoutiを使う人の足しになればと思ってます。

28
15
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
28
15