20211013のNode.jsに関する記事は9件です。

バイクで走るタイムリミットをLINE_BotとWeb_APIを組み合わせて実装してみた~

近ごろ私達は~いい感じ♪ これが私の生きる道ですね! 見出しだけでピンきて懐かしさを感じた方はおそらく30代Overでしょう笑 (何故いきなり冒頭に?といった疑問は記事を読み進めるとわかりますので、お付き合いください~) さてさて、 10月からプログラミングを習い始めて毎日勉強中の私ですが、 LINE_BotとWeb_APIを組み合わせて何か試したいと思い、 大好きなバイクを例に作ってみました! これが私の走る道 学生時代からバイクで峠を走るのが大好きで、ヒマさえあれば埼玉県飯能市の自宅から 奥多摩湖(東京都西多摩郡)まで友人と走りに行っています。 しかし、1車線の道が続く田舎道なので日中は渋滞ばかりで気持ちよく走れません(´;ω;`)ウゥゥ 特に朝方と夕方は渋滞がひどく、それなら真夜中に気持ちよく走ろう! ということで、夜が更けてから朝方までひたすら峠を走るということを、 学生時代はよくやっていました(あの頃は若かった、、、) 奥多摩の夜は、空気が澄んでいて星が本当に綺麗なんです( ̄ー ̄) 出典:YAMA HACK 東京でも星が見られる!?奥多摩のおすすめの観察スポットとタイミング これが私の求む物 暖かい時期は日の出が早く、日が昇るにつれて交通量も増えます。 朝の渋滞に巻き込まれる前に帰る!というのが毎回のミッションで、 渋滞を回避するために、日の出・日の入りがわかるSunset and sunrise times APIを利用しました。 奥多摩から自宅まで約40分の道のりなので、 日の出の時間がわかれば家に着く時間を逆算して奥多摩を出発、 渋滞が起きる前には清々しい気持ちで家に着くといった魂胆です笑 LINE_BotとWeb_APIを組み合わせて、奥多摩を出発しなけばならない時間を逆算できるようにします~ 環境 Visual Studio Code v1.60.2 node v16.10.0 npm 7.21.1 Botに没頭、できてホッと。 以下、コードです。 server3.js 'use strict'; // ######################################## // 初期設定など // ######################################## // パッケージを使用します const express = require('express'); const line = require('@line/bot-sdk'); const axios = require('axios'); // ローカル(自分のPC)でサーバーを公開するときのポート番号です const PORT = process.env.PORT || 3000; // Messaging APIで利用するクレデンシャル(秘匿情報)です。 const config = { channelSecret: '作成したBotのチャネルシークレット', channelAccessToken: '作成したBotのチャネルアクセストークン' }; // ########## ▼▼▼ サンプル関数 ▼▼▼ ########## const sampleFunction = async (event) => { // ユーザーメッセージが「日の出」か「日の入り」かどうか if (event.message.text !== '今日のタイムリミットは?') { return client.replyMessage(event.replyToken, { type: 'text', text: '「今日のタイムリミットは?」と話しかけてね' }); } else { // 「リプライ」を使って先に返事しておきます await client.replyMessage(event.replyToken, { type: 'text', text: 'ちょいとお待ちを…' }); let pushText = ''; try { // axiosで日の出日の入り時刻のAPIを叩きます(少し時間がかかる・ブロッキングする) const res = await axios.get('https://api.sunrise-sunset.org/json?lat=35.7772463&lng=138.9766782'); // 取得できるのはUTCなので日本時間(+9時間)になおす const utc_time = res.data.results.sunrise; // '時', '分', '秒 PM' に分割する const tm_split = utc_time.split(':'); // '時' を9時間進めて12時間戻す(13時を過ぎないようにする) const jp_hour = Number(tm_split[0]) + 9 - 12; // '秒 PM' を '秒' だけにする const sec = tm_split[2].split(' ')[0]; // 再構成する const time_string = `${jp_hour}時${tm_split[1]}分${sec}秒`; pushText = `今日のタイムリミットは${time_string}です!渋滞前に帰りましょう!`; } catch (error) { pushText = '検索中にエラーが発生しました。ごめんね。'; // APIからエラーが返ってきたらターミナルに表示する console.error(error); } // 「プッシュ」で後からユーザーに通知します 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 sampleFunction(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サーバーを実行中です…`); LINE_BotとWeb_APIと習ったので、様々なAPIを叩いてみたものの、うまく動かすことが出来ず。 (動かすことができたら記事UPしますね~) そこは引き続き頑張るとして、今回はこんな感じのコードです! 緯度経度を奥多摩湖の場所に変更したり、出力文言を変更したり、 使っているコードを解読しながら、数時間没頭してやっと完成! 結果 「今日のタイムリミットは?」と入力すると、 「ちょいとお待ちを、、、」 「今日のタイムリミットは〇時〇分〇秒です!渋滞前に帰りましょう!」 とリプライメッセージが届きます。 この時間が奥多摩湖の日の出の時間ですね! 適当な文字を入れても質問文字を促してくれるので大丈夫です。 バイク乗りの本音で言うと、朝が冷え込む時期になると手先の感覚皆無で、 スマホ打つどころではなくなるので、実際使う時の入力は「あ」にしたいと思います~! 他にも面白そうなAPIがたくさんありますので、しばらくBotに没頭していきます(´-`).。oO 参考:APIマーケットプレイス - 10,000以上のRest APIにアクセス | Rakuten RapidAPI 参考:APIを探して、試して、使える - APIbank これが私に活きるか未知( ̄ー ̄) うそです、使いこなせるように頑張ります。 最後まで読んでいただき、ありがとうございました!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

APIとLINE Botを組み合わせることで、患者さんが必要な情報にアクセスできる仕組みを目指す その1-天気を伝える

患者さんご家族にとって便利なLINE Botを作りたい 福岡で在宅医療を中心とした医療機関を運営しています。 当院の患者さんやご家族、もしくは当院に診察を依頼したいと考えてくださっている方向けに、必要な情報にアクセスできるLINE Botを作ろうと思い取り組んでいる経過です。 環境・利用API node v16.10.0 Visual Studio Code 1.60.2 axios 0.22.0 ngrok 2.3.40 お薬APIは有料のため断念 API連携の方法を学び、在宅医療で役にたちAPIで持って来れる情報に何があるかを考えました。 当初、薬の情報がAPIでもってこれれば、お薬の表面に書いてある文字や、色形で薬が何の薬か判断できるようなり、治療の経過で「血圧の薬だけ明日から抜く」などを患者さんご家族でもやりやすくなるかと考えましたが、薬の情報を使えるAPIは有料のものばかりのようで断念(いいAPIがあれば教えてください)。 お天気APIとの連携 次に考えたのが、お天気APIとの連携です。 病院で入院や外来を担当していたときはあまり天気を気にしていませんでしたが、在宅医療に携わるようになって晴れか雨かはもちろん、夏の暑さや冬の暑さが自分自身にダイレクトに関わるようになりました。 また、患者さんも引きこもりがちな方が多いため散歩を勧めるけど暑すぎたり寒すぎたりする日は難しかったり、特に高齢者は暑い寒いを感じる体のセンサーが弱っていて暑い中でもクーラーをつけずに過ごしすぐに熱中症になる方がいたりと、お天気情報の重要性を感じています。 そこで、天気の情報をAPIでもってきて、その日の天気に合わせてメッセージを送れるようにならないかと考えた次第です。 OpneWeatherMapを使う 天気APIは無料のものがいくつかありますが、今回は最も代表的なOpenWeatherMapを使いました。 使用するのにAPIキーを発行する必要がありますが、これについてはこちらのサイトを参照しました。 最終的にはLINE Botに乗せることが目標ですが、何せ初心者なのでまずはOpenWeatherMapから必要な情報を抜き出せるかを試してみました。 その日の天気や気温に合わせてコメントを出す http://api.openweathermap.org/data/2.5/weather?q=fukuoka&appid={APIアクセスキー}&lang=ja&units=metric 発行したAPIアクセスキーを該当部に入れ、当院は福岡にあるので場所はfukuokaとして指定、摂氏で温度が欲しいので最後をmetricとしています。 すると、 { coord: { lon: 130.4181, lat: 33.6064 }, weather: [ { id: 803, main: "Clouds", description: "曇りがち", icon: "04n" } ], base: "stations", main: { temp: 23.84, feels_like: 23.87, temp_min: 23.44, temp_max: 24.01, pressure: 1020, humidity: 61 }, visibility: 10000, wind: { speed: 3.6, deg: 330 }, clouds: { all: 75 }, dt: 1634121790, sys: { type: 1, id: 7998, country: "JP", sunrise: 1634073664, sunset: 1634114871 }, timezone: 32400, id: 1863967, name: "福岡市", cod: 200 } と、JSONで情報が返ってきます。 この情報を使って、晴れの日には「いいお天気ですよ」、曇りの日には「お散歩はいかがですか」、雨の日には「お出かけの際は傘をお持ちください」と表示し、さらに最高気温が30度以上の場合は「熱中症にご注意ください」、32度以上の場合は「クーラーを入れてください」と表示することに。 コードこちら // axiosライブラリを呼び出す const axios = require('axios'); // 実際にデータを取得する getRequest 関数 async function getRequest() { let response; try { response = await axios.get('http://api.openweathermap.org/data/2.5/weather?q=fukuoka&appid=42d222cdac5c766d1af96314e63f948d&lang=ja&units=metric'); if (response.data.weather[0].main === 'Clouds'){ console.log('お散歩はいかがですか'); } if (response.data.weather[0].main === 'Rain'){ console.log('お出かけの際は傘をお持ちください'); } if (response.data.weather[0].main === 'Clear'){ console.log('いいお天気ですよ'); } if (response.data.main.temp_max > 30){ console.log('熱中症にご注意ください'); } if (response.data.main.temp_max > 32){ console.log('クーラーを入れてください'); } else{ console.log('以上です'); } } catch (error) { console.error(error); } } // getRequest を呼び出してデータを読み込む getRequest(); これで、その日の福岡の天気や気温に合わせた情報が返ってくるようになりました。 LINE Botと連携する 次に、これをLINE Botと連携します。 せっかくなので、上記で試したif文をつかって天気情報によってLINEで返信するものを作りたかったのですが、何度やってもエラーが出てうまくいかず、、 今の力の限界ということで、シンプルに天気を返してくれるものを作りました。 'use strict'; // ######################################## // 初期設定など // ######################################## // パッケージを使用します const express = require('express'); const line = require('@line/bot-sdk'); const axios = require('axios'); // ローカル(自分のPC)でサーバーを公開するときのポート番号です const PORT = process.env.PORT || 3000; // Messaging APIで利用するクレデンシャル(秘匿情報)です。 const config = { channelSecret: '作成したBotのチャネルシークレット', channelAccessToken: '作成したBotのチャネルアクセストークン' }; // ########## ▼▼▼ サンプル関数 ▼▼▼ ########## const sampleFunction = async (event) => { const userText = event.message.text; let replyText = ''; // 部分一致1(「範囲」という文字が1ヶ所でも含まれていたら反応) if (userText.indexOf('範囲') > -1) { replyText = 'https://taro-cl.com/for_patients#b'; } // 部分一致2(「費用」という単語が1ヶ所でも含まれていたら反応) if (userText.indexOf('費用') > -1) { replyText = 'https://taro-cl.com/q_and_a'; } // 部分一致3(「天気」という単語が1ヶ所でも含まれていたら反応) if (userText.indexOf('天気') > -1) { let response = await axios.get('http://api.openweathermap.org/data/2.5/weather?q=fukuoka&appid=42d222cdac5c766d1af96314e63f948d&lang=ja&units=metric'); console.log(response.data.weather[0].main); replyText = '「今日の天気は' + response.data.weather[0].description + 'です」'; } // この時点でどの条件にも引っかかってない(replyTextが空文字列のまま)なら相槌をうっておく if (replyText === '') { replyText = '当院にお問い合わせください(092-410-3333)'; } return client.replyMessage(event.replyToken, { type: 'text', text: replyText }); }; // ########## ▲▲▲ サンプル関数 ▲▲▲ ########## // ######################################## // 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 sampleFunction(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サーバーを実行中です…`); 天気情報に加えて、尋ねられることが多い「費用」と「訪問範囲」について、それぞれ「費用」「範囲」という言葉が含まれる送信があれば、それぞれを説明しているホームページ部分のリンクを返信するようにしました。 実際に作動している様子がこちらです。 https://youtu.be/FobBOvWumrU なんとか動いてくれました。 自分の学びに合わせてLINE Botもアップデートしていきたいと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

長崎から、旅行できた友達の為に。ディズニーのお勧めアトラクションを教えてくれるLineBotを作ってみた!

プログラミング 長崎県民に、ディズニーのお勧めアトラクションを伝えたい!! 私は、長崎県出身で、東京に上京してきて13年目。 東京にきて、ビックリした事の一つに、東京都民は、ディズニーランド、ディズニーシーのアトラクションにみんな詳しい事。 平然と、ビックサンダーマウンテン、センターオブジアース、スプラッシュマウンテン、タワーオブテラーなど言われるが、 田舎者の私には、全然分からなかった事を今でも覚えております。 旅行できた地元の友達達からもよくディズニーのお勧めの場所やアトラクション、宿泊先など、よく聞かれます。そんな友達達の為に、今回ディズニーリゾートのお勧めのアトラクションを教えてくれるLINEBotを作ってみました! 作成した仕組み ディズニーリゾートのお勧めアトラクションを教えてくれるLINEBot 開発環境 ・LINE公式アカウント開設 ・LINE Developersアカウント登録 ・Visual Studio Code ・ngrok ・LINE Bot 共通テンプレート テンプレートをもとに作成しました! サンプルコード (クリックで表示) 'use strict'; // ######################################## // 初期設定など // ######################################## // パッケージを使用します const express = require('express'); const line = require('@line/bot-sdk'); const axios = require('axios'); // ローカル(自分のPC)でサーバーを公開するときのポート番号です const PORT = process.env.PORT || 3000; // Messaging APIで利用するクレデンシャル(秘匿情報)です。 const config = { channelSecret: '作成したBotのチャネルシークレット', channelAccessToken: '作成したBotのチャネルアクセストークン' }; // ########## ▼▼▼ サンプル関数 ▼▼▼ ########## (この行をサンプル関数丸ごと全部と置き換えてね) // ########## ▲▲▲ サンプル関数 ▲▲▲ ########## // ######################################## // 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 sampleFunction(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サーバーを実行中です…`); 共通テンプレート
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

長崎県民の為に!ディズニーのお勧めアトラクションを教えてくれるLINEBotを作ってみた!

長崎県民に、ディズニーのお勧めアトラクションを伝えたい!! 私は、長崎県出身で、東京に上京してきて13年目。 東京にきて、ビックリした事の一つに、東京都民は、ディズニーランド、ディズニーシーのアトラクション事に妙に詳しいこと。 平然と、ビックサンダーマウンテン、センターオブジアース、スプラッシュマウンテン、タワーオブテラーなど言われるが、田舎者の私には、全然分からなかった事を今でも覚えております。 旅行できた地元の友達達からもよくディズニーのお勧めの場所やアトラクション、宿泊先など、よく聞かれます。そんな友達達の為に、今回ディズニーリゾートのお勧めのアトラクションを教えてくれるLINEBotを作ってみました! 作成した仕組み ディズニーリゾートのお勧めアトラクションを教えてくれるLINEBot 開発環境 ・LINE公式アカウント開設 ・LINE Developersアカウント登録 ・Visual Studio Code ・ngrok ・LINE Bot 共通テンプレート テンプレートをもとに作成しました! サンプルコード (クリックで表示) 'use strict'; // ######################################## // 初期設定など // ######################################## // パッケージを使用します const express = require('express'); const line = require('@line/bot-sdk'); const axios = require('axios'); // ローカル(自分のPC)でサーバーを公開するときのポート番号です const PORT = process.env.PORT || 3000; // Messaging APIで利用するクレデンシャル(秘匿情報)です。 const config = { channelSecret: '作成したBotのチャネルシークレット', channelAccessToken: '作成したBotのチャネルアクセストークン' }; // ########## ▼▼▼ サンプル関数 ▼▼▼ ########## (この行をサンプル関数丸ごと全部と置き換えてね) // ########## ▲▲▲ サンプル関数 ▲▲▲ ########## // ######################################## // 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 sampleFunction(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サーバーを実行中です…`); お勧めのアトラクションを教えてくれるAPI 「おすすめは?」と聞くと、おすすめのアトラクションをランダムに答えてくれます。 「遊びに行きたい」や「アトラクション何がいいかな」など、ある特定の単語を含むメッセージには乗り気ですが、それ以外は適当な相槌を返します。 サンプルコード (クリックで表示) const sampleFunction = async (event) => { const userText = event.message.text; let replyText = ''; // 部分一致1(「遊」という文字が1ヶ所でも含まれていたら反応) if (userText.indexOf('遊') > -1) { replyText = 'ディズニーリゾートへ行きましょう!'; } // 部分一致2(「アトラクション」という単語が1ヶ所でも含まれていたら反応) if (userText.indexOf('アトラクション') > -1) { replyText = 'アトラクションのことでしたら、ぜひ「おすすめは?」と聞いてみてください!'; } // 完全一致したらランダムに返信 if (userText === 'おすすめは?') { // アイスの配列 const attractions = ['ビッグサンダー・マウンテン', 'センター・オブ・ジ・アース', 'スペース・マウンテン', 'エレクトリック・レールウェイ', 'スプラッシュマウンテン', 'インディ・ジョーンズ・アドベンチャー', 'カリブの海賊', 'スポンサーラウンジ']; // アイスの種類数 const att_count = attractions.length; // 乱数(0以上1未満の小数)* 種類数 をして小数以下切り捨て const index = Math.floor(Math.random() * att_count); // インデックスを指定して特定のアイスを示す文字列を取り出す replyText = '「' + attractions[index] + '」がおすすめです?'; } // この時点でどの条件にも引っかかってない(replyTextが空文字列のまま)なら相槌をうっておく if (replyText === '') { replyText = 'そうですね〜'; } return client.replyMessage(event.replyToken, { type: 'text', text: replyText }); }; 今回出来なかったこと 企画案までは、出来たのですが、実機で試すまでが出来ませんでした。 また、お勧めのアトラクションまでしか制作する事が出来ませんでした。 次回は、宿泊施設やお勧めの場所も教えてくれるLINEBotを制作したいと考えております。 これまでの成果物 ■CodePen マスクチェッカ―!連携させるのが難しい!汗何とかできたが、まだまだ、、(;^ω^)#protoout #Java #nodered #lINEBot pic.twitter.com/CTLz8P2BJF— YE0905 (@EgashiraYosuke) August 9, 2021 ■LINE Botへ配信 LINE Botと連携#protoout pic.twitter.com/h2hDdoTrjp— YE0905 (@EgashiraYosuke) August 9, 2021 ■ドメイン検索LINEBot 動画 #protoout 中々苦戦してますが、日々成長出来て嬉しい!今週も頑張るぞ! pic.twitter.com/qJ6RF5mrA5— YE0905 (@EgashiraYosuke) August 2, 2021
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

