Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
28
Help us understand the problem. What are the problem?

More than 3 years have passed since last update.

@mmm888

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

はじめに

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は、ブラウザを開いて操作がされるのでただスクレイピングしたいだけだと無駄な感じがあって、実際時間がかかる。

参考

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
28
Help us understand the problem. What are the problem?