LoginSignup
13
12

More than 5 years have passed since last update.

GoビギナーがPDFのクローラー作った

Posted at

はじめに

2017年4月22日〜23日,千葉県某所にてGoエンジニア合宿に参加したので,
そこで作ってみた物と,Goの感想などを記事にしようと思います.

参加したイベント詳細
Go合宿2017
a5356bf154130f483221a0d4e01fadf9.png

Gopherかわえぇ...

自分のスペック

  • Go歴(ほぼ)0日
  • A Tour of Goリタイア勢
  • 最近はSwiftでアプリ作ってる
  • サーバーサイドはほとんど触ったことない

Go&クローラーの話

おそらく一番有名なチュートリアルのA Tour of Goでフィボナッチ数列の練習問題までやったら謎の自信が出て来た()

Goの,goroutineとchannelを使って非同期でバババッと気持ちいいことしたくなったので,
クローラーを作ることに

クローラー概要・使い方
main関数内のurlにダウンロードしたいPDFがあるページのURLを入れる.
実行.
PDFがデフォのいい感じの名前になってダウンロードされる.
ディレクトリを指定してダウンロードするやり方がわからなかったので,残念なことにソースコードと同じディレクトリに保存される(本当に残念)

以下ソースコード

package main

import (
    //goのスクレイピングモジュール
    "github.com/PuerkitoBio/goquery"
    "net/url"
    "net/http"
    "strings"
    "io"
    "os"
    "sync"
    "log"
)

func GetPdf_goroutine(url_string string) {
    //
    wait := new(sync.WaitGroup)
    doc, _ := goquery.NewDocument(url_string)
    doc.Find("a").Each(func(_ int, s *goquery.Selection) {
        path , _ := s.Attr("href")
        if (strings.Index(path, ".pdf") != -1 ) {
                result, _ := url.Parse(url_string)
            //この辺が冗長な気がする
            i := strings.LastIndex(path, "/")
            file_name := path[i+1:len(path)]
            go func(path string) {
                wait.Add(1)
                //この辺も冗長な気がする
                response, err := http.Get(result.Scheme + "://" + result.Host + path)
                if err != nil {
                    panic(err)
                }
                defer response.Body.Close()
                file, _ := os.Create(string(file_name))
                defer file.Close()
                io.Copy(file, response.Body)
                wait.Done()
            }(path)
            wait.Wait()
        }
    })
}

func GetPdf(url_string string) {
    doc, _ := goquery.NewDocument(url_string)
    doc.Find("a").Each(func(_ int, s *goquery.Selection) {
        path , _ := s.Attr("href")
        if (strings.Index(path, ".pdf") != -1 ) {
            result, _ := url.Parse(url_string)
            //この辺も冗長な気がする
            i := strings.LastIndex(path, "/")
            file_name := path[i+1:len(path)]
            //この辺も冗長な気がする
            response, err := http.Get(result.Scheme + "://" + result.Host + path)
            if err != nil {
                panic(err)
            }
            defer response.Body.Close()
            file, _ := os.Create(string(file_name))
            defer file.Close()
            io.Copy(file, response.Body)
        }
    })
}


func main() {
    log.Print("Start",)
        //例として大学の入試ページの入試要項を保存する.大学のサーバーごめんなさい.   
        url := "http://www.iwate-pu.ac.jp/examination/gakubu.html"
    GetPdf_goroutine(url)
    log.Print("Finish",)
}


goroutine有無の比較

スクリーンショット 2017-04-23 20.35.30.png

syncの使い方が怪しいのですが,これくらい差が出ました.データを引っ張って来たりする時はgoを付ける(単純)
goroutineを使うことで半分の時間,倍の速度でダウンロードできた.これすごくない?

Node.jsで作るクローラーより,ソースコードが見やすい,非同期処理がめっちゃ簡単という印象を受けた.
逆にめんどくせーなと思ったのは,未使用のパッケージをインポートしてると怒られるところ.ポチポチコメントアウトしながらコード書いてるので,いちいち指摘されるのは少々面倒

圡善旅館の話


圡善旅館

研究室の合宿はここでしよう(岩手並感)

まとめ感想

ただただ勉強しただけなのに,賞までいただけたので,本当に実りある合宿になった.
初めてGoを勉強したが,Cから入った自分にはとても既視感のある言語でとっつきやすい.
早い,単純,みんなで開発しやすそう

今後もGoでなんかやることが増えそう

みんな圡善旅館に行こう‼︎

参考にした記事

13
12
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
13
12