Go
golang
goquery

goqueryを使ってサイト内のCSSをスクレイピング

サイト内で使用されているCSSを確認しようとしたのですが、膨大なページがあったのでスクレイピングをする事にしました。その時に使用したgoqueryがとても便利でした。

他にもスクレイピング系ライブラリがあるみたいです。
Go言語のスクレイピング系ライブラリまとめ

goqueryの便利なところは、HTMLのselectorを指定できるので、jQuery感覚で記述できる点です。
以下は、githubからExamplesをお借りしました。

ExampleScrape.go
func ExampleScrape() {
  doc, err := goquery.NewDocument("http://metalsucks.net")
  if err != nil {
    log.Fatal(err)
  }

  // Find the review items
  doc.Find(".sidebar-reviews article .content-block").Each(func(i int, s *goquery.Selection) {
    // For each item found, get the band and title
    band := s.Find("a").Text()
    title := s.Find("i").Text()
    fmt.Printf("Review %d: %s - %s\n", i, band, title)
  })
}

めちゃくちゃ読みやすくないですか?

sitemapから各ページで使用されているCSSを洗い出す

各ページで使用されているCSSを洗い出すために以下の事を行なっています。
思ったよりサクっとできました:thumbsup:

  1. sitemapにあるaタグのhref、タイトルを取得。
  2. http://example.com/がついていないかチェック。ついていなかったらつける。
  3. 重複が存在している場合は削除。(めっちゃdirty)
  4. 最後はURLを使って、各ページにアクセスし、CSSを取得・表示。
main.go
package main

import _ "fmt"

import (
    "bytes"
    "fmt"
    "github.com/PuerkitoBio/goquery"
    "regexp"
)

func main() {
    urls := []string{}
    titles := []string{}
    doc, err := goquery.NewDocument("http://example.com/sitemap/")
    if err != nil {
        fmt.Print("url scarapping failed")
    }
    doc.Find("a").Each(func(_ int, s *goquery.Selection) {
        url, _ := s.Attr("href")
        title, _ := s.Html()
        urls = append(urls, url)
        titles = append(titles, title)
    })
    urls = removeDuplicate(createProtocolUrl(urls))
    for i := range urls {
        doc, err := goquery.NewDocument(urls[i])
        if err != nil {
            fmt.Print("\n", "child url scarapping failed", "\n")
        }
        doc.Find("[rel='stylesheet']").Each(func(_ int, s *goquery.Selection) {
            cssPath, _ := s.Attr("href")
            fmt.Print(titles[i], "  --  ", urls[i], " -> ", cssPath, "\n")
        })
    }
}

func createProtocolUrl(urls []string) (result []string) {
    arrayUrlHasProtocol := []string{}
    for i := range urls {
        var url string
        if hasDomain(urls[i]) {
            url = urls[i]
        } else {
            var buffer bytes.Buffer
            buffer.WriteString("https://example.com")
            buffer.WriteString(urls[i])
            url = buffer.String()
        }
        if url != "" {
            arrayUrlHasProtocol = append(arrayUrlHasProtocol, url)
        }
    }
    return arrayUrlHasProtocol
}

func hasDomain(path string) bool {
    return regexp.MustCompile(`^http://example.com/`).Match([]byte(path))
}

func removeDuplicate(args []string) []string {
    results := make([]string, 0, len(args))
    for i := 0; i < len(args); i++ {
        dup := false
        for j := 0; j < len(results); j++ {
            if args[i] == results[j] {
                dup = true
                break
            }
        }
        if !dup {
            results = append(results, args[i])
        }
    }
    return results
}

まとめ

スクレイピング自体どの言語を使っても割と簡単にできるので、今回はGo言語で行いました。
コードを書くよりも環境設定の方が時間かかりました。結局gopathをどこにしたらいいのかはわからず:cry:
Go自体こういったコードを書くには向いてると思います!