cloud functions・pub/sub・puppetterで夜22時前後のテレビ番組情報を取得して生活を少し良くした話
夜の報道番組が結構好きです。
最近、テレビ東京のニュース番組であるWBSが22時台になったり、大谷翔平が想像以上に活躍して日本のプロ野球情報よりもMLB情報の方が欲しくなったり、緊急事態宣言やまんぼうで夜のカフェで作業できなくなったり、としたことで、何か生活のリズムが崩れて来た感覚を持ち始めていました。
そんななか、夜22時前後のテレビ番組情報をさくっとcloud functions・pub/sub・puppetterで取得して自分のslackに通知するだけでその辺の感覚が結構正常化されたので、ざっくり共有です:
結果
情報の取得
あまり使ったことなかったですが、こういう情報は動的なサイトが多いイメージがあったので、puppetterで取得してみました。
こんな感じのhtmlがあったとすると、
<table class="aaa">
<tbody>
<tr>
<td>
<div class="bbb">TITLE<div class="ccc">CONTENT</div></div>
</td>
<td></td>
<td></td>
</tr>
<tr><tr/>
<tr><tr/>
</tbody>
</table>
puppeterではこんな感じでしょうか。
import * as puppeteer from 'puppeteer';
// https://github.com/GoogleChrome/puppeteer/issues/3120
const browser = await puppeteer.launch({
args: [
'--no-sandbox',
'--disable-setuid-sandbox',
'-–disable-dev-shm-usage',
'--disable-gpu',
'--no-first-run',
'--no-zygote',
'--single-process',
],
headless: true
});
const page = (await browser.pages())[0];
await page.goto(URL);
let listSelector = "table.aaa > tbody > tr > td";
const datas = await page.evaluate((selector) => {
const list = Array.from(document.querySelectorAll(selector));
var contents = [];
for (let i = 0; i < list.length; i++) {
if (list[i].querySelector("div.bbb") != null) {
let title = list[i].querySelector("div.bbb").innerText;
// 自分のみたい内容があるときは詳細取得
if (title.includes("XXX")) {
let programType;
if (title.includes("XXX")) {
programType = "XXX"
}
let textContent = list[i].querySelector("div.bbb > div.ccc").innerText;
var content = {
programType: programType,
textContent: textContent,
};
contents.push(content);
}
}
}
return contents;
}, listSelector);
page.evaluate()内では、page.click()が使えなかったのですが、性能面含めてもう少し良い書き方はある気がしています。。。
https://stackoverflow.com/questions/59867111/puppeteer-how-to-use-page-click-inside-page-evaluate
slackへの投稿
取得した内容は、slack側で権限を設定したりトークンを取得した後に、下記のようにslackにも投稿しておきます。slackに投稿されてから20分ぐらい放置しておくとメールが飛んできます。
const {WebClient} = require('@slack/web-api');
const token = "xabcd-123451234512-123451234512345-xXXXX~~~";
const channelId = "C012345~~~";
const web = new WebClient(token);
web.chat.postMessage({
text: textContent + "\n" + url,
channel: channelId,
}).catch((e: any) => {
functions.logger.info(`end slack error:${e}`);
})
cloud functionsとpub/subで定期的に動かす
上記のスクリプトをcloud functionsとpub/subで下記のようにして定期的に動かします。メモリは512MBぐらいにしておいた方があまりエラーはないと思います。
import * as functions from "firebase-functions";
const runtimeOpts: RuntimeOptions = {
// timeoutSeconds: 300,
memory: '512MB'
}
exports.scheduledFunctionGetData = functions
.runWith(runtimeOpts)
.pubsub
.schedule('0 */x * * *') //x時間ごとに動かす
.timeZone('Asia/Tokyo')
.onRun(async (context) => {
※上記のスクリプト※
}
firestoreへの保存
何となくfirestoreにも入れておきます。データが溜まったらbig queryで何かしてみたいと思います。
ちなみに、 https://www.bravesoft.co.jp/seblog/archives/2213 を参考にさせて頂きました。
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
const firestore = admin.firestore();
var docRef = firestore.collection("route22").doc(YYYYMMDD());
const now: Date = new Date();
docRef.collection(programType).doc(now.toDateString()).set({
text: textContent,
programType: programType,
url: url,
created: now
}
);
function YYYYMMDD() {
var dt = new Date();
return dt.getFullYear()
+ (('00' + (dt.getMonth() + 1)).slice(-2))
+ (('00' + dt.getDate()).slice(-2));
}
Author And Source
この問題について(cloud functions・pub/sub・puppetterで夜22時前後のテレビ番組情報を取得して生活を少し良くした話), 我々は、より多くの情報をここで見つけました https://qiita.com/water_boy_tokyo/items/d82f296c75fc1520f05b著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .