goで「今日はなんの日?」をSlackに投稿する
goの学習を進めたいんだけどなかなかテーマが決まらない…。
チュートリアルや本を読んでいてもなかなか頭に入らず、手を動かさないと身につかないタイプ。
そこで、自身のTwitterアカウントで自動投稿している「今日はなんの日?」をgoを使ってSlackに投稿出来るようにしてみようと思ってやってみました。
Yahooキッズの中に「今日はなんの日?」というコンテンツがあるので、そのページからXPATHを使って「なんの日なのか?」と「記念日の説明」を取得し、Slackに投稿するというところまでを試してみる。
YahooのページにアクセスしてHTMLを取得する
まずはページにアクセスすることが出来ないと始まらないので go を使ってHTTPアクセスを行い、ページを取得するところまでを実装してみる。
goでのHTTPアクセスは元々用意されている net/http を利用する。
そしてページのBodyの取得は ioutil を利用する。
package main
import (
"fmt"
"io/ioutil"
"log"
"net/http"
)
func main() {
log.Println("Start")
response, error := http.Get("https://kids.yahoo.co.jp/today/")
defer response.Body.Close()
if error != nil {
log.Println("Access failed.")
return
}
if response.StatusCode != 200 {
log.Fatalf("Access failed. StatusCode: %d\n", response.StatusCode)
return
}
log.Println("Success access.")
bytes, err := ioutil.ReadAll(response.Body)
if err != nil {
log.Fatalln(err.Error())
return
}
fmt.Println(string(bytes))
}
XPathを使ってページの要素を取得する
ページの取得は行えたので、まずはChromeを使って取得したい要素のXPathを調べる。
- 何の日
//*[@id="dateDtl"]/dt/span
- 詳細
//*[@id="dateDtl"]/dd
そして go で XPATH から要素を取得する方法を調べていくと、公開されているライブラリでHTMLからXPathを元に要素を取得できるものがあった。
こちらのライブラリはURLを指定すればHTTPアクセスし、HTMLを取得、そこからXPATHを使って要素を取得するところまでやってくれるようだ。
package main
import (
"fmt"
"log"
"github.com/antchfx/htmlquery"
)
func main() {
log.Println("Start")
doc, _ := htmlquery.LoadURL("https://kids.yahoo.co.jp/today/")
titleElement := htmlquery.FindOne(doc, "//*[@id=\"dateDtl\"]/dt/span")
fmt.Printf("タイトル: %s\n", htmlquery.InnerText(titleElement))
descriptionElement := htmlquery.FindOne(doc, "//*[@id=\"dateDtl\"]/dd")
fmt.Printf("本文: %s\n", htmlquery.InnerText(descriptionElement))
}
Slackへ投稿する
Slack周りのライブラリは slack-go を使う。
Slackトークン・チャンネルはハードコーディングせず、環境変数に設定する。
package main
import (
"fmt"
"log"
"os"
"github.com/antchfx/htmlquery"
"github.com/slack-go/slack"
)
func main() {
log.Println("Start")
token := os.Getenv("SLACK_BOT_TOKEN")
channel := os.Getenv("SLACK_CHANNEL")
if token == "" || channel == "" {
log.Fatalln("環境変数が取得できませんでした")
return
}
doc, _ := htmlquery.LoadURL("https://kids.yahoo.co.jp/today/")
titleElement := htmlquery.FindOne(doc, "//*[@id=\"dateDtl\"]/dt/span")
fmt.Printf("タイトル: %s\n", htmlquery.InnerText(titleElement))
descriptionElement := htmlquery.FindOne(doc, "//*[@id=\"dateDtl\"]/dd")
fmt.Printf("本文: %s\n", htmlquery.InnerText(descriptionElement))
message := "✨✨✨ 今日は何の日? ✨✨✨\n\n**" + htmlquery.InnerText(titleElement) + "**\n\n" + htmlquery.InnerText(descriptionElement)
client := slack.New(token)
// MsgOptionText() の第二引数に true を設定すると特殊文字をエスケープする
_, _, err := client.PostMessage(channel, slack.MsgOptionText(message, true))
if err != nil {
panic(err)
}
log.Println("Finish")
}
ここまで実装すれば go run main.go
をターミナルから実行すればSlackに投稿できるようになる。
参考にしたサイト
- https://zenn.dev/kou_pg_0131/articles/go-slack-go-usage
- https://qiita.com/frozenbonito/items/1df9bb685e6173160991
- https://yhidetoshi.hatenablog.com/entry/2021/12/17/163639
AWSのLambdaから定期実行させる
Lambdaへの登録の方法は参考にしたサイトがあるのでこちらを見てもらうほうが良さそう。
参考にしたサイト
最終的なコード
package main
import (
"fmt"
"log"
"os"
"github.com/antchfx/htmlquery"
"github.com/aws/aws-lambda-go/lambda"
"github.com/slack-go/slack"
)
func Handler() {
log.Println("Start")
token := os.Getenv("SLACK_BOT_TOKEN")
channel := os.Getenv("SLACK_CHANNEL")
if token == "" || channel == "" {
log.Fatalln("環境変数が取得できませんでした")
return
}
doc, _ := htmlquery.LoadURL("https://kids.yahoo.co.jp/today/")
titleElement := htmlquery.FindOne(doc, "//*[@id=\"dateDtl\"]/dt/span")
fmt.Printf("タイトル: %s\n", htmlquery.InnerText(titleElement))
descriptionElement := htmlquery.FindOne(doc, "//*[@id=\"dateDtl\"]/dd")
fmt.Printf("本文: %s\n", htmlquery.InnerText(descriptionElement))
message := "✨✨✨ 今日は何の日? ✨✨✨\n\n" + htmlquery.InnerText(titleElement) + "\n\n" + htmlquery.InnerText(descriptionElement)
client := slack.New(token)
// MsgOptionText() の第二引数に true を設定すると特殊文字をエスケープする
_, _, err := client.PostMessage(channel, slack.MsgOptionText(message, true))
if err != nil {
panic(err)
}
log.Println("Finish")
}
func main() {
lambda.Start(Handler)
}
$ GOOS=linux GOARCH=amd64 go build -o main
$ zip main.zip main
これでOK!
感想
やっぱりテーマを決めて手を動かすとさくさく進む。
何よりgoのライブラリがとても優秀でほぼライブラリを呼び出すだけでコーディングよりも調べたりする時間のほうが多かった気がする。
まだ slack-go の使い方はちゃんと調べられておらず、SlackBotの名前とアイコンの書き換え方法がわかっていないので引き続き調べていきたい。
こんな感じで今後も何かテーマを決めて学習を進めていくのが良さそう。
今回の実際のコードはこちら。
Discussion