Goのスクレイピングライブラリ goquery と colly を試してみる
概要
Goのスクレイピングライブラリでスター数が多い、goquery
とcolly
を触ってみようと思います。
スクレイピングするのは、https://zenn.dev/ さんです。またこちらの記事ではCSVなど出力までは行っておりませんので悪しからず。
少しライブラリ調べてみた
goのスクレイピングライブラリを使用するにあたり、どんなものがあるのか調べてみました。
※ 2022/04/29時点での情報
注意点
スクレイピングするにあたり、【2020年度版】個人用クローラーの開発手順とその注意点 -Qiitaを参考にさせていただき、robots.txtを確認しました。
zenn.devさんのrobot.txtはこちらでした。
自分も拝見し、今回Disallow
に載っていなさそうな部分をスクレイピングさせていただきました。
User-agent: *
Disallow: /dashboard/
Disallow: /settings/
Disallow: /search?q=
Disallow: /report
Disallow: /onboarding
User-agent: Yahoo Pipes 1.0
Disallow: /
User-agent: 008
Disallow: /
User-agent: voltron
Disallow: /
User-agent: Bytespider
Disallow: /
User-agent: Livelapbot
Disallow: /
User-agent: Megalodon
Disallow: /
User-agent: ia_archiver
Disallow: /
Sitemap: https://zenn.dev/sitemap/sitemap.xml
使用例
※ Playground内では動かないので注意
goquery
goqueryは、Go標準のnet/htmlパッケージとCSSセレクタライブラリのcascadiaがベースになっており、jQueryっぽく書くことができます。
- 簡単な例: https://example.com/ からタイトルを取得 Playground
package main
import (
"fmt"
"log"
"net/http"
"github.com/PuerkitoBio/goquery"
)
func main() {
webPage := ("https://example.com/")
resp, err := http.Get(webPage)
if err != nil {
log.Printf("failed to get html: %s", err)
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
log.Fatalf("failed to fetch data: %d %s", resp.StatusCode, resp.Status)
}
doc, err := goquery.NewDocumentFromReader(resp.Body)
if err != nil {
log.Printf("failed to load html: %s", err)
}
// ここでタイトルを取得
title := doc.Find("title").Text()
fmt.Println(title)
}
//Output:
//Example Domain
- zenn.dev の Explore からBooks一覧を取得する Playground
package main
import (
"fmt"
"log"
"net/http"
"github.com/PuerkitoBio/goquery"
)
func ExampleScrape() {
// 読み込むページ
res, err := http.Get("https://zenn.dev/books/explore")
if err != nil {
log.Fatal(err)
}
defer res.Body.Close()
if res.StatusCode != 200 {
log.Fatalf("status code error: %d %s", res.StatusCode, res.Status)
}
// Bodyを読み込む
doc, err := goquery.NewDocumentFromReader(res.Body)
if err != nil {
log.Fatal(err)
}
// articleタグの中から著者とタイトルのclassを取得する
doc.Find("article").Each(func(i int, s *goquery.Selection) {
author := s.Find(".BookLargeLink_userName__jNbk5").Text()
book := s.Find(".BookLargeLink_title__RqL6r").Text()
if "" == author {
author = s.Find(".BookLink_userName__avtjq").Text()
}
if "" == book {
book = s.Find(".BookLink_title__b8hGg").Text()
}
fmt.Printf("%d 著者: %v / タイトル: %v\n", i, author, book)
})
}
func main() {
ExampleScrape()
}
//Output:
//0 著者: ふーが / タイトル: RailsチュートリアルのテストをRSpecで書き換える
//1 著者: yamatatsu / タイトル: AWS CDK ドキュメント(和訳メモ)
//⋮
参考にしたサイト: https://zetcode.com/golang/goquery/
colly
collyは、goquery をベースにしたライブラリのようです。
また、公式からDocumentationが公開されています。
- 簡単な例: https://example.com/ からタイトルを取得 Playground
package main
import (
"fmt"
"github.com/gocolly/colly"
)
func main() {
c := colly.NewCollector()
//ここでタイトルを取得
c.OnHTML("title", func(e *colly.HTMLElement) {
fmt.Println(e.Text)
})
c.Visit("https://example.com/")
}
- zenn.dev の Explore からBooks一覧を取得する Playground
package main
import (
"fmt"
"github.com/gocolly/colly"
)
func main() {
c := colly.NewCollector()
i := 0
c.OnHTML("article", func(e *colly.HTMLElement) {
i++
book := e.DOM.Find("a > h3").Text()
author := e.DOM.Find("div > a").Text()
if author == "" {
author = e.ChildText(".BookLink_userName__avtjq")
}
fmt.Printf("%d 著者: %s / タイトル: %s\n", i, author, book)
})
c.Visit("https://zenn.dev/books/explore")
}
参考にしたサイト: https://blog.webmatrices.com/web-scraping-with-golang-go-and-colly
感想
goqueryもcollyも日本語で書かれている記事が少なかったので、記事にしてみました。
collyの方はgoqueryを拡張した感じなので、出来ることが多そうな印象でした。
今後は、他言語でもスクレイピングを試してみたいので、Pythonあたりを調べてみようかなと考えております。
Discussion