#作ったもの
エリアを指定したら本日開催しているイベント情報を検索してくれるLINE Botです。
(ウォーカープラスよりデータを取得)
友だち登録はこちらから
今回このBotを100行で実装しました。
ソースを公開しますので、参考していただきオリジナルBotを作ってみましょう。
#用意するもの
- Heroku または PHPが動くサーバー (QiitaかGoogle調べてください)
- LINE Message APIアカウント (QiitaかGoogle調べてください)
- linebot_libをダウンロード (こちらから) < 重要!
#まずはサンプルソースを動くようにする
こちらはHerokuのアプリケーションフォルダにlinebot_libを入れた状態です。
「sample_linebot.php」を動かしてみましょう。
下記記事を参考にdefine.phpにAPIのアクセストークンとシークレットを入れれば動くはずです。
▼▼
LineBot PHPで簡単シンプルに使えるライブラリを使ってLineBotを作る FlexMessaging対応
Webhook URLは「https://{アプリケーション名}.herokuapp.com/sample_linebot.php」
動かない場合はheroku logs
を打ってエラーをみて解消してください。
#本題の実装へ
##1.エリア選択の表示
メイン部分。
$messeage_type === 'text'
:メッセージだったらエリア選択を返す。
<?php
require_once __DIR__ . '/linebot_lib-master/linebot.php';
require_once 'phpQuery-onefile.php';
$bot = new LineBotClass();
try {
while ($bot->check_shift_event()) { // メッセージがなくなるまでループ
$text = $bot->get_text(); // テキストを取得
$messeage_type = $bot->get_message_type(); // メッセージタイプを取得
$event_type = $bot->get_event_type(); // イベントタイプを取得
if ($event_type === "postback") { // ポストバックのイベントなら
// あとで
} else if ($messeage_type === 'text') {
$bot->add_flex_builder("エリアを選択してください", createSelectAreaMessage());
}
$bot->reply();
}
} catch (Exception $e) {
$error = $e->getMessage();
$bot->add_text_builder("エラーキャッチ:" . $error);
$bot->reply();
}
createSelectAreaMessageでFlexMessageのコンテナオブジェクトを生成します。
サンプルのflex4を拡張したものです。
post Actionのオブジェクト作るのも繰り返しが面倒だったのでメソッド化してます > createPostActionText
function createSelectAreaMessage() {
global $bot;
$flex_box_mein = array();
$flex_components = array();
$flex_components['body'][] = $bot->create_text_component("検索エリアを選択してください",array("size"=>5,"weight"=>"bold"));
$area = ['新宿'=>'t_shinjuku', '渋谷'=>'t_shibuya', '池袋'=>'t_ikebukuro', '銀座'=>'t_ginza', '六本木'=>'t_roppongi',
'お台場'=>'t_odaiba', '吉祥寺'=>'t_kichijoji', '上野'=>'t_ueno', '品川'=>'t_shinagawa', '浅草'=>'t_asakusa', '東京駅周辺'=>'t_tokyoeki'];
foreach ($area as $key => $value) {
$flex_components['body'][] = createPostActionText($key,$value);
}
$flex_box_mein['body'] = $bot->create_box_component("vertical",$flex_components['body'],array("spacing"=>4));
$bubble_blocks = array(
"body" => $flex_box_mein['body']
);
return [$bot->create_bubble_container($bubble_blocks)];
}
function createPostActionText($label, $data) {
global $bot;
$action = $bot->create_post_action_builder($label,$data,$label);
return $bot->create_text_component($label, array("size"=>6,"wrap"=>true,"action"=>$action,"align"=>"center","color"=>"#0000ff"));
}
参考:LINEBotクラス($bot)の各関数はlinebot.phpに書かれているので引数が分からない場合は読みましょう。
/**
* Flex Messageは、複数の要素を組み合わせてレイアウトを自由にカスタマイズできるメッセージです
* @param [type] $altText 代替テキスト 最大文字数:400
* @param [type] $bubbles Flex Messageのコンテナオブジェクト
*/
public function add_flex_builder($altText,$bubbles)
{
$bubbles_array = array();
foreach ((array)$bubbles as $key => $value) {
$bubbles_array[] = $value;
}
// ビルダーを追加
$this->builder_stok[] = new FlexMessageBuilder($altText,new ContentsBuilder($bubbles_array));
}
おまけ
$area = ['新宿'=>'t_shinjuku', foreach〜
の部分は下記ベタで書かける所をちょっとスマートにしたカタチです。
$flex_components['body'][] = createPostActionText('新宿','t_shinjuku');
$flex_components['body'][] = createPostActionText('渋谷','t_shibuya');
$flex_components['body'][] = createPostActionText('池袋','t_ikebukuro');
$flex_components['body'][] = createPostActionText('銀座','t_ginza');
$flex_components['body'][] = createPostActionText('六本木','t_roppongi');
$flex_components['body'][] = createPostActionText('お台場','t_odaiba');
$flex_components['body'][] = createPostActionText('吉祥寺','t_kichijoji');
$flex_components['body'][] = createPostActionText('上野','t_ueno');
$flex_components['body'][] = createPostActionText('品川','t_shinagawa');
▼こっちの方がコードを短縮できる
$area = ['新宿'=>'t_shinjuku', '渋谷'=>'t_shibuya', '池袋'=>'t_ikebukuro', '銀座'=>'t_ginza', '六本木'=>'t_roppongi',
'お台場'=>'t_odaiba', '吉祥寺'=>'t_kichijoji', '上野'=>'t_ueno', '品川'=>'t_shinagawa', '浅草'=>'t_asakusa', '東京駅周辺'=>'t_tokyoeki'];
foreach ($area as $key => $value) {
$flex_components['body'][] = createPostActionText($key,$value);
}
##2.エリア選択を受け取る〜スクレイピング〜メッセージ作成
post actionを利用したので、$event_type === "postback"
の時に処理します。
<?php
require_once __DIR__ . '/linebot_lib-master/linebot.php';
require_once 'phpQuery-onefile.php';
$bot = new LineBotClass();
try {
while ($bot->check_shift_event()) { // メッセージがなくなるまでループ
$text = $bot->get_text(); // テキストを取得
$messeage_type = $bot->get_message_type(); // メッセージタイプを取得
$event_type = $bot->get_event_type(); // イベントタイプを取得
if ($event_type === "postback") { // ポストバックのイベントなら
$bot->add_flex_builder("検索しました", createEventSearchMessage($bot->get_post_data()));
} else if ($messeage_type === 'text') {
$bot->add_flex_builder("エリアを選択してください", createSelectAreaMessage());
}
$bot->reply();
}
} catch (Exception $e) {
$error = $e->getMessage();
$bot->add_text_builder("エラーキャッチ:" . $error);
$bot->reply();
}
###スクレイピング
Web上のHTMLを抜き出します。
phpQueryというライブラリーを使います。
以下参考にしてください。
まず対象のウォーカープラスのイベントページのHTMLを解析。
本日+新宿のページ > こちら
▼こちらはChromeのデベロッパーツールで要素の検証をしているところ
このクラスを取ればいいかなと思ったら、paizaで試してみる。
(phpQuery-onefile.phpを別タブにコピペして、requireしたら使えます)
aタグの1個目が「タイトル」
aタグの2個目が「イベント内容」
aタグの5個目が「場所」
imgタグが「写真」
aタグの1個目のhref
アトリビュートに「詳細ページのリンク」
上記が判明しました。
あとはlinebot_app.phpにロジックを書いていくだけ
① スクレイピングして、イベントのまとまり.m-mainlist-item
のListを返す
function getEventList($areaName) {
$html = file_get_contents('https://www.walkerplus.com/event_list/today/ar0313TER/'.$areaName.'/');
$doc = phpQuery::newDocument($html);
$list = $doc[".m-mainlist-item"];
return $list;
}
② 上記リスト(イベントデータ)からFlexMessageを作ります > createFlexMessage
Flex Messageはサンプルのflex3のモデルをほぼそのまま使ってます。
function createEventSearchMessage($postData) {
$flex_bubble = array();
$searchResult = getEventList($postData);
foreach ($searchResult as $item) {
$flex_bubble[] = createFlexMessage($item);
}
return $flex_bubble;
}
function createFlexMessage($item) {
$title = pq($item)->find('a:eq(0)')->text(); //タイトル
$decs = pq($item)->find('a:eq(1)')->text(); //説明
$place = pq($item)->find('a:eq(4)')->text(); //場所
$img = pq($item)->find('img')->attr('src'); //写真(url)
$link = pq($item)->find('a:eq(0)')->attr('href'); //イベントページ
global $bot;
$flex_box_mein = array();
$flex_components = array();
$flex_components['header'][] = $bot->create_text_component($place,array("size"=>5,"weight"=>"bold","color"=>"#e60033"));
$flex_box_mein['header'] = $bot->create_box_component("vertical",$flex_components['header'],array("spacing"=>4));
$flex_components['body'][] = $bot->create_text_component(trim($title),array("size"=>5,"weight"=>"bold","wrap"=>true));
$flex_components['body'][] = $bot->create_text_component($decs,array("size"=>4,"wrap"=>true));
$flex_box_mein['body'] = $bot->create_box_component("vertical",$flex_components['body'],array("spacing"=>3));
$action = $bot->create_url_action_builder("イベント詳細をみる",'https://www.walkerplus.com'.$link);
$flex_components['footer'][] = $bot->create_button_component($action,array("style"=>"secondary"));
$flex_box_mein['footer'] = $bot->create_box_component("vertical",$flex_components['footer'],array("spacing"=>3));
$image_url = 'https:'.$img;
$bubble_blocks = array(
"header" => $flex_box_mein['header']
,"hero" => $bot->create_image_component($image_url, array("size"=>11,"aspectRatio"=>"4:3","aspectMode"=>"cover"))
,"body" => $flex_box_mein['body']
,"footer" => $flex_box_mein['footer']
);
return $bot->create_bubble_container($bubble_blocks);
}
はい、これにて完成です!
完成ソースはこちら▼
<?php
require_once __DIR__ . '/linebot_lib-master/linebot.php';
require_once 'phpQuery-onefile.php';
$bot = new LineBotClass();
try {
while ($bot->check_shift_event()) { // メッセージがなくなるまでループ
$text = $bot->get_text(); // テキストを取得
$messeage_type = $bot->get_message_type(); // メッセージタイプを取得
$event_type = $bot->get_event_type(); // イベントタイプを取得
if ($event_type === "postback") { // ポストバックのイベントなら
$bot->add_flex_builder("検索しました", createEventSearchMessage($bot->get_post_data()));
} else if ($messeage_type === 'text') {
$bot->add_flex_builder("エリアを選択してください", createSelectAreaMessage());
}
$bot->reply();
}
} catch (Exception $e) {
$error = $e->getMessage();
$bot->add_text_builder("エラーキャッチ:" . $error);
$bot->reply();
}
function createSelectAreaMessage() {
global $bot;
$flex_box_mein = array();
$flex_components = array();
$flex_components['body'][] = $bot->create_text_component("検索エリアを選択してください",array("size"=>5,"weight"=>"bold"));
$area = ['新宿'=>'t_shinjuku', '渋谷'=>'t_shibuya', '池袋'=>'t_ikebukuro', '銀座'=>'t_ginza', '六本木'=>'t_roppongi',
'お台場'=>'t_odaiba', '吉祥寺'=>'t_kichijoji', '上野'=>'t_ueno', '品川'=>'t_shinagawa', '浅草'=>'t_asakusa', '東京駅周辺'=>'t_tokyoeki'];
foreach ($area as $key => $value) {
$flex_components['body'][] = createPostActionText($key,$value);
}
$flex_box_mein['body'] = $bot->create_box_component("vertical",$flex_components['body'],array("spacing"=>4));
$bubble_blocks = array(
"body" => $flex_box_mein['body']
);
return [$bot->create_bubble_container($bubble_blocks)];
}
function createPostActionText($label, $data) {
global $bot;
$action = $bot->create_post_action_builder($label,$data,$label);
return $bot->create_text_component($label, array("size"=>6,"wrap"=>true,"action"=>$action,"align"=>"center","color"=>"#0000ff"));
}
function createEventSearchMessage($postData) {
$flex_bubble = array();
$searchResult = getEventList($postData);
foreach ($searchResult as $item) {
$flex_bubble[] = createFlexMessage($item);
}
return $flex_bubble;
}
function getEventList($areaName) {
$html = file_get_contents('https://www.walkerplus.com/event_list/today/ar0313TER/'.$areaName.'/');
$doc = phpQuery::newDocument($html);
$list = $doc[".m-mainlist-item"];
return $list;
}
function createFlexMessage($item) {
$title = pq($item)->find('a:eq(0)')->text();
$decs = pq($item)->find('a:eq(1)')->text();
$place = pq($item)->find('a:eq(4)')->text();
$img = pq($item)->find('img')->attr('src');
$link = pq($item)->find('a:eq(0)')->attr('href');
global $bot;
$flex_box_mein = array();
$flex_components = array();
$flex_components['header'][] = $bot->create_text_component($place,array("size"=>5,"weight"=>"bold","color"=>"#e60033"));
$flex_box_mein['header'] = $bot->create_box_component("vertical",$flex_components['header'],array("spacing"=>4));
$flex_components['body'][] = $bot->create_text_component(trim($title),array("size"=>5,"weight"=>"bold","wrap"=>true));
$flex_components['body'][] = $bot->create_text_component($decs,array("size"=>4,"wrap"=>true));
$flex_box_mein['body'] = $bot->create_box_component("vertical",$flex_components['body'],array("spacing"=>3));
$action = $bot->create_url_action_builder("イベント詳細をみる",'https://www.walkerplus.com'.$link);
$flex_components['footer'][] = $bot->create_button_component($action,array("style"=>"secondary"));
$flex_box_mein['footer'] = $bot->create_box_component("vertical",$flex_components['footer'],array("spacing"=>3));
$image_url = 'https:'.$img;
$bubble_blocks = array(
"header" => $flex_box_mein['header']
,"hero" => $bot->create_image_component($image_url, array("size"=>11,"aspectRatio"=>"4:3","aspectMode"=>"cover"))
,"body" => $flex_box_mein['body']
,"footer" => $flex_box_mein['footer']
);
return $bot->create_bubble_container($bubble_blocks);
}
?>
linebotライブラリー使わないと3倍以上のコードかつ工数もかかるので、今回かなり楽でした。(実際3時間半で出来ました)
ぜひ皆さんも使ってみてください。
【参考】LineBot PHPで簡単シンプルに使えるライブラリを使ってLineBotを作る FlexMessaging対応
https://qiita.com/jyuki/items/035cfeb72d7d359c738b
今回紹介したLINE Bot「遊び場さがし」の友だち登録はこちら
#自作LINE Bot紹介
[LINE Bot] 位置情報から食べログ3.5以上の優良店を検索するbot作った