推しの村山美羽ちゃんによる致死量を超えるかわいい写真の供給が始まったので自動で収集したい
はじめに
おはようございます
祝 村山美羽ちゃん ブログ開始おめでとうございます! 祝
初回のブログから致死量を超えるかわいい写真を供給してくれてオタクは大歓喜でございます。
せっかくこんなにもかわいい写真を供給してくれているのに、保存のし忘れなんてしてしまっては絶望です。
そこで、今回はちょっぱやでどうにか仕組みを作ってみないかと思い手を動かしてみた次第です。
準備
こちらを参考に通知用のSlackアプリを作成します。
ここで推しのアーティスト写真を設定しておくのもポイントです。
構成
SlackへブログURL共有 -> サーバー -> ブログから情報収集 -> Slackへ通知
※ slackでイベント共有をトリガーにしてしまうと ブログURL共有 -> 写真URL共有の無限ループが起こりそうだったので今回はcurlで叩くことにしました。
という処理にします。
また、筆者はGo言語も推しています。
いつしか知った、vercel
のserverless-functions
を用いてGoアプリをデプロイしようと思います。
実装
以前、櫻坂46のブログから画像のURLだけを引っこ抜くという実装はしたことがあったので今回はそれを使いまわします。
特に紹介するほどでもないので今回は割愛します。
goqueryというライブラリを使ってごにょごにょするだけです。
vercelのドキュメントによるとapi
というディレクトリを作ってそこにindex.go
というファイルを配置しfunc Handler(w http.ResponseWriter, r *http.Request)
を実装するようです。
コードは以下のような流れにしました。
エラー処理はものすごくザルです。
package handler
const (
baseURL = "https://sakurazaka46.com"
)
type Body struct {
URL string `json:"url"`
}
func Handler(w http.ResponseWriter, r *http.Request) {
var body Body
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}
if !Validate(body.URL) {
w.WriteHeader(http.StatusBadRequest)
return
}
pics, err := ExtractPhotoURLFromBlog(body.URL)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}
for _, pic := range pics {
Post(os.Getenv("ENDPOINT"), fmt.Sprintf("%s%s", baseURL, pic))
}
w.WriteHeader(http.StatusOK)
}
念のためバリデーションも実装しておきます。
先頭と末尾で櫻坂46のブログURLかどうか判定するだけです。
決め打ちなので今後は変わってしまうかもしれません。
func Validate(url string) bool {
// baseURLから始まる
if !strings.HasPrefix(url, baseURL) {
return false
}
// 末尾がblogで終わる
return strings.HasSuffix(url, "blog")
}
Slackへの通知は以下の実装です。
ただSlackアプリで払い出したWebhookのURLにPOSTするだけです。
(エラーハンドリングはpanic
実装なので結構雑です。)
func Post(endpoint string, msg string) {
body := map[string]string{
"text": msg,
}
jsonString, err := json.Marshal(body)
if err != nil {
panic(err)
}
req, err := http.NewRequest(http.MethodPost, endpoint, bytes.NewBuffer(jsonString))
if err != nil {
panic(err)
}
req.Header.Set("Content-Type", "application/json")
client := new(http.Client)
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
}
デプロイ
このページを参照し作業しました。
ただ、デプロイするのに以下ハマりました。
-
npm install vercel@latest
でnode_modules
に入れていたがgo mod tidy
がうまく動かなかった
-> とくにこだわりがないのであればnpm install -g vercel@latest
でよさそう。 -
vercel deploy
していたがprev
環境が作られすぎた。
-> 個人開発とかちょっとした開発ならvercel deploy --prod
でよさそう。 -
--env XXX=YYY
で環境変数を指定できる。
-> シークレット値とかはこれで管理することになりそう。
動作確認
Slackへの通知
Slackは画像のURLを共有すると自動で展開してくれるので良いですね。
curlによりvercel起動
400エラーも正しく動作することが確認できました。
お片付け
雑に作ったアプリなので以下のコマンドでお片付けしておきます。
vercel project rm <project-name>
深堀りしたいこと
- ルーティングの設定
- 複数functionをひとつのリポジトリで管理できるのか
展望
- ちゃんとリポジトリ管理する
- 村山美羽ちゃんの個人ブログが本格的に始まったら更新を自動検知したい
- 方法要検討
- cron使える?
- 画像を自動保存する
- 保存先要件等
おわりに
ブログ開始に合わせてちょっぱやで手を動かして作ったので完成度は低いです。
ですが、キャッチアップしてみたかったvercel
のserverless-functions
を試せたのでよかったです。
これでまたGo実装のデプロイ先としての手札が増えました。
(貧乏エンジニアリングでFaaSによりGoデプロイできるのは素晴らしい。)
村山美羽ちゃんかわいいです。
Discussion