LoginSignup
45

More than 5 years have passed since last update.

テレビ番組をキーワード検索してSlack通知するならYahoo!テレビが最強(golang+goquery)

Last updated at Posted at 2018-03-20

特定のキーワード(キャラクターや俳優やサービス等)の番組がいつ放送されるかを抑えたい!という人は結構いらっしゃるんじゃないでしょうか。
私もその一人で、自社サービスに関連する市場のニュースは抑えておきたいなぁと思い、テレビ番組をキーワード検索してSlackに流したいなと思っていました。

↓こんな感じで通知したいなぁと。

image.png

テレビ番組表のAPIやRSSはない。Yahoo!テレビを使おう。

そこで、テレビ番組表のAPIやRSSを探してみましたが、、該当するものは以下の通りでした。

  • NHK番組表API(地上波の全放送局をカバーできない)
  • Gガイド.テレビ王国(RSSがあるらしいがSo-net会員になる必要あり)
  • Livedoor RSS(2008年にサービス終了)

テレビの番組表(アニメ)取得APIについて色々というエントリーを拝見しましたが、やはりAPIやRSSで一発で地上波の番組を網羅するのは難しいようです。

そこで、スクレイピング前提でテレビ番組表のサービスを見ていたら、Yahoo!テレビ.Gガイドのキーワード検索が非常に使い勝手がよいと分かりました。

あなたが神か

https://tv.yahoo.co.jp/search/?q=ITのようにGETパラメータだけで、放送予定の番組名と番組内容からキーワード検索してくれます。
もちろん地上波の全放送局をカバー。地域設定も可能で、BS/CSの番組も検索対象に含めることができます。
goo番組表もキーワード検索できるのですが、過去の番組が多くヒットするので、今回は利用しないことにしました。

あとはスクレイピングするだけです。

golang+goqueryでスクレイピング

Yahoo!テレビ.Gガイドでは、ul.programlist > liで取得した各要素をEachすれば番組情報をさくっと取り出せます。(2018年3月時点)
今回は、golangの有名なスクレイピング用ライブラリのgoqueryを使ってみました。
jQueryと同様にセレクタを指定すれば要素を抜き出すことができます。

goqueryの基本的な使い方などはgoqueryでお手軽スクレイピング!を参照していただくとよいかと。
go getするなり何なりして利用します。

$ go get github.com/PuerkitoBio/goquery

とりあえず、以下のように動かすだけで、番組情報をテキスト化することができます。
とっても簡単です。

main.go
package main

import (
    "os"
    "fmt"
    "github.com/PuerkitoBio/goquery"
)

func main() {
    doc, err := goquery.NewDocument("https://tv.yahoo.co.jp/search/?q=キーワード")
    if err != nil {
        fmt.Print("document not found. ")
        os.Exit(1)
    }

    program := ""
    doc.Find(".programlist > li").Each(func(_ int, s *goquery.Selection) {
        program += s.Text() + "\n"
    })

    fmt.Print(program)
}

私が実際に使うときには、こんな感じに情報を絞って取り出しています。

  • 放送日時
  • 放送局
  • 番組名
  • 番組内容
  • Yahoo!テレビ内の番組詳細へのリンク
    postText := ""
    linkUrl := ""
    doc.Find(".programlist > li").Each(func(_ int, s *goquery.Selection) {
        postText += "_"
        s.Find(".leftarea > p > em").Each(func(_ int, em *goquery.Selection) {
            postText += em.Text() + " "
        })
        atag := s.Find(".rightarea > p > a").First()
        postText += s.Find(".rightarea > p > span").First().Text()
        postText += "_"
        postText += " *[" + atag.Text() + "]* :"
        linkUrl, _ = atag.Attr("href")
        postText += s.Find(".rightarea > p").Filter(":not(:has(a,span))").Text()

        postText += "\n" + "> https://tv.yahoo.co.jp/" + linkUrl + "\n"
    })

slack通知までやってみよう

このソースをマルコピでそれなりに動くかと思います。
実行時は $ go run main.go "キーワード" "https://hooks.slack.com/services/hogefuga/foobar" のように検索キーワードとwebhookのURLを指定してください。

main.go
package main

func main() {
    if len(os.Args) != 3 {
        fmt.Print("specify keyword and webhook url.")
        os.Exit(1)
    }
    var keyword string = os.Args[1]
    var webhook string = os.Args[2]

    doc, err := goquery.NewDocument("https://tv.yahoo.co.jp/search/?q=" + keyword)
    if err != nil {
        fmt.Print("document not found. ")
        os.Exit(1)
    }

    postText := ""
    linkUrl := ""
    doc.Find(".programlist > li").Each(func(_ int, s *goquery.Selection) {
        postText += "_"
        s.Find(".leftarea > p > em").Each(func(_ int, em *goquery.Selection) {
            postText += em.Text() + " "
        })
        atag := s.Find(".rightarea > p > a").First()
        postText += s.Find(".rightarea > p > span").First().Text()
        postText += "_"
        postText += " *[" + atag.Text() + "]* :"
        linkUrl, _ = atag.Attr("href")
        postText += s.Find(".rightarea > p").Filter(":not(:has(a,span))").Text()

        postText += "\n" + "> https://tv.yahoo.co.jp/" + linkUrl + "\n"
    })

    if postText == "" {
        fmt.Print("program not found. ")
        os.Exit(0)
    }

    jsonStr := "{\"text\":\"" + postText + "\"}"
    fmt.Print(jsonStr)
    req, _ := http.NewRequest(
        "POST",
        webhook,
        bytes.NewBuffer([]byte(jsonStr)),
    )
    req.Header.Set("Content-Type", "application/json")

    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        fmt.Print(err)
    }
    defer resp.Body.Close()

}

cronで毎晩キーワード検索を仕掛けるといいんじゃないかと思います。!
以上です。

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
45