LineBotの作り方を教わったので、「14時くらいから17時までの「テレ朝 ドラマ再放送ゴールデンタイム」の番組タイトルを教えてくれるLineBotを作ってみる!」にチャレンジしています。今回は前回(スクレイピングしてみた)の続きになります。
スクレイピングでゴールデンタイムの情報を取得することができたのでLineBotとして組み込んでまいりたいとおもいます。
#LineBotの作成
ひとまず動くプロトタイプの完成を目指したいので、環境はテスト用とします。外部のサーバなどは利用せず、自分のパソコンをサーバとして、テスト的にLineBotを機能させます。Lineの開発アカウントの取得、環境の作り方はmintak21さんのページが参考になります。
いろいろなサービスを使ってLINEbotを作ろう【ngrok編】
#ひとまずできました
とりあえずできました!
なんでもよいので、Botちゃんに問いかけるとその日のゴールデンタイムに放送するドラマを返してくれます!
いろいろ課題がありますが、こんな簡単に通信して情報を表示するアプリが作れるなんてすごい世の中になったなぁとしみじみ。。
今日は土曜日なので再放送ゴールデンタイムではなかったです、、残念。
#非同期処理が実装できませんでした
テレ朝のサイトに情報を取得しに行くため処理に時間がかかります。非同期な処理を実現する必要があり、見よう見まねでコードを書いてみましたが、うまくいかず。。。残念。
ひとまず動けばいいや!の精神でウェイトのようなものを入れて要件を満たしました。今後しっかり勉強して正しく解決したいところです。
//非同期がうまくいかないので、とりあえず2秒待つ//
const _sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
await _sleep(2000);
#スクレイピングとLineBotを合体させたコード
前回作ったスクレイプの機能とLineBotの機能を合体させました。そんなわけで非同期的な処理がうまくできていないですが、、、
'use strict';
// パッケージの設定
const express = require('express');
const line = require('@line/bot-sdk');
const cheerioh = require('cheerio-httpcli');
//スーパー再放送タイムの設定 任意の時間帯
const ssstarttime = '13:46';
const ssendtime = '16:30';
// ローカル(自分のPC)でサーバーを公開するときのポート番号です
const PORT = process.env.PORT || 3000;
// Messaging APIで利用するクレデンシャル(秘匿情報)です。
const config = {
channelSecret: 'XXXXXXXXXXXXXXXXX',
channelAccessToken: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXx'
};
//テレ朝様から情報をもらいつつ、Lineに返します
const tereasaFunction = async (event) => {
// 「リプライ」を使って先に返事しておきます
await client.replyMessage(event.replyToken, {
type: 'text',
text: '少々おまちください……'
});
let pushText = '';
//テレ朝様に情報をもらいに行きます
const res = await cheerioh.fetch('https://www.tv-asahi.co.jp/bangumi/', {}, function (err, $, res) {
//当日の番組一覧を取得して配列に入れる
let tvinfo = [];
let r = 0;
$('.new_table .today .new_day .prog_name .bangumiDetailOpen').each(function () {
tvinfo[r] = [];
tvinfo[r][0] = $(this).text();
tvinfo[r][1] = "";
r = r + 1;
});
//開始時間を配列に格納する
let c = 0;
$('.new_table .today .new_day .min').each(function () {
let title = $(this).text();
tvinfo[c][1] = title.trim(); //空白が入っているので削除する
c = c + 1;
});
//スーパー再放送タイムか確認
let conststr = '2000/01/01 ';
let starttime = new Date(conststr + ssstarttime);
let endtime = new Date(conststr + ssendtime);
let tempdatestr;
let targettime;
for (let t = 0; t < tvinfo.length; t++) {
//判定
tempdatestr = conststr + tvinfo[t][1]; //番組表から取得した各番組の開始時刻で日付の文字列を生成
targettime = Date.parse(tempdatestr);
//スーパー再放送タイムであるか判定
if (targettime > starttime && targettime < endtime) {
pushText = pushText + tvinfo[t][1] + ' ' + tvinfo[t][0] + '\n';
}
}
pushText = pushText + '...を放送するようです!'
});
//非同期がうまくいかないので、とりあえず2秒待つ。。。。。//
const _sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
await _sleep(2000);
//非同期がうまくいかないので、とりあえず2秒待った あとでちゃんと勉強しよう//
// 「プッシュ」でLineに送る
return client.pushMessage(event.source.userId, {
type: 'text',
text: pushText,
});
};
// ########################################
// LINEサーバーからのWebhookデータを処理する部分
// ########################################
// LINE SDKを初期化します
const client = new line.Client(config);
// LINEサーバーからWebhookがあると「サーバー部分」から以下の "handleEvent" という関数が呼び出されます
async function handleEvent(event) {
// 受信したWebhookが「テキストメッセージ以外」であればnullを返すことで無視します
if (event.type !== 'message' || event.message.type !== 'text') {
return Promise.resolve(null);
}
// サンプル関数を実行します
return tereasaFunction(event);
}
// ########################################
// Expressによるサーバー部分
// ########################################
// expressを初期化します
const app = express();
// HTTP POSTによって '/webhook' のパスにアクセスがあったら、POSTされた内容に応じて様々な処理をします
app.post('/webhook', line.middleware(config), (req, res) => {
// 検証ボタンをクリックしたときに飛んできたWebhookを受信したときのみ以下のif文内を実行
if (req.body.events.length === 0) {
res.send('Hello LINE BOT! (HTTP POST)'); // LINEサーバーに返答します(なくてもよい)
console.log('検証イベントを受信しました!'); // ターミナルに表示します
return; // これより下は実行されません
} else {
// 通常のメッセージなど … Webhookの中身を確認用にターミナルに表示します
console.log('受信しました:', req.body.events);
}
// あらかじめ宣言しておいた "handleEvent" 関数にWebhookの中身を渡して処理してもらい、
// 関数から戻ってきたデータをそのままLINEサーバーに「レスポンス」として返します
Promise.all(req.body.events.map(handleEvent)).then((result) => res.json(result));
});
// 最初に決めたポート番号でサーバーをPC内だけに公開します
// (環境によってはローカルネットワーク内にも公開されます)
app.listen(PORT);
console.log(`ポート${PORT}番でExpressサーバーを実行中です…`);
#つぎはユーザーインタフェースを修正してみます
機能はできたので、最後にUIをいじってみたいと思います。
今日はここまで。おつかれさまでしたー