10
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Onikenがセールになったら通知してくれるやつをつくる

Last updated at Posted at 2021-01-12

この記事はリンク情報システム2021新春アドベントカレンダー Tech Connect!のリレー記事です。
Tech Connect! は勝手に始めるアドベントカレンダーとして、engineer.hanzomon のグループメンバによってリレーされます。


この間のセールで買いそびれた人に向けた記事です。

スクレイピングした結果をSlackに連携するだけのよくあるやつですが、他の記事との差別化を図るためにGoogle Cloud Platform(以下GCP), Microsoft Azure(以下Azure), Amazon Web Services(以下AWS)にそれぞれデプロイしてみます。

つくるもの

1日1回 My Nintendo StoreのOnikenのページ を見に行ってセール中だったらSlackに連携する。

つくる

My Nintendo Storeのrobots.txtを確認

https://store-jp.nintendo.com/robots.txt を確認します。
「/list/software/」はDisallowされていなかったので問題なし。

Slackの設定

アプリの追加画面を開く

slack01.png

Incoming WebHooksを追加

slack02.png

slack03.png

通知先のチャンネルを指定

slack04.png

Webhook URLをメモ

名前もわかりやすいものに変えておく。
slack05.png

スクリプトなどの準備

スクレイピングとSlackへの連携用のスクリプト

とりあえず動けばいいぐらいのやつ。

import json
import os

import requests
from bs4 import BeautifulSoup

res = requests.get(os.environ['TARGET_URL'])
soup = BeautifulSoup(res.text, 'html.parser')
div = soup.select_one('div.productDetail--detail__pricePrice')

if div is not None:
    item = {
        "text": div.text.strip()
    }
    json_data = json.dumps(item)
    res = requests.post(os.environ['WEBHOOK_URL'], json_data)

スクレイピング

div = soup.select_one('div.productDetail--detail__pricePrice') で以下の情報(値段)を取得します。
これが取得できなかった場合はセール中ではないためSlackへは連携しません。
s01.png

Slackへの連携

res = requests.post(os.environ['WEBHOOK_URL'], json_data) の部分。
Webhook URLへjsonのデータをpostするだけです。

今回は単純なメッセージですが、複雑なものを作ってみたい場合はBlock Kit Builderで色々試してみるのがいいかと思います。

requirements.txt

beautifulsoup4==4.9.1
requests==2.24.0

GCPへデプロイ

開く

Cloud Functions

スクレイピングしてSlackに連携する部分を担当。

Cloud Functionsを選択

gcp01.png

関数を作成

gcp02.png

各種設定

"基本"はお好きなように。
"トリガー"は画像の通りに設定して"保存"する。
URLは後で使うのでメモしておくこと
gcp03.png

ランタイム環境変数の設定

名前
TARGET_URL OnikenのページのURL
WEBHOOK_URL 最初の方でメモしたSlackのWebhook URL

設定したら"次へ"。
gcp04.png

Build APIの有効化

gcp05.png

スクリプトを編集

まんまコピペしているわけではないので注意。
gcp06.png

requirements.txtを編集

コピペしたら"デプロイ"。
gcp07.png

デプロイ完了を確認

これは少し時間がかかります。
gcp08.png

Cloud Scheduler

これを使って1日1回Cloud Functionsを実行します。
無料枠で3ジョブまで作成できる

Cloud Schedulerを選択

gcp09.png

ジョブを作成

この画面のあとにリージョン選択画面がありますが、スクショを撮り忘れました。
好きな場所を選択してください。
gcp10.png

各種設定

名前、説明などはお好きなように。

項目
ターゲット HTTP
URL 先ほど作成したCloud FunctionsのトリガーURL
HTTPメソッド GET

設定が終わったら"作成"。

gcp11.png

GCPへのデプロイ終わり

GCPへのデプロイはこれで終わりです。

Azureへデプロイ

開く

環境構築

今回の構成ではAzure Portal上でコードを書けないため、色々と準備が必要になります。
長くなりそうなので詳細は割愛します。

