My Note

自己理解のためのブログ

Goでスクレイピングするためにgoqueryを使い、Yahoo路線情報の遅延情報を取得してみる

やったこと

Goのプログラミング学習の一環としてスクレイピングするためにgoquery使ってみた。

goqueryについて

  • GoDoc

godoc.org

github.com

Yahoo路線運行情報をスクレイピングする

スクレイピングするサイト ( Yahoo路線運行情報 )

transit.yahoo.co.jp

■ main.go

package main

import (
    "fmt"
    "net/url"

    "github.com/PuerkitoBio/goquery"
)

var(
    _url = "https://transit.yahoo.co.jp/traininfo/area/4/"
)

func main() {
    doc, err := goquery.NewDocument(_url)
    if err != nil {
        fmt.Println(err)
    }
    u := url.URL{}
    u.Scheme = doc.Url.Scheme
    u.Host = doc.Url.Host

    fmt.Println(u.Scheme)
    fmt.Println(u.Host)

    title := doc.Find("title").Text()
    fmt.Println(title)
}

/* 実行結果
https
transit.yahoo.co.jp
関東の運行情報(JR、私鉄、地下鉄、新幹線) - Yahoo!路線情報
*/

コードを読む

goquery.NewDocument(_url)

↓↓↓NewDocument↓↓↓

package goquery
・・・
func NewDocument(url string) (*Document, error) {
    // Load the URL
    res, e := http.Get(url)
    if e != nil {
        return nil, e
    }
    return NewDocumentFromResponse(res)
}

↓↓↓Document↓↓↓

package goquery
・・・
type Document struct {
    *Selection
    Url      *url.URL
    rootNode *html.Node
}

↓↓↓url.URL↓↓↓

package url
・・・
type URL struct {
    Scheme     string
    Opaque     string    // encoded opaque data
    User       *Userinfo // username and password information
    Host       string    // host or host:port
    Path       string    // path (relative paths may omit leading slash)
    RawPath    string    // encoded path hint (see EscapedPath method)
    ForceQuery bool      // append a query ('?') even if RawQuery is empty
    RawQuery   string    // encoded query values, without '?'
    Fragment   string    // fragment for references, without '#'
}

↑↑↑URL↑↑↑

u := url.URL{}

title := doc.Find("title").Text()

↓↓↓Find("title")↓↓↓

package goquery

・・・
type Document struct {
    *Selection
    Url      *url.URL
    rootNode *html.Node
}
// ↑↑↑*SelectionはDocument構造体に埋め込まれている↓↓↓

・・・  
func (s *Selection) Find(selector string) *Selection {
    return pushStack(s, findWithMatcher(s.Nodes, compileMatcher(selector)))
}

↓↓↓Text()↓↓↓

package goquery

・・・
func (s *Selection) Text() string {
    var buf bytes.Buffer

    // Slightly optimized vs calling Each: no single selection object created
    var f func(*html.Node)
    f = func(n *html.Node) {
        if n.Type == html.TextNode {
            // Keep newlines and spaces, like jQuery
            buf.WriteString(n.Data)
        }
        if n.FirstChild != nil {
            for c := n.FirstChild; c != nil; c = c.NextSibling {
                f(c)
            }
        }
    }
    for _, n := range s.Nodes {
        f(n)
    }

    return buf.String()
}

Yahoo路線情報の遅延情報を取得する

■ 運行情報 ( 関東 )

f:id:yhidetoshi:20190621084223p:plain

 <div class="elmTblLstLine trouble">

f:id:yhidetoshi:20190621084242p:plain

■ main.go

package main

import (
    "fmt"
    "net/url"

    "github.com/PuerkitoBio/goquery"
)

var(
    targetUrl = "https://transit.yahoo.co.jp/traininfo/area/4/"
)

func main() {
    doc, err := goquery.NewDocument(targetUrl)
    if err != nil {
        fmt.Println(err)
    }
    u := url.URL{}
    u.Scheme = doc.Url.Scheme
    u.Host = doc.Url.Host

    //fmt.Println(u.Scheme)
    //fmt.Println(u.Host)

    title := doc.Find("title").Text()
    fmt.Println(title)

    var message string

    doc.Find("div.trouble > table > tbody").Each(func(_ int, s *goquery.Selection) {
        s.Children().Each(func(i int, ss *goquery.Selection) {
            if (i > 0) {
                //fmt.Println(i)
                route := ss.Children().Find("a").Text()
                status := ss.Children().Find("span.colTrouble").Text()
                info := ss.Children().Next().Next().Text()
                message = message + status + " / " + route + " (" + info + ")\n"
            }
        })
    })
    fmt.Println(message)
}

■ 実行結果

関東の運行情報(JR、私鉄、地下鉄、新幹線) - Yahoo!路線情報
列車遅延 / 常磐線(快速)[品川~取手] (06:07頃、松戸~柏駅間で線…)

参考