Help us understand the problem. What is going on with this article?

Go言語で動的HTMLをWebスクレイピングする

More than 1 year has passed since last update.

はじめに

JavaScriptで動的に生成されるWebページの場合、goqueryに直接URL渡しても正しい値でスクレイピングができない。
そのため、WebDriverを使ってブラウザに表示された実際のHTMLをgoqueryに渡してスクレイピングする必要がある。

環境

  • Ubuntu 16.04.3
  • go 1.8.3

インストール

  • ChromeDriver
# インストール
export WD_VER=2.32
wget -O /tmp/chromedriver.zip http://chromedriver.storage.googleapis.com/${WD_VER}/chromedriver_linux64.zip
sudo unzip /tmp/chromedriver.zip chromedriver -d /usr/local/bin/
sudo chmod +x /usr/local/bin/chromedriver

# 確認
$ which chromedriver 
/usr/local/bin/chromedriver
  • Go パッケージ
go get github.com/PuerkitoBio/goquery
go get github.com/sclevine/agouti

流れ

ブラウザ経由でHTMLを取得

WebDriverを使用してHTMLを取得する。

url := "http://target.example.com"

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"))
if err != nil {
    log.Printf("Failed to open page: %v", err)
}

err = page.Navigate(url)
if err != nil {
    log.Printf("Failed to navigate: %v", err)
}

// contentにHTMLが入る
content, err := page.HTML()
if err != nil {
    log.Printf("Failed to get html: %v", err)
}

スクレイピング

goqueryを使用してスクレイピングする。
bodyタグのaタグからhrefとコンテンツを取り出している。

  • Find()の指定方法
    • body, .container, body[class="container"]
reader := strings.NewReader(content)
doc, _ := goquery.NewDocumentFromReader(reader)
doc.Find("body a").Each(func(i int, s *goquery.Selection) {
    // bodyにコンテンツ, hrefにhrefの値が入る
    body := s.Text()
    href, _ := s.Attr("href")
    fmt.Printf("body: %s, href: %s\n", body, href)
})

実践

ブラウザで表示し、クリックしてからHTMLを取得する

クリックすると表示内容が変化する際に変化後のコンテンツをスクレイピングしたい時、ブラウザでクリック操作をした後にHTMLを取得する。

package main

import (
    "fmt"
    "log"
    "strings"

    "github.com/PuerkitoBio/goquery"
    "github.com/sclevine/agouti"
)

func main() {
    url := "http://target.example.com"

    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"))
    if err != nil {
        log.Printf("Failed to open page: %v", err)
    }

    err = page.Navigate(url)
    if err != nil {
        log.Printf("Failed to navigate: %v", err)
    }

    page.FindByButton("Next").Click()

    content, err := page.HTML()
    if err != nil {
        log.Printf("Failed to get html: %v", err)
    }

    reader := strings.NewReader(content)
    doc, _ := goquery.NewDocumentFromReader(reader)
    doc.Find("body a").Each(func(i int, s *goquery.Selection) {
        body := s.Text()
        href, _ := s.Attr("href")
        fmt.Printf("body: %s, href: %s\n", body, href)
    })
}

まとめ

動的HTMLを取得し、スクレイピングを行うことができた。
ただ、WebDriverは、ブラウザを開いて操作がされるのでただスクレイピングしたいだけだと無駄な感じがあって、実際時間がかかる。

参考

mmm888
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした