まとまった休みが取れたので、以前から興味のあったAmazon Alexaにチャレンジしましたが、思いのほか躓いてしまったので記録しておきます。
やったことは公式のサンプルをなぞっただけですので、詳しい手順はそちらを参照して頂けたらと思います。
やったこと
スマートスピーカーのEcho dotに問い合わせを行うと、Alexaスキルがその回答をWEBスクレイピングをして答えてくれる。
私のスペック
今回のチャレンジにあたっての私のスペックです。
プログラミング歴は19年くらいありますが、どれもこれも初めて。
- Amazon Alexa:はじめて
- AWS Lambda:はじめて
- Node.js:はじめて
- Java Script:はじめて
Amazon Alexa について
Alexa公式 動画シリーズ「Alexa道場」が親切丁寧なので、アカウントの作成〜スキル作成までを一通り悩まずにできました。
動画の本数が多いので「うお」と思いますが、1本の動画が5分程なので自分のテンポで進められます。
AWS Lambda について
当初、上記で作成する「alexa developer console」内でスクレイピングまでやろうと試行錯誤していましたが、どうもブラウザのJavaScriptでできるようなDom操作が、Node.jsの標準ライブラリではできないようなので、スクレイピングを簡単にするために、やむなくAWS Lambdaを使う事にしました。
これにあたり、「alexa developer console」のカスタムスキルのリクエスト先をAWS Lambdaに変更する必要ができたので、公式のカスタムスキルをAWS Lambda関数としてホスティングするを参考に実施しました。
ハマり① 移植
「alexa developer console」で実装したものを、「AWS Lambda関数」に移植しないといけませんが、サンプルコードがまあまあ違うので、移植先のサンプルコードを理解しないといけません。
インテント名を手掛かりにすると、移植しやすいかと思います。
ハマり② AlexaスキルとAWS Lambdaの関連付け
「AlexaスキルのスキルID」と「AWS Lambda関数のARN」を交換しないといけません。
確かに一緒のページには書いてあるのですが、一方がサンプルの記事の中にさらっと書いてあったので見落としていました。
- AlexaスキルのスキルIDの交換については、Alexa Skills Kitトリガーを追加するの3でやってます。
- AWS Lambda関数のARNの交換については、
カラーエキスパート設計図のサンプル対話モデルの4でやってます。
ハマり③ タイムアウト
AWS Lambda関数のデフォルトのタイムアウト値は3秒です。
最初は3秒以内で動いていたのですが、HTTPSでWEBページを取得する処理を追加したり、スクレイピングの処理を追加したりするうちに、いつの間にか処理時間が延びていた事に気づかず、ロジックを見て困っていました。
処理を追加してエラーが発生したらタイムアウトも疑ってみてください。
AWS Lambdaのマネジメントコンソールにて、タイムアウト値の変更が可能です。
https://aws.amazon.com/jp/blogs/news/aws-lambda-timeout-15min/
Node.js について
JavaScriptならなんとかなるかな。と思ってNode.jsについてロクに調べもせずに取り掛かってしまいました。
ハマり① ノンブロッキングIO
HTMLの取得を待たずにパース処理が動いてしまいます。
標準ライブラリに含まれるhttpを使って通信を行うと、結果を待たずに先に進んでしまいました。(で、解析失敗)
これは、「ノンブロッキングIO」と言うNode.jsの仕様であり、メインスレッド1本で複数のリクエストを裁くタイプのサーバーの特徴だそうです。
とはいえ、HTMLの取得を待ってパースを行う必要があるので調べた結果、Promiseという非同期処理を制御(直列実行・並列実行)できるものがある事がわかった為、下記記事を参考に実装を一部やり直しました。
お気楽 Node.js 超入門
いまさら聞けないNode.jsの基礎知識とnpm、Gulpのインストール
Node.jsのhttpsモジュールを用いた通信処理をPromiseで書き直して解読してみた
ハマり② スクレイピング
「Node.jsでスクレイピングするならこれが本命(たぶん)」を参考に(と言うかコピペ)させていただいて、HTMLの取得とパースが簡単にできました。
が、HTMLのパースで使うcheerioというライブラリは、パース結果をjQueryオブジェクトで返すとのこと。
jQueryについても知らない為、ハマったと言うか、JavaScriptを舐めてた為に理解するものが増えてしまい、時間がかかってしまいました。
HTMLと下記記事を何回も交互に見ながら、なんとか取りたい情報を取得する事に成功しました。