初心者向けの記事って多すぎん??(JavaScript初心者向けQiitaAPIでLGTM数TOP10を出してみる)

はじめましての自己紹介 はじめまして!超ウルトラスーパー初心者のぜらちんです。 JavaScript?新しい紅茶?というくらいにチンプンカンプンな30オーバー限界ヲタク女が JavaScriptで何かを作り始めてみる、という記事をこれからいくつか投稿していこうと思います。 何を作ろうか まずはQiitaのAPIを使用して、(この言い回しがあっているかも分からない……。) 初心者が読むべき記事を抽出してみることにします。 そう。自分のために作るのです! Qiitaは記事が多すぎる……。初心者向けだけでも無数にある中から良さそうな記事だけ読みたいんじゃー! 何をもって良い記事とするか。そう。他者からの評価が多い記事だけを読むのです。 自分はJavaScriptを使用して挑戦するので、抽出する記事は「JavaScriptを学ぶ初心者向けの記事」にします。 作成するものの概要 ・QiitaAPIを使って、記事タイトル、本文、タグに「JavaScript」と「初心者」が含まれる記事を取得する。 ・2021年9月までの記事を取得することにする。(実行の度に結果がブレるため日付を区切る。) ・結果を手動集計しLGTM数で並び変える。(アナログ・・・!) 環境 Node v16.10.0 axios 0.22.0 完成コード XXXXXは発行されたアクセストークン const axios = require('axios'); //タグに「初心者」「JavaScript」どちらも設定されている記事 async function main() { for (page = 1;page<=100;page++){ let parm = "https://qiita.com/api/v2/items?page=" + page + "&per_page=100&query=JavaScript+" + encodeURIComponent("初心者") + "+created%3A" + encodeURIComponent("<2021-10"); let response = await axios.get(parm, { headers: { "Authorization": "Bearer XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" } }); //取得したデータ件数分タイトル、URL、LGTM数取得 for (let i = 0; i < response.data.length; i++) { var title_name = response["data"][i]["title"]; var sample = response["data"][i]["url"]; var cntlike = response["data"][i]["likes_count"]; console.log(title_name+"¥"+sample+"¥"+cntlike); } } } main(); コードはこのように記載しましたが、数が多すぎるのか途中でエラーになったので、10ずつ区切って実行し結果をExcelに貼り付けて手動で降順にしました。(圧倒的アナログ……!) 結果を「¥」で結び、Excel上でデータ分割しました。 (タイトルにカンマやスペースを入れいてる記事があったため区切り文字として設定できませんでした。) JavaScript初心者向けLGTM数TOP10(~2021年9月作成記事) 得られた結果からLGTM数のTOP10を発表します!! それぞれリンクも設定していますので飛んでみてください。 記事タイトル、本文、タグのいずれかに、「JavaScript」と「初心者」の2語が含まれています。 ※LGTM数は2021/10/13時点のものとなります。 No 記事タイトル LGTM数 1 AtCoder に登録したら次にやること ~ これだけ解けば十分闘える!過去問精選 10 問 ~ 6248 2 イマドキのJavaScriptの書き方2018 5554 3 良いコードの書き方 4363 4 すべての新米フロントエンドエンジニアに読んでほしい50の資料 3876 5 2020年のフロントエンドマスターになりたければこの9プロジェクトを作れ 3647 6 プログラミング勉強を加速させる7つの習慣 3379 7 トップデベロッパーになるために作成したいアプリ8選 3248 8 初心者歓迎!手と目で覚える正規表現入門・その1「さまざまな形式の電話番号を検索しよう」 3163 9 初心者プログラマが犯しがちな過ち25選 2492 10 【保存版・初心者向け】独学でAIエンジニアになりたい人向けのオススメの勉強方法 2444 考察 TOP10に記載させていただいた記事をすべて見てみました。 一字一句逃さず、とはいきませんが、全体をざっと見てLGTMを集める記事の共通点を考察してみました。 ● タイトルに数値が入っている 「過去問精選10門」「読んでほしい50の資料」「7つの習慣」「アプリ8選」 上記のようにタイトルに目を引く数字が入っています。 具体的な数字が書かれていると「これだけやればいいんだ!」「この数の分だけ覚えればいいんだ!」と思い、 初心者がとっつきやすくなるのかもしれません。 ● 長い 一部の記事を除いて、とにかく記事の内容が長い!一体何回スクロールしたことか! あまり長いと初心者の方は敬遠するんじゃないか?と思いましたが、 情報量が多ければ多いほどQiitaを利用する初心者には好まれるのかもしれません。 ● 図が豊富に組み込まれている 参考画像などの図が少なくとも3つ以上組み込まれている記事が多かったです。 中には動画の埋め込みもありました。 文字ばっかりになるよりは、図やイラスト、動画を入れることでより分かりやすくなっているようです。 ● 折りたたみを使用していない 中には、これだけ長い記事なら「折りたたみ」を使用すればいいのに、と思う記事もありました。 が、気づきました。折りたたまれた記事は読まれない! スクロールの途中でマウスに置く指の位置を変えて折りたたみを開こうと思わないのです。 10個の記事を見ている自分がそうでした。 たくさんある記事を渡り歩いていく途中で折りたたみは見逃されてしまうのです。 どんなに長くなっても折りたたみは使わないほうがいいようです。 (時と場合によると思いますが……。) ● おすすめの資料、テキスト、参考書が紹介されている 表紙の画像を添えておすすめの本を紹介している記事がいくつかありました。 Qiitaやnoteの記事、YouTubeの動画などインターネット上にはたくさんの初心者向けコンテンツが溢れていますが、 プロが執筆し、校正、校閲を通った書籍を初心者が求めるのは今も昔も変わらないようです。 ● 形容詞が多く使われている 最後にTOP10の記事本文をテキストマイニングツールにかけてみました。 使用したツールはこちら→「userlocal テキストマイニングツール」 結果は折りたたみの中に画像として貼り付けています。 (TOP10に倣わず折りたたみました。) 各記事で取り上げている内容が異なるため、出現頻度の多い単語には着目せず画像の黄緑色文字(形容詞)に注目しました。 「良い」「素晴らしい」「難しい」「早い」「新しい」「多い」「優しい」「短い」「長い」 などなど、様々な形容詞が各記事で使われていることがわかりました。 ほとんどの記事で、動詞よりも多用されていると言ってもいいほどです。 誰もが想像しやすく、分かりやすい内容となるように形容詞を使うことで、 戸惑う初心者の心に寄り添う内容となり、結果多くのLGTMが得られたのかもしれません。 TOP10記事本文のテキストマイニング ▼AtCoder に登録したら次にやること ~ これだけ解けば十分闘える!過去問精選 10 問 ~ ▼イマドキのJavaScriptの書き方2018 ▼良いコードの書き方 ▼すべての新米フロントエンドエンジニアに読んでほしい50の資料 ▼2020年のフロントエンドマスターになりたければこの9プロジェクトを作れ ▼プログラミング勉強を加速させる7つの習慣 ▼トップデベロッパーになるために作成したいアプリ8選 ▼初心者歓迎!手と目で覚える正規表現入門・その1「さまざまな形式の電話番号を検索しよう」 ▼初心者プログラマが犯しがちな過ち25選 ▼【保存版・初心者向け】独学でAIエンジニアになりたい人向けのオススメの勉強方法 初心者向けの記事を書き、多くのLGTMをもらうためにはこれらのことを念頭に置いて執筆してみるとよいでしょう。 と言いましたが、書いてみた結果うまくいかなくても投稿主は責任を取れませんのでご了承ください……。 感想 最後は手動でゴリ押ししたところもあったので、そこが悔やまれました。 情報を取れるだけとってExcelに貼り付けてソートして……と不毛な作業をしていたように思います。 終わり良ければ総て良し!なのかもしれませんが、なんだかスッキリしません。 ですが、今まで使ってこなかった脳みそを使えたので良い勉強になりました! 私のこの記事も抽出期間を広げれば対象に入ってきますが、上位10記事くらいLGTMを付けられる日はおそらく来ないので、今後記事を更新することはなさそうです。 参考にした記事は一番下にまとめていますのでご参照ください。 紆余曲折 Visual Studio Codeを使用してJavaScriptでやりました。 初心者の勉強用投稿なのでやってみてダメだったコードも書いていきます。 ここからはとにかく長くなってしまったので、お時間のある方のみどうぞ……。 初心者向けの記事数を得る まずは、タグに「初心者」と設定されている記事数を取得してみます。 const axios = require('axios'); //タグが「初心者」である記事 async function main() { let response = await axios.get('https://qiita.com/api/v2/tags/' + encodeURIComponent('初心者')); console.log(response.data); } main(); こんな結果が得られました。 { followers_count: 5331, icon_url: 'https://s3-ap-northeast-1.amazonaws.com/qiita-tag-image/2383c6450ddfcedeb18a168a1a13023ee25687c5/medium.jpg?1611635876', id: '初心者', items_count: 19206 } 記事数が19206件もある! こんなに読み切れない!! 初心者が入口で躓くのは参考資料の多さが原因の一つだと私は思っています。 フォロー数は5331。 そりゃ、継続していけば初心者ではなくなるからこれは納得。 閑話休題。 私が知りたいのはJavaScriptに関する初心者向け記事なので数を絞ってみます。 JavaScriptの初心者向け記事を取得する 初心者タグが設定されている、かつ、JavaScriptタグも設定されている記事に絞ればいいのだから、 タグのAND検索でいけそうです。 検索窓に「JavaScript 初心者」と入れるイメージです。 const axios = require('axios'); //タグに「初心者」「JavaScript」どちらも設定されている記事 async function main() { let response = await axios.get('https://qiita.com/api/v2/tags/' + encodeURIComponent('初心者') + '&tags/' + + encodeURIComponent('javascript')); console.log(response.data); } main(); 結果は……言うまでもなく失敗です。 そもそも「JavaScript」は日本語じゃないんだからエンコードする必要がないです。 投稿主は超のつく初心者なので、どうか暖かい目で見てください……。(褒めて伸びるタイプです。) ここでチームに相談!15分調べてわからなかったら聞くに限ります! 調べても分からなかったんだし! 教えてもらった内容で再挑戦します。 const axios = require('axios'); //タグに「初心者」「JavaScript」どちらも設定されている記事 async function main() { let response = await axios.get('https://qiita.com/api/v2/items?query=tag%3AJavaScript+tag%3A' + encodeURIComponent('初心者') ); console.log(response.data); } main(); エラーは出なくなりました。 成功ですが、なんだか出力された内容が少ないように見えます。 気になるので取得できた記事数を確認してみます。 取得した記事件数を確認 「items_count」を追加して取得した記事件数が確認できるか試してみます。 const axios = require('axios'); //タグに「初心者」「JavaScript」どちらも設定されている記事 async function main() { let response = await axios.get('https://qiita.com/api/v2/items?query=tag%3AJavaScript+tag%3A' + encodeURIComponent('初心者') ); console.log(response.data.items_count); } main(); 結果は「undefined」という表示。 「undefined」は「未定義」という意味らしい……。 んんーー??どういうことだー?? おそらく「値がない」ということなんだろうと思います。 この方法ではダメなので他の方法を探します。 色んな記事を見てみると「length」で数が取れそうです! 早速書き書き……。 const axios = require('axios'); //タグに「初心者」「JavaScript」どちらも設定されている記事 async function main() { let response = await axios.get('https://qiita.com/api/v2/items?query=tag%3AJavaScript+tag%3A' + encodeURIComponent('初心者') ); //取得した記事数 console.log(response.data.length); } main(); 結果は「20」と出ました! ……いや!そんなわけない!初心者向けのjavascriptの記事が20件なわけがない!! またしても問題にぶちあたりました……。 記事をさらに取得する Qiita API v2(ページネーション)を調べてみると以下の記載がありました。 per_pageの初期値は20、per_pageの最大値は100に設定されています。 「per_page」をいじる必要がありそうです。 「per_page」の最大値を設定してリトライしてみます。 const axios = require('axios'); //タグに「初心者」「JavaScript」どちらも設定されている記事 async function main() { let response = await axios.get('https://qiita.com/api/v2/items?per_page=100&query=tag%3AJavaScript+tag%3A' + encodeURIComponent('初心者') ); //取得した記事数 console.log(response.data.length); } main(); 結果は『100』と表示されました!成功です! 最大値に100を設定しているから当たり前ですね……。 そして条件にあてはまる記事が100件なわけないです……。 次はすべての記事を取得する必要があります。 すべての記事を取得する 2021/10/11現在、Qiitaの検索窓で「JavaScript 初心者」と入力すると、すべての検索結果は「7276」件となりました。 「page」の最大値も設定して取得できる記事の数が増えるか試してみます。 const axios = require('axios'); //タグに「初心者」「JavaScript」どちらも設定されている記事 async function main() { let response = await axios.get('https://qiita.com/api/v2/items?per_page=100&page=100&query=tag%3AJavaScript+tag%3A' + encodeURIComponent('初心者') ); //取得した記事数 console.log(response.data.length); } main(); 結果は『0』 ええ!なんで!?これは再度調査が必要そうです……。 チームからの助言をまるっと引用 Qiita APIでは検索結果が複数返ってくるようなAPIに対して、それを一度に返すことはせずに、ページという単位で分割して返すようになっています。 この時に使うオプションがper_pageとpageで、per_pageで1ページ辺りに幾つの検索結果を含むかを指定でき、pageでその中の何ページ目を取得するかを指定します。 per_page=100&page=100 という記載をした場合、検索結果を100個ずつに区切って、その中の100番目のページを取得する(=9901番目~10000番目の結果を取得する)という意味になります。 なので、検索結果が9901件以上無いと結果は0になります。 per_page=100 という記載の場合は、検索結果は上と同様に100個ずつに区切られ、その中の1番目のページを取得する(=1番目~100番目の結果を取得する)という意味になります。 ※これはpageというパラメータを指定しなかった場合の初期値が1だからです。ちなみに、per_pageの初期値は20です。 なので、この場合は検索結果が100件以上あれば取得できるデータの個数は100になります。 APIではレスポンスヘッダーというところに要素の合計数が出力されます。 レスポンスのボディ(データ本体)ではなくヘッダーの情報を取りたいときはaxiosで取得した結果に対してheadersという要素にアクセスすると取り出せます。 console.log(response.headers); としていただけるとヘッダーの中身が見れますのでtotal-countという項目を探してみてください。 いただいた助言を元に以下を実行してみます。 const axios = require('axios'); //タグに「初心者」「JavaScript」どちらも設定されている記事 async function main() { let response = await axios.get('https://qiita.com/api/v2/items?query=tag%3AJavaScript+tag%3A' + encodeURIComponent('初心者') ); //取得した記事数 console.log(response.headers); } main(); 得られた結果の中に'total-count': '1576',とありました。 ふむ……。1576件……。思ったより少ないな……。 Qiitaの検索窓で検索した結果は7276件だったので、検索対象をタグではなく、タイトルと本文を含めたすべてにしてみます。 const axios = require('axios'); //タグに「初心者」「JavaScript」どちらも設定されている記事 async function main() { let response = await axios.get('https://qiita.com/api/v2/items?query=JavaScript+' + encodeURIComponent('初心者') ); //取得した記事数 console.log(response.headers); } main(); 結果は'total-count': '7280',(2021/10/13時点) うん!いい感じです! ここから全記事のLGTM数をとり、降順にして上位10個の記事だけを取得します。 記事全文だと長すぎるのでタイトルとURLだけ取得し、末尾にLGTM数も取得するようにしてみます。 for (page = 1;page<=100;page++){ let parm = "https://qiita.com/api/v2/items?page=" + page + "&per_page=100&query=JavaScript+" + encodeURIComponent("初心者") + "+created%3A" + encodeURIComponent("<2021-10"); let response = await axios.get(parm, { headers: { "Authorization": "Bearer a57b66c2c1c2a8a9bb53be4879f6ecf5ab28c5a4" } }); 実行中にまたもやエラー発生! per_page=100&page=100 だと途中でエラーになったので、 per_page=100&page=10 で数回実行し、結果をExcelに貼り付けていくことにします。 本当はコード内だけで降順にしてTOP10の記事だけ抽出、としたかったのですが力量不足でした……。 とりあえずは形にすることができたので自分で自分を褒めてあげたいです!(懐) が、また途中で謎のエラーに引っ掛かりました。 頼れるチームメンバーに相談し、アクセストークンなるものを設定してみました。 ※以下のコードは一部抜粋しています。XXXXX~は発行したアクセストークンを設定。 ※アクセストークンの設定方法は参考記事を参照。 let parm = "https://qiita.com/api/v2/items?page=" + page + "&per_page=100&query=JavaScript+" + encodeURIComponent("初心者") + "+created%3A" + encodeURIComponent("<2021-10"); let response = await axios.get(parm, { headers: { "Authorization": "Bearer XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" } }); これで何とかすべての記事を取得することができました。 最終的に完成したコードは「完成コード」のとおりです。 参考記事 以下の記事を参考にしました。 ▼私にはMarkdownチートシートよりもわかりやすかったです。 Qiita Markdown 書き方 まとめ ▼コメント数を取得するあたりなどまるっとパクった参考にしました。 結局Qiita記事ってどれぐらい書けばいいのさ ▼作成日を指定して取得する箇所を参考にしました。 QiitaAPIで2020年投稿のストック数が多い記事のタグ情報を調べてみた ▼記事をたくさん取得する方法を参考にしました。 「テレワーク」と「新型コロナ」には相関性があるのか確かめてみた。 ▼アクセストークンの設定について参考にしました。 よそ様の情報を簡単に参照できるWEBAPIが本当に簡単なのか体験してみた。 ▼なんやかんや参考にしました。(説明めんどくさくなるな。) Qiita API v2(ページネーション)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