関数アプリ(Azure Functions)

リソースの作成

az01.png

関数アプリを選択

az02.png

各種設定

赤枠以外はお好きなように。
他はデフォルトで"確認および作成"。
az03.png

作成

az04.png

デプロイ完了したら"リソースに移動"。
az05.png

環境変数の設定

以下の2つを設定して"保存"。

名前
TARGET_URL OnikenのページのURL
WEBHOOK_URL 最初の方でメモしたSlackのWebhook URL

az06.png

関数を作成

Visual Studio Codeでの操作になります。

Azureにサインイン

az07_01.png

プロジェクト作成

今回はDesktopに作ったazure_sampleフォルダで作業を行います。
az07_02.png

言語を選択

az08.png
az09.png

関数のトリガーを選択

"Timer trigger"を選択します。
az10.png

名前を付ける

az--.png

スケジュールを指定

毎日01:00に実行するように指定しています。
az11.png

スクリプトを編集

しばらく待つと__init__.pyというファイルが開かれるので、事前に用意していた内容に書き換えます。
az12.png

requirements.txtを編集

プロジェクトフォルダ(今回はazure_sample)にrequirements.txtがあるのでそれを編集します。
az13.png

デプロイ

多少時間がかかります。
az14.png

ちゃんとデプロイされています。
az15.png

Azureへのデプロイ終わり

Azureへのデプロイはこれで終わりです。
Timer triggerのおかげで関数アプリ単独で実現できました。

AWSへデプロイ

開く

Lambda

関数作成の画面に行く

aws01.png
aws02.png

関数の作成

関数名はお好きなように。
オプションとランタイムの選択が終わったら"関数の作成"。
aws03.png

zipファイルをつくる

bs4~urllib3まではpythonのライブラリ。
lambda_function.py は事前に用意したスクリプトをlambda用にしたもの。

oniken.zip
 ├ bs4
 ├ certifi
 ├ chardet
 ├ idna
 ├ requests
 ├ soupsieve
 ├ urllib3
 └ lambda_function.py
lambda_function.py
import json
import os

import requests
from bs4 import BeautifulSoup

def lambda_handler(event, context):
	res = requests.get(os.environ['TARGET_URL'])
	soup = BeautifulSoup(res.text, 'html.parser')
	div = soup.select_one('div.productDetail--detail__pricePrice')

	if div is not None:
	    item = {
	        "text": div.text.strip()
	    }
	    json_data = json.dumps(item)
	    res = requests.post(os.environ['WEBHOOK_URL'], json_data)
	    
	    return "success"

zipファイルのアップロード

aws04.png
aws05.png

環境変数の設定

aws06.png

以下の2つを設定して"保存"。

名前
TARGET_URL OnikenのページのURL
WEBHOOK_URL 最初の方でメモしたSlackのWebhook URL

aws07.png

トリガー

トリガーを追加

aws08.png

EventBridgeの設定

毎日02:00に実行するように指定しています。
aws09.png

AWSへのデプロイ終わり

AWSへのデプロイはこれで終わりです。
ライブラリも自分でアップロードしないといけないので面倒でした。(GCP, Azureはrequirements.txt書くだけ)

動作確認

00:00(GCP)、01:00(Azure)、02:00(AWS)にそれぞれ通知が来る予定でしたが、AzureとAWSが9時間ほどずれています。
GCPはCloud Schedulerでタイムゾーンを設定しましたが、そういえばAzureとAWSではそのような設定が無かったような気がします。
result.png

Azure

ログを見ると01:03(UTC)に動いていました。
3分のずれは一体?

AWS

ログを見るとこちらも02:00(UTC)に動いていました。

とはいえ

動きはしたのでこれは宿題とします。

まとめ

環境構築が出来ていればAzureが圧倒的に楽でした。
Timer triggerは偉大。

種類 かんたん ふつう むずかしい
環境構築していない GCP AWS Azure
環境構築済み Azure GCP AWS

参考

Microsoft StoreのOnikenのページがどうしてあんなことになっているのか解明してくれる人を探しています。

