LoginSignup
17
13

More than 5 years have passed since last update.

Go+goqueryでGithubRankingにWebスクレイピングを試みる

Last updated at Posted at 2016-03-03

Goのスクレイピング系ライブラリまとめの中からgoqueryをピックアップして試してみました。
ターゲットはGithubRanking
ちなみに、ただただランキング情報を取得したい場合はGithubAPIを使えばいけます。

ターゲット

スクリーンショット 2016-03-03 23.38.36.png

利用ライブラリ

  • goquery
    • jQueryに近しい関数が用意されており、セレクタも使えるスーパー便利なライブラリ

いざ、スクレピング!

goqueryの追加

% go get github.com/PuerkitoBio/goquery

DOMの調査

  • ブラウザのデベロッパーコンソールとか、Firebugとか使ってDOMを調査する
  • goqueryはjQueryのセレクタがほぼ使えるので、コンソールでセレクタに当てをつけてjs書いて取得要素を確認してくのが効率が良い
    • 例)コンソールに$("a.list-group-item")を入力して取得要素を見てみる

スクリーンショット 2016-03-03 23.59.57.png

プログラム

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")のように対象要素の属性値を取得する

実行

結果

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

参考

17
13
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
13