初心者向けの記事って多すぎん??(javascript初心者向けQiitaAPIでLGTM数TOP10を出してみる)

はじめましての自己紹介 はじめまして!超ウルトラスーパー初心者のぜらちんです。 JavaScript?新しい紅茶?というくらいにチンプンカンプンな30オーバー限界ヲタク女が JavaScriptで何かを作り始めてみる、という記事をこれからいくつか投稿していこうと思います。 何を作ろうか まずはQiitaのAPIを使用して、(この言い回しがあっているかも分からない……。) 初心者が読むべき記事を抽出してみることにします。 そう。自分のために作るのです! Qiitaは記事が多すぎる……。初心者向けだけでも無数にある中から良さそうな記事だけ読みたいんじゃー! 何をもって良い記事とするか。そう。他者からの評価が多い記事だけを読むのです。 作成するものの概要 ・QiitaAPIを使って、記事タイトル、本文、タグに「JavaScript」と「初心者」が含まれる記事を取得する。 ・2021年9月までの記事を取得することにする。(実行の度に結果がブレるため日付を区切る。) ・結果を手動集計しLGTM数で並び変える。(アナログ・・・!) 環境 Node v16.10.0 axios 0.22.0 完成コード XXXXXは発行されたアクセストークン const axios = require('axios'); //タグに「初心者」「JavaScript」どちらも設定されている記事 async function main() { for (page = 1;page<=100;page++){ let parm = "https://qiita.com/api/v2/items?page=" + page + "&per_page=100&query=JavaScript+" + encodeURIComponent("初心者") + "+created%3A" + encodeURIComponent("<2021-10"); let response = await axios.get(parm, { headers: { "Authorization": "Bearer XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" } }); //取得したデータ件数分タイトル、URL、LGTM数取得 for (let i = 0; i < response.data.length; i++) { var title_name = response["data"][i]["title"]; var sample = response["data"][i]["url"]; var cntlike = response["data"][i]["likes_count"]; console.log(title_name+"¥"+sample+"¥"+cntlike); } } } main(); コードはこのように記載しましたが、数が多すぎるのか途中でエラーになったので、10ずつ区切って実行し結果をExcelに貼り付けて手動で降順にしました。(圧倒的アナログ……!) 結果を「¥」で結び、Excel上でデータ分割しました。 (タイトルにカンマやスペースを入れいてる記事があったため区切り文字として設定できませんでした。) javascript初心者向けLGTM数TOP10(~2021年9月作成記事) 得られた結果からLGTM数のTOP10を発表します!! それぞれリンクも設定していますので飛んでみてください。 記事タイトル、本文、タグのいずれかに、「JavaScript」と「初心者」の2語が含まれています。 ※LGTM数は2021/10/13時点のものとなります。 No 記事タイトル LGTM数 1 AtCoder に登録したら次にやること ~ これだけ解けば十分闘える!過去問精選 10 問 ~ 6248 2 イマドキのJavaScriptの書き方2018 5554 3 良いコードの書き方 4363 4 すべての新米フロントエンドエンジニアに読んでほしい50の資料 3876 5 2020年のフロントエンドマスターになりたければこの9プロジェクトを作れ 3647 6 プログラミング勉強を加速させる7つの習慣 3379 7 トップデベロッパーになるために作成したいアプリ8選 3248 8 初心者歓迎!手と目で覚える正規表現入門・その1「さまざまな形式の電話番号を検索しよう」 3163 9 初心者プログラマが犯しがちな過ち25選 2492 10 【保存版・初心者向け】独学でAIエンジニアになりたい人向けのオススメの勉強方法 2444 考察 なんとなくですが、初心者向けの良い記事が集まったように見えます。 ただ情報が古いものもありそうなので、累積数でランキングするのはあまりよくないのかな、と思いました。 しかし1位の方のLGTM数はすごいなぁ。 感想 最後は手動でゴリ押ししたところもあったので、そこが悔やまれました。 情報を取れるだけとってExcelに貼り付けてソートして……と不毛な作業をしていたように思います。 終わり良ければ総て良し!なのかもしれませんが、なんだかスッキリしません。 ですが、今まで使ってこなかった脳みそを使えたので良い勉強になりました! 私のこの記事も抽出期間を広げれば対象に入ってきますが、上位10記事くらいLGTMを付けられる日はおそらく来ないので、今後記事を更新することはなさそうです。 参考にした記事は一番下にまとめていますのでご参照ください。 紆余曲折 Visual Studio Codeを使用してJavaScriptでやりました。 初心者の勉強用投稿なのでやってみてダメだったコードも書いていきます。 ここからはとにかく長くなってしまったので、お時間のある方のみどうぞ……。 初心者向けの記事数を得る まずは、タグに「初心者」と設定されている記事数を取得してみます。 const axios = require('axios'); //タグが「初心者」である記事 async function main() { let response = await axios.get('https://qiita.com/api/v2/tags/' + encodeURIComponent('初心者')); console.log(response.data); } main(); こんな結果が得られました。 { followers_count: 5331, icon_url: 'https://s3-ap-northeast-1.amazonaws.com/qiita-tag-image/2383c6450ddfcedeb18a168a1a13023ee25687c5/medium.jpg?1611635876', id: '初心者', items_count: 19206 } 記事数が19206件もある! こんなに読み切れない!! 初心者が入口で躓くのは参考資料の多さが原因の一つだと私は思っています。 フォロー数は5331。 そりゃ、継続していけば初心者ではなくなるからこれは納得。 閑話休題。 私が知りたいのはJavaScriptに関する初心者向け記事なので数を絞ってみます。 javascriptの初心者向け記事を取得する 初心者タグが設定されている、かつ、javascriptタグも設定されている記事に絞ればいいのだから、 タグのAND検索でいけそうです。 検索窓に「javascript 初心者」と入れるイメージです。 const axios = require('axios'); //タグに「初心者」「JavaScript」どちらも設定されている記事 async function main() { let response = await axios.get('https://qiita.com/api/v2/tags/' + encodeURIComponent('初心者') + '&tags/' + + encodeURIComponent('javascript')); console.log(response.data); } main(); 結果は……言うまでもなく失敗です。 そもそも「JavaScript」は日本語じゃないんだからエンコードする必要がないです。 投稿主は超のつく初心者なので、どうか暖かい目で見てください……。(褒めて伸びるタイプです。) ここでチームに相談!15分調べてわからなかったら聞くに限ります! 調べても分からなかったんだし! 教えてもらった内容で再挑戦します。 const axios = require('axios'); //タグに「初心者」「javascript」どちらも設定されている記事 async function main() { let response = await axios.get('https://qiita.com/api/v2/items?query=tag%3AJavaScript+tag%3A' + encodeURIComponent('初心者') ); console.log(response.data); } main(); エラーは出なくなりました。 成功ですが、なんだか出力された内容が少ないように見えます。 気になるので取得できた記事数を確認してみます。 取得した記事件数を確認 「items_count」を追加して取得した記事件数が確認できるか試してみます。 const axios = require('axios'); //タグに「初心者」「javascript」どちらも設定されている記事 async function main() { let response = await axios.get('https://qiita.com/api/v2/items?query=tag%3AJavaScript+tag%3A' + encodeURIComponent('初心者') ); console.log(response.data.items_count); } main(); 結果は「undefined」という表示。 「undefined」は「未定義」という意味らしい……。 んんーー??どういうことだー?? おそらく「値がない」ということなんだろうと思います。 この方法ではダメなので他の方法を探します。 色んな記事を見てみると「length」で数が取れそうです! 早速書き書き……。 const axios = require('axios'); //タグに「初心者」「javascript」どちらも設定されている記事 async function main() { let response = await axios.get('https://qiita.com/api/v2/items?query=tag%3AJavaScript+tag%3A' + encodeURIComponent('初心者') ); //取得した記事数 console.log(response.data.length); } main(); 結果は「20」と出ました! ……いや!そんなわけない!初心者向けのjavascriptの記事が20件なわけがない!! またしても問題にぶちあたりました……。 記事をさらに取得する Qiita API v2(ページネーション)を調べてみると以下の記載がありました。 per_pageの初期値は20、per_pageの最大値は100に設定されています。 「per_page」をいじる必要がありそうです。 「per_page」の最大値を設定してリトライしてみます。 const axios = require('axios'); //タグに「初心者」「javascript」どちらも設定されている記事 async function main() { let response = await axios.get('https://qiita.com/api/v2/items?per_page=100&query=tag%3AJavaScript+tag%3A' + encodeURIComponent('初心者') ); //取得した記事数 console.log(response.data.length); } main(); 結果は『100』と表示されました!成功です! 最大値に100を設定しているから当たり前ですね……。 そして条件にあてはまる記事が100件なわけないです……。 次はすべての記事を取得する必要があります。 すべての記事を取得する 2021/10/11現在、Qiitaの検索窓で「javascript 初心者」と入力すると、すべての検索結果は「7276」件となりました。 「page」の最大値も設定して取得できる記事の数が増えるか試してみます。 const axios = require('axios'); //タグに「初心者」「javascript」どちらも設定されている記事 async function main() { let response = await axios.get('https://qiita.com/api/v2/items?per_page=100&page=100&query=tag%3AJavaScript+tag%3A' + encodeURIComponent('初心者') ); //取得した記事数 console.log(response.data.length); } main(); 結果は『0』 ええ!なんで!?これは再度調査が必要そうです……。 チームからの助言をまるっと引用 Qiita APIでは検索結果が複数返ってくるようなAPIに対して、それを一度に返すことはせずに、ページという単位で分割して返すようになっています。 この時に使うオプションがper_pageとpageで、per_pageで1ページ辺りに幾つの検索結果を含むかを指定でき、pageでその中の何ページ目を取得するかを指定します。 per_page=100&page=100 という記載をした場合、検索結果を100個ずつに区切って、その中の100番目のページを取得する(=9901番目~10000番目の結果を取得する)という意味になります。 なので、検索結果が9901件以上無いと結果は0になります。 per_page=100 という記載の場合は、検索結果は上と同様に100個ずつに区切られ、その中の1番目のページを取得する(=1番目~100番目の結果を取得する)という意味になります。 ※これはpageというパラメータを指定しなかった場合の初期値が1だからです。ちなみに、per_pageの初期値は20です。 なので、この場合は検索結果が100件以上あれば取得できるデータの個数は100になります。 APIではレスポンスヘッダーというところに要素の合計数が出力されます。 レスポンスのボディ(データ本体)ではなくヘッダーの情報を取りたいときはaxiosで取得した結果に対してheadersという要素にアクセスすると取り出せます。 console.log(response.headers); としていただけるとヘッダーの中身が見れますのでtotal-countという項目を探してみてください。 いただいた助言を元に以下を実行してみます。 const axios = require('axios'); //タグに「初心者」「javascript」どちらも設定されている記事 async function main() { let response = await axios.get('https://qiita.com/api/v2/items?query=tag%3AJavaScript+tag%3A' + encodeURIComponent('初心者') ); //取得した記事数 console.log(response.headers); } main(); 得られた結果の中に『'total-count': '1576',』とありました。 ふむ……。1576件……。思ったより少ないな……。 Qiitaの検索窓で検索した結果は7276件だったので、検索対象をタグではなく、タイトルと本文を含めたすべてにしてみます。 const axios = require('axios'); //タグに「初心者」「JavaScript」どちらも設定されている記事 async function main() { let response = await axios.get('https://qiita.com/api/v2/items?query=JavaScript+' + encodeURIComponent('初心者') ); //取得した記事数 console.log(response.headers); } main(); 結果は『'total-count': '7280',』(2021/10/13時点) うん!いい感じです! ここから全記事のLGTM数をとり、降順にして上位10個の記事だけを取得します。 記事全文だと長すぎるのでタイトルとURLだけ取得し、末尾にLGTM数も取得するようにしてみます。 for (page = 1;page<=100;page++){ let parm = "https://qiita.com/api/v2/items?page=" + page + "&per_page=100&query=JavaScript+" + encodeURIComponent("初心者") + "+created%3A" + encodeURIComponent("<2021-10"); let response = await axios.get(parm, { headers: { "Authorization": "Bearer a57b66c2c1c2a8a9bb53be4879f6ecf5ab28c5a4" } }); 実行中にまたもやエラー発生! per_page=100&page=100 だと途中でエラーになったので、 per_page=100&page=10 で数回実行し、結果をExcelに貼り付けていくことにします。 本当はコード内だけで降順にしてTOP10の記事だけ抽出、としたかったのですが力量不足でした……。 とりあえずは形にすることができたので自分で自分を褒めてあげたいです!(懐) が、また途中で謎のエラーに引っ掛かりました。 頼れるチームメンバーに相談し、アクセストークンなるものを設定してみました。 ※以下のコードは一部抜粋しています。XXXXX~は発行したアクセストークンを設定。 ※アクセストークンの設定方法は参考記事を参照。 let parm = "https://qiita.com/api/v2/items?page=" + page + "&per_page=100&query=JavaScript+" + encodeURIComponent("初心者") + "+created%3A" + encodeURIComponent("<2021-10"); let response = await axios.get(parm, { headers: { "Authorization": "Bearer XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" } }); これで何とかすべての記事を取得することができました。 最終的に完成したコードは「完成コード」のとおりです。 参考記事 以下の記事を参考にしました。 ▼私にはMarkdownチートシートよりもわかりやすかったです。 Qiita Markdown 書き方 まとめ ▼コメント数を取得するあたりなどまるっとパクった参考にしました。 結局Qiita記事ってどれぐらい書けばいいのさ ▼作成日を指定して取得する箇所を参考にしました。 QiitaAPIで2020年投稿のストック数が多い記事のタグ情報を調べてみた ▼記事をたくさん取得する方法を参考にしました。 「テレワーク」と「新型コロナ」には相関性があるのか確かめてみた。 ▼アクセストークンの設定について参考にしました。 よそ様の情報を簡単に参照できるWEBAPIが本当に簡単なのか体験してみた。 ▼なんやかんや参考にしました。(説明めんどくさくなるな。) Qiita API v2(ページネーション)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

