Goのスクレイピング系ライブラリまとめの中からgoqueryをピックアップして試してみました。
ターゲットはGithubRanking。
ちなみに、ただただランキング情報を取得したい場合はGithubAPIを使えばいけます。
ターゲット
- Github Repositories Ranking
- ページングをたどりながら上位1000件のリポジトリ名とstarの数を取得する
利用ライブラリ
いざ、スクレピング!
goqueryの追加
% go get github.com/PuerkitoBio/goquery
DOMの調査
- ブラウザのデベロッパーコンソールとか、Firebugとか使ってDOMを調査する
- goqueryはjQueryのセレクタがほぼ使えるので、コンソールでセレクタに当てをつけてjs書いて取得要素を確認してくのが効率が良い
- 例)コンソールに
$("a.list-group-item")
を入力して取得要素を見てみる
プログラム
package main
import (
"fmt"
"log"
"strings"
"time"
"github.com/PuerkitoBio/goquery"
)
const (
targetfqdn = "github-ranking.com"
)
func IsRelativePath(url string) bool {
if strings.Index(url, "//") == 0 {
return false
} else if strings.Index(url, "/") == 0 {
return true
} else {
return false
}
}
func GetAbsoluteURLFromRelativePath(scheme string, fqdn string, relativePath string) string {
return scheme + "://" + fqdn + relativePath
}
func hasNextPageURL(doc *goquery.Document) (string, bool) {
nexturl, exists := doc.Find("ul > li.next > a").First().Attr("href")
if exists == true && IsRelativePath(nexturl) {
return GetAbsoluteURLFromRelativePath("https", targetfqdn, nexturl), true
}
return nexturl, false
}
func outputRepoAndStar(groupItemSelection *goquery.Selection) {
groupItemSelection.Each(func(i int, s *goquery.Selection) {
repositorie := s.Find("span.name span.hidden-lg").Text()
stars := s.Find("span.stargazers_count").Text()
fmt.Printf("★ %s : %s\n", strings.TrimSpace(stars), strings.TrimSpace(repositorie))
})
}
func main() {
doc, err := goquery.NewDocument(GetAbsoluteURLFromRelativePath("https", targetfqdn, "/repositories"))
nexturl, hasNext := "", true
if err != nil {
log.Fatal(err)
}
for hasNext {
outputRepoAndStar(doc.Find("a.list-group-item"))
nexturl, hasNext = hasNextPageURL(doc)
doc, err = goquery.NewDocument(nexturl)
time.Sleep(3000)
}
}
ポイント
func NewDocument
-
doc, err := goquery.NewDocument(GetAbsoluteURLFromRelativePath("https", targetfqdn, "/repositories"))
のように利用 - 引数のURLにリクエスト送付してレスポンス取得&DOMのロード&解析までしてくれる
func (*Selection) Find
-
doc.Find("a.list-group-item")
のように引数にセレクタを指定
func (*Selection) First
-
nexturl, exists := doc.Find("ul > li.next > a").First()
のようにFind関数で指定したセレクタにヒットする要素の中から1番目の要素を取得
func (*Selection) Attr
-
nexturl, exists := doc.Find("ul > li.next > a").First().Attr("href")
のように対象要素の属性値を取得する
実行
- GoSublimeを利用しているので
Command + 9
でSublimeのコンソールを開く- GoSublimeの入れ方は10分で終わるGo言語の開発環境構築を参照
- コンソールで
run
結果
1000件取得完了
[ `run` | done: 1.188862586s ]
★ 77733 : bootstrap
★ 35984 : free-programming-books
★ 35311 : angular.js
★ 34715 : node
★ 34492 : d3
★ 33394 : jquery
★ 30484 : Font-Awesome
★ 28736 : html5-boilerplate
★ 25849 : awesome
★ 24954 : rails
★ 23174 : impress.js
★ 22520 : meteor
......省略......
★ 2763 : generator-angular-ful...
★ 2762 : JazzHands
★ 2762 : bottle
★ 2760 : serf
★ 2757 : nock
★ 2755 : scraperjs
★ 2755 : cool-retro-term
★ 2750 : passenger
★ 2748 : heatmap.js
★ 2747 : peerjs
参考