今回はNode-REDを使ってWebページの情報を処理してみます。Webページのデータ(HTML)をダウンロード(取得)して処理、保存する方法については以前扱っています。


第6回 Webからデータをダウンロード
https://news.mynavi.jp/techplus/article/natonakucommand-6/

Webページ上のデータを扱うには、なかなか難しい面もあります。多くはスクレイピングしてデータを取り出すことになります。ここらへんUNIXの標準コマンドや言語などでは面倒なこともあります。Webサーバーにデータを返す専用のAPIでも用意されていれば便利なのでしょうが、そのようなことはほとんどないでしょう。このため、Python言語などでHTMLデータから必要な情報を抜き出すスクレイピングが使われてしまうわけです。スクレイピングはHTMLの構造に大きく依存するため、対象となるHTMLの構造が変われば作り直さなければならず手間がかかります。
とは言え現状ではWebページ上のデータはスクレイピングして抜き出すのがいちばん効果的でしょう。
幸にしてNode-REDのベースとなっているNodeJSはWebページで使用されているJavaScript言語が動作します。つまり、大変親和性が高いと言えます。

○HTMLデータを取得

 それでは基本となるWebページのHTMLを取得してみましょう。取得するWebページは、この連載の第6回です。

 まず、新規にフローを作成します。
フローのタブの右側にある+ボタンをクリックすると新規にフローが作成されます。

 次にinjectノードを配置します。HTMLデータを取得するためには何らかのトリガーが必要なので、ここではinjectノードを使っています。もちろん何らかのトリガーとなるノードであればinjectノードでなくても構いません。

 次にネットワークのカテゴリからhttp requestノードをドラッグドロップして配置します。

 配置したらhttp requestノードをダブルクリックして設定画面を開きます。

 URLの欄に「https://news.mynavi.jp/techplus/article/natonakucommand-6/」と入力します。ここが取得したいWebページのURLになります。今回は他の設定は変更する必要はありません。このまま完了ボタンをクリックします。

 次にdebugノードを配置します。今回はデバッグメッセージサイドバーのみに出力するので何も設定する必要はありません。


 以下の図のようにノードを繋ぎます。繋いだらデプロイボタンをクリックします。

 無事にデプロイが終わったら実行してみましょう。Web上のデータには回線状況によっては時間がかかることがあります。しばらくするとデバッグメッセージサイドバーにHTMLデータが表示されます。エラーでなければHTMLデータ内に「なんとなくコマンド(6)~といった文字を確認できるはずです。

場合によっては図のようなメッセージが表示されることがあります。

"あなたのフローの認証情報ファイルは、システムによって生成されたキーで暗号化されています。このキーが何らかの理由で失われると、その認証情報ファイルは復号できず、削除して再入力する必要があります。"

これは警告ではなくセキュリティに関する注意喚起のメッセージです。Raspberry PiのOS再インストールやNode-REDに関係するディレクトリやファイルなどの破損・消滅などによっても表示されます。
今回のようなサンプルの場合は特段動作には影響がないので、このまま無視して進めても問題ありません。
なお、これは独自の暗号化キーをsettings.jsファイルに設定することで解消されます。(設定方法は一番最後に掲載してあります)

○特定のHTMLタグ内の文字列を抜き出す

 HTMLデータを取得できたのでHTMLタグ内の文字列を抜き出してみましょう。まず、簡単なところでページタイトルを抜き出します。ページのタイトルはtitleタグ内に書かれています。HTMLソースを表示すると以下のハイライト部分がtitleタグ部分になります。このtitleタグで囲まれた文字列を抜き出すわけです。

 まず、http requestノードとdebugノードを繋いでいる線を選択して削除します。

 次にパーサのカテゴリ内にあるhtmlノードをドラッグドロップして配置します。

 配置したら図のように各ノードを繋ぎます。

 htmlノードをダブルクリックして設定画面を開きます。抽出する要素にtitleと入力します。titleタグ内の文字を抜き出すので出力の部分では「要素のテキストのみ」を選択します。
設定が終わったら完了ボタンをクリックします。

 デプロイボタンをクリックします。問題がなければ実行します。すると結果がデバッグメッセージサイドバーに表示されます。配列なので▼をクリックすると内容が展開され表示されます。

 ページタイトルを抜き出すはずが、本文内の他の何かのtitleタグの内容まで抜き出されてしまっているようです。今回はページのタイトルだけを抜き出したいのでCSSセレクタを指定する部分を調整する必要があります。titleタグはheadタグ内に1つのはずなので抽出する要素の欄の指定をtitleでなくhead > titleとします。また、出力で「配列化した1つのメッセージ」から「要素毎の複数のメッセージ」に変更します。設定が終わったら完了ボタンを押します。

 デプロイしたら実行してみましょう。今度はページのtitleタグの文字だけがデバッグメッセージサイドバーに出力されるはずです。


○特定のHTMLタグ内の文字列を抜き出す(functionノード)

 先ほどの方法はタグがうまく階層化されているなどの条件を満たさないとうまくいかないことがあります。複雑なCSSセレクタを指定するくらいならfunctionノードでJavaScriptコードを書いた方がわかりやすく便利な場合があります。そこで今度はfunctionノードを使ってtitleタグの文字を抜き出してみます。
 まず、htmlノードとdebugノードの線を選択して削除します。

htmlノードをダブルクリックして図のように設定します。設定したら完了ボタンをクリックします。

次にfunctionノードを配置し図のように繋ぎます。

functionノードをダブルクリックして設定画面を開きます。コードの部分に以下のJavaScriptプログラムを入力します。JavaScriptプログラムの最初の1行がpayloadに入っている配列の最初の要素を抜き出してpayloadに書き戻すというものです。[0]を[1]にすると2番目の要素がpayloadに入ります。ページ内に複数の要素があり、必要な箇所だけを抜き出す場合は、この方がやりやすいのではないかと思います。

入力したら完了ボタンをクリックします。

msg.payload = msg.payload[0];
return msg;

 入力が終わったらデプロイして実行してみましょう。先ほどと同様にデバッグメッセージサイドバーにはtitleタグ内の文字が表示されます。

.
編集部おすすめ