Go 언어로 HTML을 스크래핑하여 기차 지연 정보를 가르쳐주는 Slack-bot 만들기

11584 단어 5goqueryslackbot
Go와 Slack의 bot를 조합해서 공부를 하고 싶었기 때문에 관동의 전철 운행 상황을 취득하는 bot를 만들어 보았습니다.
사실은 마음대로 중얼거리는 방식으로 하고 싶었습니다만 우선 이 시점에서 기사로 합니다.
(그 중 개조할지도.)

슬랙 앱 만들기



이 사이트를 참조하여 만들었습니다.
Golang에서 Slack Interactive Message를 사용하여 Bot 작성

bot 만들기



스크래핑할 패키지 설치



goquery를 설치합니다.
jQuery적인 조작을 할 수 있으므로 경험이 있는 Web 엔지니어에게는 비교적 이해할 수 있습니다.
$ go get github.com/PuerkitoBio/goquery

정보를 얻는 웹사이트



여기가 없으면 시작되지 않습니다.
이번은 Yahoo!노선 정보 씨로부터 취득합니다.

구현



그럼 실제로 코딩하여 앱을 만듭니다.
「운행 상황」이라는 키워드에 반응해 상기 사이트로부터 운행 상황을 돌려주는 bot입니다.

slack_bot.go
package main

import (
    "log"
    "os"
    "net/url"
    "github.com/nlopes/slack"
    "github.com/PuerkitoBio/goquery"
)

// HTMLをスクレイピングして運行状況のテキストを取得する
func getRailwayText() string {
    _url := "https://transit.yahoo.co.jp/traininfo/area/4/"

    doc, err := goquery.NewDocument(_url)
    if err != nil {
        panic(err)
    }

    u := url.URL{}
    u.Scheme = doc.Url.Scheme
    u.Host = doc.Url.Host

    var message string
    // まずはテーブル要素を取得する
    doc.Find("div.trouble > table > tbody").Each(func(_ int, s *goquery.Selection) {
        // 次にtrを掘っていく
        s.Children().Each(func(idx int, ss *goquery.Selection) {
            // idx==0は見出し列なので飛ばす
            if (idx > 0) {
                railway := ss.Children().Find("a").Text()
                status := ss.Children().Find("span.colTrouble").Text()
                detail := ss.Children().Next().Next().Text()
                message = message + status + " @ " + railway + " (" + detail + ")\n"
            }
        })
    })
    return message
}

func run(api *slack.Client) int {
    rtm := api.NewRTM()
    go rtm.ManageConnection()

    for {
        select {
        case msg := <-rtm.IncomingEvents:
            switch ev := msg.Data.(type) {
            case *slack.HelloEvent:
                log.Print("Hello Event")

            case *slack.MessageEvent:
                switch ev.Text {
                case "運行状況":
                    message := getRailwayText()
                    rtm.SendMessage(rtm.NewOutgoingMessage(message, ev.Channel))
                case "help":
                    rtm.SendMessage(rtm.NewOutgoingMessage("Usage: 運行状況 関東圏の電車の運行状況を表示します。\n       他の機能?ないよ。", ev.Channel))
                }

            case *slack.InvalidAuthEvent:
                log.Print("Invalid credentials")
                return 1

            }
        }
    }
}

func main() {
    api := slack.New("YOUR TOKEN")
    os.Exit(run(api))
}


토큰은 Slack API 페이지의 왼쪽 메뉴 [OAuth & Permissions]의 [Bot User OAuth Access Token]에 있습니다.


실행



그럼 로컬 터미널에서 움직입니다.
$ go run slack_bot.go
2019/05/03 11:03:27 Hello Event


Hello Event가 표시되면 성공입니다.
실제로 만든 bot에 대해 메시지를 보냅니다.


제대로 돌아왔습니다!

끝에



goquery는 원하는 객체의 검색 조건을 지정하는 것만으로 마음대로 와 주므로 매우 편리했습니다.
복수의 사이트로부터 정보를 취득하는 경우라도 Go 유익한 병행 처리로 효율적으로 처리하거나 할 수 있을 것 같네요.
slack-bot도 확장성이 높고, 궁리에 따라 다양한 곳에서 효율화를 할 수 있을 것 같습니다.

참고



Go와 goquery로 스크래핑

좋은 웹페이지 즐겨찾기