こんにちは。KOUKIです。
goroutineを学ぶために、何かサンプルがないかとYoutubeで探していたところ、面白そうな動画がアップロードされてました。
この動画で紹介されているコードは、Webページから情報をスクレイピングして、その結果をCSVファイルに出力します。
goroutine化ができそうなコードだったので紹介します。
<目次>
必要なモジュール
1 |
go get -u github.com/gocolly/colly/... |
goroutine化前
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
package main import ( "encoding/csv" "fmt" "log" "os" "strconv" "time" "github.com/gocolly/colly" ) func main() { fName := "data.csv" // data.csvを作成する file, err := os.Create(fName) if err != nil { log.Fatalf("Could not create file, err :%q", err) return } defer file.Close() // csv操作インスタンス writer := csv.NewWriter(file) defer writer.Flush() // collyインスタンス c := colly.NewCollector( colly.AllowedDomains("internshala.com"), ) // html -> .internship_meta要素にアクセス c.OnHTML(".internship_meta", func(e *colly.HTMLElement) { writer.Write([]string{ // aタグ e.ChildText("a"), // spanタグ e.ChildText("span"), }) }) start := time.Now() // スクレイピング for i := 0; i < 312; i++ { fmt.Printf("Scraping Page: %d\n", i) c.Visit("https://internshala.com/internships/page-" + strconv.Itoa(i)) } // 後処理 end := time.Now() log.Println("Scraping Complete") log.Printf("Time:%v", end.Sub(start)) log.Println(c) } |
簡単な説明は、コメントしました。本当に簡単ですけどね^^;
このプログラムを実行するとWebページからスクレイピングした情報をdata.csvファイルに出力します。
1 2 3 4 5 6 7 8 9 10 |
go run main.go Scraping Page: 0 Scraping Page: 1 Scraping Page: 2 Scraping Page: 3 .... 2020/12/21 07:24:44 Scraping Complete 2020/12/21 07:24:44 Time:3m30.197672269s 2020/12/21 07:24:44 Requests made: 312 (312 responses) | Callbacks: OnRequest: 0, OnHTML: 1, OnResponse: 0, OnError: 0 |
「Time:3m30.197672269s」と表示されたので、約3分かかるようですね。これをgoroutineを使って高速化しましょう。
goroutine化後
直感的な感じだとネットワーク越しにアクセスしている「c.Visit」の処理がボトルネックになっている気がします。
この処理をgoroutine化してみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
start := time.Now() var wg sync.WaitGroup // スクレイピング for i := 0; i < 312; i++ { wg.Add(1) // goroutine化 go func(i int) { defer wg.Done() fmt.Printf("Scraping Page: %d\n", i) c.Visit("https://internshala.com/internships/page-" + strconv.Itoa(i)) }(i) } wg.Wait() |
goroutine化するとその処理がサブプロセスとして実行されます。
しかし、実装上、main関数の処理が先に終了してしまうので、syncパッケージのWaitGroupを使って、サブプロセスが全て終了するまで、main関数が終了するのを待ちます。
プログラムを実行してみましょう。
1 2 3 4 5 |
go run main.go 2020/12/21 10:24:25 Scraping Complete 2020/12/21 10:24:25 Time:2.763387294s 2020/12/21 10:24:25 Requests made: 312 (10 responses) | Callbacks: OnRequest: 0, OnHTML: 1, OnResponse: 0, OnError: 0 |
今度は、「Time:2.763387294s」になりました。約3秒なので、かなり早くなったと思います。
おわりに
スクレイピングすることができるCollyは、3rd-Partyのモジュールですが、結構便利ですよね。私もYoutube動画で初めて知りました。
それにプラスして、goroutineを使うと処理がめちゃくちゃ早くなることも体験できたと思います。
どんどん活用していきましょう!
コメントを残す
コメントを投稿するにはログインしてください。