いまさらながらNode.jsとLINE Messaging APIを使って簡単なLINEBOT作ってみた(入門)

やりたいこと LINE上でメッセージを送信すると指定の応答をするBot作成。 1. LINE Developers まずはLINE developerというMessaging APIが使用できる開発者向けのサイトで準備をします。LINEアカウントが必要になりますので、持ってない方は先に作成しておきましょう。 ログイン まずはLINE Developersにアクセスし、ログイン >LINEアカウントでログインでログインページへ。 LINEアカウントに登録しているメールアドレスとパスワードを入力しログインすると認証コードが発行されるので、LINEアプリを立ち上げ該当コードを入力してください。 認証が成功したら developer name your email に任意の名前とメールアドレスを入力し、create my accountしましょう。 Provider作成 ログインができたら、Providerを作成します。 create new providerを押し、Provider nameに任意の名前を入力し、作成しましょう。 Channel作成 Providerの作成ができたら、次はChannelの作成をします。 ChannelのタイプはMessaging APIを選択してください。 ・Channel name ・Channel description ・Category ・Subcategory の4つを入力し、createします。 作成したChannelは以降のプロセスでも何度か訪れるので覚えておいてください。 2. Heroku Herokuは簡単に言うとWebサーバを提供しているプラットフォームになります。 簡単なアプリをアップロードする場合に使うことが多いです。 今回は無料の範囲で使用できます。制限や料金等の詳細はこちらの記事をご参考ください。 アカウント作成 Heroku公式にアクセスし、無料で新規登録してください。 Heroku CLI Herokuへのログイン操作などはCLI上でするので、HerokuをCLI上で使えるようにする必要があります。 The Heroku CLIにアクセスし、ご自身の環境に合わせてインストーラをダウンロードしてください。 バージョン確認 下記コマンドを実行して、バージョンが出力されたらOKです。 $ heroku -v 3. Node.js インストール Node.js公式にアクセスし、インストールしてください。LTSの方で大丈夫です。 バージョン確認 下記コマンドを実行して、バージョンが出力されたらOKです。 $ node -v バージョンが出力されない場合、node.exeが存在するフォルダパスを環境変数に設定しましょう。設定が終わったら、CLIを再起動し上記コマンドを実行してみてください。 4. Git インストール Gitダウンロード公式にアクセスし、ご自身の環境に合わせてインストールしてください。 バージョン確認 下記コマンドを実行して、バージョンが出力されたらOKです。 $ git --version 5. CLI操作 ここからは主にCLI操作をします。Windowsの場合はコマンドプロンプト/Power shell、Macの場合はターミナルを使用。 Herokuログイン Herokuにログインにするため、下記コマンドを実行します。 $ heroku login ブラウザが立ち上がるので、メールアドレスとパスワードを入力しログインしましょう。 ディレクトリ/フォルダ作成 アプリケーションを置くディレクトリ/フォルダを作成しておきます。 # 新しいディレクトリ/フォルダ作成 $ mkdir <任意のディレクトリ/フォルダ名> # 作成したディレクトリ/フォルダに移動 $ cd <上記ディレクトリ/フォルダ名> 以降のCLI操作は、作成したディレクトリ/フォルダ内で行います。 Gitリポジトリ gitを使ってHerokuにアップするので該当ディレクトリ/フォルダをリポジトリ化しておきます。 $ git init Heroku URL作成 下記コマンドを実行すると、https://{アプリ名}.herokuapp.com/のようなURLが作成されます。 作成されたURLはどこかにコピーしておきましょう。 $ heroku create <任意のアプリ名> Webhook URLを設定 ブラウザに戻ります。 LINE Developersで作成したChannelにアクセスし、 Messaging API設定のWebhook URLという項目に、生成したURLを設定します。 このとき、https://{アプリ名}.herokuapp.com/webhookのように生成されたURLの末尾にwebhookを付け加えておきましょう。 Channel access tokenのHeroku環境変数への設定 一番下にあるChannel access tokenをコピーします。 CLIに戻り、下記コマンドを実行してHeroku内の環境変数にLINE_ACCESS_TOKENとして設定しておきましょう。 $ heroku config:set LINE_ACCESS_TOKEN={コピーしたチャネルアクセストークンをペースト} package.json作成 CLIに戻り、下記コマンドを実行しましょう。 $ npm init -y 実行後、カレントディレクトリ内にpackage.jsonファイルが作成されていることを確認しましょう。 作成の確認が出来たら、エディタで当該ファイルを開き"start": "node index.js"を追加していきます。 ○変更前 package.json { "name": <ディレクトリ名>, "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC" } ○変更後 package.json { "name": <ディレクトリ名>, "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "start": "node index.js", "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC" } 変更が終わったら、CLIに戻ります。 expressインストール node.jsのwebフレームワークであるexpressを下記コマンドでインストールします。 $ npm install express --save 6. メインファイル このファイルを実行するとアプリが立ち上がります。 作成 CLIで作成する場合、下記コマンドで作成してください。 $ touch index.js Windowsではおそらくtouchコマンドは使えないのでエクスプローラだったり、エディタ上でファイルを作成しても大丈夫です。 編集 以下のように編集しましょう。 index.js // パッケージ取得 const https = require("https") const express = require("express") // PORTとTOKENは環境変数に設定しておき、そこから取得 const PORT = process.env.PORT || 3000 const TOKEN = process.env.LINE_ACCESS_TOKEN const app = express() // ミドルウェアの設定 app.use(express.json()) app.use(express.urlencoded({ extended: true })) // 「/」にGETリクエストがあった場合の処理 app.get("/", (req, res) => { res.sendStatus(200) }) // 「/webhook」にPOSTリクエストがあった場合の処理 app.post("/webhook", function(req, res) { res.send("HTTP POST request sent to the webhook URL!") // ユーザーがボットにメッセージを送った場合、返信メッセージを送る if (req.body.events[0].type === "message") { // 文字列化したメッセージデータ const dataString = JSON.stringify({ replyToken: req.body.events[0].replyToken, messages: [ { "type": "text", "text": "Hello, user" }, { "type": "text", "text": "May I help you?" } ] }) // リクエストヘッダー const headers = { "Content-Type": "application/json", "Authorization": "Bearer " + TOKEN } // リクエストに渡すオプション const webhookOptions = { "hostname": "api.line.me", "path": "/v2/bot/message/reply", "method": "POST", "headers": headers, "body": dataString } // リクエストの定義 const request = https.request(webhookOptions, (res) => { res.on("data", (d) => { process.stdout.write(d) }) }) // エラーをハンドル request.on("error", (err) => { console.error(err) }) // データを送信 request.write(dataString) request.end() } }) app.listen(PORT, () => { console.log(`Example app listening at http://localhost:${PORT}`) }) 7. Herokuにデプロイ CLIに戻り、下記3つのコマンドを実行すると、Herokuへのデプロイが完了します。 $ git add . $ git commit -m "First commit" $ git push heroku master 8. Botを動かしてみよう LINEに作成したBotを追加(友だち追加) LINE DevelopersのChannel上のBot basic IDやQR codeを使ってLINEにBotを追加できます。 メッセージを送信 何かしらメッセージを送信すると Hello, user May I help you? の2つのメッセージが返ってくるはずです。 なにも返ってこない場合はこれまでのプロセスと違うことをしている可能性がありますので、もう一度チェックしましょう。 なお、上記以外のメッセージが付随して返ってくる場合は、LINE DevelopersのChannelにて以下のような項目がありますので、それぞれDisableに設定するとOKです。 ・Allow bot to join group chats ・Auto-reply messages ・Greeting messages LINE Messaging APIの仕組みとしてはユーザーがメッセージを送信するとLINEサーバー上でWebhookが発生し、設定したWebhook URL(BOT側)にイベント内容をPOSTリクエストします。 今回の場合Webhook URLの向き先はindex.jsの/webhookになります。 POSTリクエストを受け取った/webhookはリクエストの内容からLINEにどのようなイベントが発生したか(どのようなメッセージがユーザーから送信されたか)がわかります。 そして、そのイベント内容によってどのようなメッセージを返信するかを定義し、LINEサーバーに返しています。 今回の場合、以下の部分でイベント内容を特定し、返信内容を定義しています。 index.js .... if (req.body.events[0].type === "message") { // 文字列化したメッセージデータ const dataString = JSON.stringify({ replyToken: req.body.events[0].replyToken, messages: [ { "type": "text", "text": "Hello, user" }, { "type": "text", "text": "May I help you?" } ] }) ...... } 返信メッセージを変更したい場合は"text"の値を変更します。 返信できるメッセージタイプはテキストだけでなく、スタンプや画像、動画等多数サポートしています。詳しくはこちらを参照してください。 変更を反映する場合は7. Herokuにデプロイを再度実行してください。 9. まとめ 非常に簡単なLINEBOTになりますが、環境構築に悩んでいた方は参考にしていただければと思います。 10. 参考記事
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