あんなこととは?
Microsoft StoreのOnikenのページより引用。

不吉な企業によって制御された目次録後の未来において、8ビットのアクション/プラットフォームの過酷なゲームプレイに触発されて、鬼剣は敵、罠、そして挑戦的なボスの籠手に対してあなたの敏捷性と刀剣を打ちつけます。

少し読んでもらえば分かる通り、日本語がおかしなことになっています。

翻訳元を探る
Microsoft StoreのOnikenのページ(英語)より引用。
パブリッシャーの製品ページも同じ文章。

In a post-apocalyptic future controlled by a sinister corporation, ninja mercenary Zaku is the last hope for humanity. Inspired by the demanding gameplay of 8-bit action/platformers, Oniken pits your agility and swordplay against a gauntlet of enemies, traps, and challenging bosses.

「目次録」とは「黙示録」のことでした。

翻訳してもらう
原文(日本語ページ)を見る限り何らかの翻訳をかませてそうなので、英語ページの文章をいくつかのサイトで翻訳してもらいます。

不吉な企業によって支配された終末後の未来において、忍者傭兵ザクは人類への最後の希望です。 8ビットアクション/プラットフォーマーの要求の厳しいゲームプレイに触発されたOnikenは、敵、罠、挑戦的なボスのガントレットに対して敏捷性と剣術を打ち負かします。

邪悪な企業に支配されたポスト黙示録的な未来では、忍者の傭兵ザクが人類の最後の希望となっていた。8ビットアクション/プラットフォーマーの厳しいゲーム性にインスパイアされた「鬼剣」は、敏捷性と剣術を駆使して、敵、トラップ、ボスなどの難関を突破していく。

不吉な企業が支配するポスト黙示録的な未来の中で、忍者傭兵ザクは人類の最後の希望です。8ビットアクション/プラットホームの厳しいゲームプレイに触発され、Onikenは敵、トラップ、そして挑戦的なボスのガントレットに対してあなたの敏捷性と剣遊びをピット。

不吉な企業によって支配された後の後進法において、忍者の傭兵のザクは人類にとって最後の希望である。 8 ビットアクション/小皿の厳しいゲームに触発され、鬼剣は敵、罠、そして挑戦的なボスに対して、機敏に剣術を注ぎ、その腹部に対して剣術を行う。

Google翻訳の結果が原文に近い
DeepL翻訳を除いた3つはほぼ似た結果になっており、中でもGoogle翻訳は忍者傭兵ザクの部分を除くとかなり原文に近い印象です。
原文とGoogle翻訳の結果を並べて違いを見てみます。

  • 原文

不吉な企業によって制御された目次録後の未来において、8ビットアクション/プラットフォーム過酷なゲームプレイに触発されて、鬼剣は敵、罠、そして挑戦的なボスの籠手に対してあなたの敏捷性と刀剣打ちつけます

  • Google翻訳(から忍者傭兵ザクの部分を除外)

不吉な企業によって支配された終末後の未来において、8ビットアクション/プラットフォーマー要求の厳しいゲームプレイに触発されたOnikenは、敵、罠、挑戦的なボスのガントレットに対して敏捷性と剣術打ち負かします

Google翻訳のアップデートで翻訳結果が変わってしまったようなレベルの違いしかないように見えます。

深まる謎
日本語ページの文章はおそらくGoogle翻訳の結果をベースにしていると思われる、というところまでは来ましたが理解できない謎が残っています。

  • 目次録
    何をどうやったら黙示録が目次録になってしまうのか検討もつきません。
    英語 → (翻訳) → 日本語 → (音声読み上げ) → (Speech to Text) → 日本語 とすれば、Speech to Textの箇所で聞き間違いが発生する可能性もなくはないですが、わざわざこんなことする意味もないでしょう。

  • 消えてしまった忍者傭兵ザク
    ザクはOnikenの主人公です。
    翻訳の際に

おわりに
答えに近づけた方がいましたらぜひ教えて下さい。

10
6
0

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
10
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?