メインコンテンツへスキップ
【Golang】Collyを使用してWebスクレイピングを行う

【Golang】Collyを使用してWebスクレイピングを行う

··5 分
Programming Golang
かずさプログラマー
著者
かずさプログラマー
業務の作業自動化を行っています。Go、VBA、Pythonを主に使用しています。過去にはC#、VB.Net、JavaScriptも使用していました。
目次

CollyはGo言語でWebスクレイピングを行うためのライブラリです。

gocolly/colly

Elegant Scraper and Crawler Framework for Golang

Go
23426
1771

以下にCollyの使い方を紹介します。

インストール
#

go modコマンドでgo.modファイルを作成し、go getでcollyを導入します。

go mod init colly-scraping-test
go get github.com/gocolly/colly/v2

collyの基本的な使用方法
#

Collyを使用してスクレイピングを行うには以下のような流れで処理を行います。

例として、このブログのトップページのプロフィール部分のプロフィール画像URLとプロフィール名を取得してみます。

package main

import (
	"fmt"

	"github.com/gocolly/colly/v2"
)

func main() {
	c := colly.NewCollector()

	var profileImageURL string
	c.OnHTML("#main-content img", func(e *colly.HTMLElement) {
		profileImageURL = e.Attr("src")
	})

	var profileName string
	c.OnHTML("#main-content h1", func(e *colly.HTMLElement) {
		profileName = e.Text
	})

	err := c.Visit("https://kazusa-pg.com/")
	if err != nil {
		panic(err)
	}

	fmt.Println(profileImageURL)
	fmt.Println(profileName)
}

このコードは実行するとプロフィール画像のsrcとプロフィール名が表示されます。

/img/profile-picture_hu2961160223197158946.png

                        かずさプログラマー

collectorのOnHTMLメソッドにはセレクター要素ごとに動作を定義できるので今回のコードでは以下の2つの動作を設定しています。

  • #main-content img のセレクター要素でsrc属性をprofileImageURL変数に格納する
  • #main-content h1 のセレクター要素のテキストをprofileName変数に格納する

リンク先のページの情報を取得する
#

Collyを使用すると指定したページに表示されている各リンクをたどって、リンク先のページの情報を取得することができます。
このブログのトップページに表示されている最新の記事10件にアクセスして、各記事のタイトルと何分で読了できるかの情報を取得してみます。

package main

import (
	"fmt"

	"github.com/gocolly/colly/v2"
)

// 参考URL:https://github.com/gocolly/colly/blob/master/_examples/coursera_courses/coursera_courses.go

type pageDetail struct {
	title    string
	readTime string
}

func main() {
	pageDetails := []pageDetail{}

	c := colly.NewCollector(
		colly.AllowedDomains("kazusa-pg.com"),
	)

	detailCollector := c.Clone()

	c.OnHTML("section.w-full > a", func(e *colly.HTMLElement) {
		absoluteURL := e.Request.AbsoluteURL(e.Attr("href"))
		detailCollector.Visit(absoluteURL)
	})

	detailCollector.OnRequest(func(r *colly.Request) {
		fmt.Println("visiting", r.URL.String())
	})

	detailCollector.OnHTML("#single_header", func(e *colly.HTMLElement) {
		pd := pageDetail{
			title:    e.ChildText("h1"),
			readTime: e.ChildText("span[title]"),
		}
		pageDetails = append(pageDetails, pd)
	})

	c.Visit("https://kazusa-pg.com/")

	for _, pd := range pageDetails {
		fmt.Printf("%s %s\n", pd.title, pd.readTime)
	}
}

コードを実行すると各ブログのURLにアクセスし、リンク先のタイトルと何分で読了できるかの情報を表示します。

visiting https://kazusa-pg.com/neetcode-arrays-and-hashing/
visiting https://kazusa-pg.com/golang-jpeg-progressive/
visiting https://kazusa-pg.com/pq-next-business-day/
visiting https://kazusa-pg.com/playwright-go-upload-file/
visiting https://kazusa-pg.com/golang-add-shape-frame/
visiting https://kazusa-pg.com/vba-copy-shapes/
visiting https://kazusa-pg.com/wp-to-hugo/
visiting https://kazusa-pg.com/golang-get-files-in-zip/
visiting https://kazusa-pg.com/vba-get-files-in-zip/
visiting https://kazusa-pg.com/golang-colly-web-scraping/
【Golang】NeetCodeのArrays & Hashingを解く 5 分
【Golang】jpeg画像がプログレッシブ形式か判別する 2 分
【Power Query】Excel Power Queryで翌営業日・前営業日を出力する 4 分
【Golang】playwright-goでファイルをアップロードする 3 分
【Golang】png画像に枠線をつける 1 分
【VBA】図形を別シートにコピーする 1 分
WordPressからHugoに移行しました 10 分
【Golang】zip内のファイル一覧を展開せずに取得する 2 分
【VBA】zip内のファイル一覧を展開せずに取得する 2 分
【Golang】Collyを使用してWebスクレイピングを行う 5 分

ファイルや画像を保存する
#

Collyを使って画像をダウンロードして保存するにはcollectorのOnResponseメソッドを使用します。

OnResponseはサーバーからレスポンスを受け取るたびに呼び出されます。
レスポンスにはサーバーから返されたHTMLや画像などのコンテンツが含まれているのでSaveメソッドを使用することでレスポンスの内容を保存することができます。

下記のコードは、このブログのトップページのプロフィール画像を保存するサンプルです。

package main

import (
	"fmt"

	"github.com/gocolly/colly/v2"
)

func main() {

	c := colly.NewCollector()
	c.OnResponse(func(r *colly.Response) {
		r.Save("./profile.png")
		fmt.Print("保存しました")
	})

	err := c.Visit("https://kazusa-pg.com/img/profile-picture_hu2961160223197158946.png")
	if err != nil {
		panic(err)
	}

}

コードを実行すると、コードを実行したパスに、このブログのプロフィール画像をprofile.pngとして保存します。

エラーを処理する
#

Collyを使ってWebスクレイピングを行う際にエラーが発生することがあります。
例えばサーバーから404エラーが返されたり、タイムアウトしたりすることがあります。

Collyではエラーを処理するためにOnErrorメソッドが用意されています。
このメソッドを設定することで、エラーが発生したときの動作を定義することができます。

下記のコードではテストサーバーから404 Not Foundが返ってくるのでOnErrorメソッドを使ってエラーを処理しています。

package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"

	"github.com/gocolly/colly/v2"
)

func main() {
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusNotFound)
	}))
	defer server.Close()

	c := colly.NewCollector()

	c.OnError(func(r *colly.Response, err error) {
		fmt.Println("エラーが発生しました:", err)
	})

	c.Visit(server.URL)
}

コードを実行すると下記のように表示されます。

エラーが発生しました: Not Found

もしくはVisitメソッドがerrorを返すので、errorの内容を元に処理を行います。

	err := c.Visit("URL")
	if err != nil {
		panic(err)
	}

参考リンク
#

関連記事

Robotgoで指定範囲のキャプチャーを連続で取得する
·1 分
Programming Golang
Robotgoで自動操作
··3 分
Programming Golang
Golangで標準入力を使用する関数のテスト
··3 分
Programming Golang