LINE Message API を活用して、ポケモン対戦がやりやすくなるツールを作成

前回初めて書いた記事は真面目に考察したので、今回は自分の趣味の一部を交えて、少し読みやすいテーマ・内容としてみました。 ポケモン対戦は覚えることが多い  ポケモン対戦をやったことある方は、この章については読み飛ばしていただいて問題ありません。  なぜそもそも、ポケモン対戦を題材としたのかということについてです。自分の趣味ということもありますが、最大の理由として、ポケモン対戦は覚えることが非常に多く、初心者の参入障壁が高いという問題点があると考えているためです。  現在、ポケモン対戦は毎年世界大会が実施され、国内でも新作が発売されると、10万人程度が参加するコンテンツとなりました。youtubeなどの動画サイトでも対戦の模様は動画として上がっており、もし興味が湧いたら検索してご覧いただきたいのですが、まあ覚えることが多い。 種族値・個体値・努力値(公式名称では無いです。) ポケモンの特性 技の効果 対戦でよく使われる育成方法、いわゆる型 などなど  初心者が負けて覚えるのは当然ですが、それでも少しでも勝つ喜びを味わってもらう補助ができないかと考え、ツールの作成に着手しました。 対戦中の負担を軽減する 対戦始めたばかりの方が、少しでも対戦しやすくなるツール 自分が対戦中にど忘れした際、簡単に確認できるツール この2点を意識して、表示する項目を選定しました。 今回は対戦の勝敗に直結すると考えている 特性 素早さ 慣れていてもど忘れしてしまう 威力が相手の体重に依存する技の威力 この3つを、まず簡単に調べることができるツールに決定。 さらに、対戦中は常に90秒という選択時間に追われることを考え、パッと入力してパッと答えが返ってくる上に扱いが簡単な、linebotをインターフェイスとして活用することとしました。 なぜ、素早さが対戦の勝敗に直結するかは、非常に長くなるので本記事では割愛します。 環境・利用API node v16.10.0 Visual Studio Code 1.60.2 axios 0.22.0 ngrok 2.3.40 PokeAPI https://pokeapi.co/ ポケモンのAPIとしては他にもありましたが、データの網羅性が高く、今後の機能拡張がしやすい点を考えて、PokeAPIを選択しました。 サンプルコード LINE Messaging APIとPokeAPI それぞれのコードを記載します。 LINE Messaging API / Axiosのコード 'use strict'; // ######################################## // 初期設定など // ######################################## // パッケージを使用します const express = require('express'); const line = require('@line/bot-sdk'); const axios = require('axios'); // ローカル(自分のPC)でサーバーを公開するときのポート番号です const PORT = process.env.PORT || 3000; // Messaging APIで利用するクレデンシャル(秘匿情報)です。 const config = { channelSecret: '作成したBotのチャネルシークレット', channelAccessToken: '作成したBotのチャネルアクセストークン' }; // ########## ▼▼▼ サンプル関数 ▼▼▼ ########## (この行をサンプル関数丸ごと全部と置き換えてね) // ########## ▲▲▲ サンプル関数 ▲▲▲ ########## // ######################################## // 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 sampleFunction(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サーバーを実行中です…`); PokeAPIによるデータ取得 const getPoke = async (userId, tag) => { let result = ''; try { // axiosでQiitaのAPIを叩きます const res = await axios.get('https://pokeapi.co/api/v2/pokemon/' + encodeURIComponent(tag)); const item = res.data; const speed = item.stats[5].base_stat; const weight = item.weight; let powerWeight = ''; if(weight < 90){ powerWeight = '20'; } else if(weight < 249){ powerWeight = '40'; } else if(weight < 499){ powerWeight = '60'; } else if(weight < 999){ powerWeight = '80'; } else if(weight < 1999){ powerWeight = '100'; } else{powerWeight ='120' } try{ const abi2 = item.abilities[2].ability.name;//特性が3つある const abi0 = item.abilities[0].ability.name; const abi1 = item.abilities[1].ability.name; result = `特性1 ${abi0} 特性2 ${abi1} 特性3 ${abi2} 素早さ種族値 ${speed} くさむすび、けたぐりの威力${powerWeight}`; console.log(`「${tag}」`); } catch(error) { try{const abi1 = item.abilities[1].ability.name;//特性が2つある const abi0 = item.abilities[0].ability.name; result = `特性1 ${abi0} 特性2 ${abi1} 素早さ種族値 ${speed} くさむすび、けたぐりの威力${powerWeight}`; console.log(`「${tag}」`); } catch(error) {const abi0 = item.abilities[0].ability.name; result = `特性1 ${abi0} 素早さ種族値 ${speed} くさむすび、けたぐりの威力${powerWeight}`; console.log(`「${tag}」`); } } // 正常に取得できればここで終了 } catch (error) { // HTTPステータスコードが404ならタグが見つからない、それ以外は別のHTTPエラーです const { status, statusText } = error.response; if (status == 404) { result = 'ポケモンの名前を正確に入力してください。英語で。'; } else { result = `エラー: ${status} ${statusText}`; } } // リプライではなく「プッシュ」を送ります // Botからユーザーへ一方的に通知を送ることができる機能です await client.pushMessage(userId, { type: 'text', text: result, }); } const sampleFunction = async (event) => { // ユーザーIDとメッセージ文字列を関数に渡します // メッセージ文字列でQiitaタグを検索し、結果をQiitaから受け取ったらユーザーIDに対して「プッシュ」送信します // 検索には少し時間がかかるので、これの結果は後でユーザーに送られます getPoke(event.source.userId, event.message.text); // こちらが先に返事を返します // ユーザーからのメッセージに対する「リプライ」です // リプライは、受信したメッセージ1つにつき1回しか使えません return client.replyMessage(event.replyToken, { type: 'text', text: '検索しています……' }); }; 特性の数が変わると、ポケモンによってJSONの形式が異なるため、単純な繰り返し処理でのデータ取得ではエラーが発生するため、苦戦しました。 今回は例外処理を用いましたが、コードが非常に汚いので改善が必要かと思います。 動作 ポケモンの名前を英語で入力すると、特性、素早さ、体重依存の技を受けるときの威力が返ってきます。 必要なデータがサクサクと取れるので、対戦中確認したいときには一々ネットで調べる必要もなく便利です。 今後の追加機能 日本語化機能 ダメージ計算機能 体重差に応じた技威力の表示  まずは、日本語化でしょうか。私のようにニックネームを英語にしたいから英語でプレイするという方ばかりではないと思いますので。  他には、入力した内容を判別して、〇〇が✖️✖️で△△を攻撃した時のダメージは□□といった具合で、ダメージ計算ツールも実装できればより使いやすいかと考えています。ダメージ計算ツール自体は巷に溢れているため、ひとまずの実装優先度は低いと考えて一旦見送り。  また、攻撃する側とされる側の体重差に応じて技威力が変わる技については、あまり簡単に計算してくれるツールが見当たらないので、できれば実装したいのですが、これも該当する技の利用頻度が低いため、ひとまず見送っています。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

デブ活必需品!? お菓子の虜LINE bot

とにかく甘いお菓子が好き?  おしゃれなスイーツも、手作りケーキもおいしいけれど、私は断固「お菓子」推し!!  なんと数百円で楽園へひとっとび…わかる人にはわかりますよね・・・?    https://twitter.com/okinakamasayos1/status/1447864486598103041  https://twitter.com/okinakamasayos1/status/1423594038947500036 私の神サイト「お菓子の虜」?  メーカーが書いた記事じゃなく、実際に食べ歩いたレビューがなんと2,600種類以上!  お菓子好きにはたまらない「新商品」「期間限定商品」を重点的に紹介してくれます。  短くも美しく、想像力を掻き立てるレビューは必見ですよ~例えばこちら  「マロン」「梨」「ココア」など永遠にキーワード検索していられます。。。 APIで「お菓子の虜LINE bot」を作る?  そんな神サイトにWebAPIを発見!覚えたてのLINEbotの技術を組み合わせて、  キーワードを打ち込むと最新のお菓子情報が返信されるLINEbotを作りました!  チョコ?ピスタチオ? ふっと浮かんだキーワードから、   瞬時にあなたを最新お菓子レビューへ誘います!  完成品・コードははこちら サンプルコード (クリックで表示) 'use strict'; // ######################################## // 初期設定など // ######################################## // パッケージを使用します const express = require('express'); const line = require('@line/bot-sdk'); const axios = require('axios'); // ローカル(自分のPC)でサーバーを公開するときのポート番号です const PORT = process.env.PORT || 3000; // Messaging APIで利用するクレデンシャル(秘匿情報)です。 const config = { channelSecret: 'チャンネルシークレット', channelAccessToken: 'アクセストークン' }; const getQiitaTag = async (userId, tag) => { let result = ''; try { // axiosでお菓子のAPIを叩きます const res = await axios.get('https://sysbird.jp/webapi/?apikey=guest&keyword=' + encodeURIComponent(tag)+'&max=1&format=json'); const item = res.data; result = '最新の「' + tag + '」関連お菓子は、' + item.item.regist + '紹介、\r\n「' + item.item.name + '」\r\n!詳しくはこちら(^^♪ \r\n' + item.item.url + '!'; // ターミナルにも検索結果を出しておきます console.log(`「${tag}」の検索結果:${item.item.name}`); // 正常に取得できればここで終了 } catch (error) { result = '「' + tag + '」のお菓子はまだないみたい。\r\n開発者のつもりで想像してみて♪\r\n私の一押しはこれ!https://sysbird.jp/toriko/2021/10/04/%e8%b4%85%e6%b2%a2%e3%83%ab%e3%83%9e%e3%83%b3%e3%83%89/'; } // リプライではなく「プッシュ」を送ります // Botからユーザーへ一方的に通知を送ることができる機能です await client.pushMessage(userId, { type: 'text', text: result, }); } const sampleFunction = async (event) => { getQiitaTag(event.source.userId, event.message.text); // こちらが先に返事を返します // ユーザーからのメッセージに対する「リプライ」です // リプライは、受信したメッセージ1つにつき1回しか使えません return client.replyMessage(event.replyToken, { type: 'text', text: 'あま~く詮索中……????' }); }; // ######################################## // 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 sampleFunction(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サーバーを実行中です…`); 甘いだけじゃない苦労話?  ①日本語tag検索どうすればいいのか問題   + encodeURIComponent(tag)+を入力することで解決    ②JSON形式ではなかった問題   &format=jsonをAPIの最後に入力することで表記がJSONに  ③画像が表示できない問題(未解決)   JSONではjpegでデータを取得できているが、LINEで表示させられず、今回は断念。  ④長いURLではなくサムネイルだけ表示させたい(未解決)   レビューサイトの長ったらしいURLではなく、サムネイル画像だけを表示させ   クリックするとレビューサイトへ飛べるようにしたかったが、辿り着けなかった。  ⑤検索結果が「0」だのときのリプライ問題   try...catch文で「0」をエラーとして検知し、別のメッセージを表示させた。   当初catch文の中にif文で組んでいたがうまくいかず、   結果シンプルに下記のコードで実行できた。   { status: 'OK', count: '0' }というJSONデータが帰ってきており、   これをどのような理由で「error」と検知しているのか、今の自分にはわからなかった。 } catch (error) { result = '「' + tag + '」のお菓子はまだないみたい。 努力は夢中に勝てない?  実はLINE botを作るのは今回が2回目。自分の大好きなテーマで制作したので  難しいながらも夢中で取り組め、理解も進んだと思う。今後は業務にも結び付けたいが、  いつも自分の「好き」や「やってみたい」に真摯に向き合っていたいな~と  お菓子を食べながら振り返る深夜1時30分でした?  
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む