Electronではwebviewを使って、簡単にwebページを表示することができるけど、そのページを構成しているhtmlってどうやって操作するんだろう・・・と思ったのでメモ。
Electronのメインプロセスとレンダラープロセスを理解しないとダメだったようです。
electronでは、以下のようにすれば、指定したwebページを表示することができる。
<webview> src="https://qiita.com/trend"> </webview>
だけど、この中の要素を扱おうと思っても扱うことができない。JavaScriptで要素を取得して出力しようと思ってもコンソールに出すことはできません。
要素の検証をしてみても、表示しているものはwebviewになっていますね。このwebviewで表示しているページの中の要素をいじりたい。
preloadを使って表示するページの要素を取得する
ここで表示しているページの要素を取得してコンソールに出したい、とするならpreload
を使えば可能。
<webview id="foo" preload="foo.js" src="https://qiita.com/trend"> </webview>
preloadで指定したfoo.jsでそのページの要素をいじることができる。
hatenaブログからおすすめ記事をコンソールに出力する
Qiitaのtrendの記事なんかを表示しようと思ったけど、ログイン処理が必要になってきそうので、はてなブログのトップページを表示させ、そこからおすすめ記事のタイトルを取ってきます。
今回で言えば、「正義の報復を受けよ」ですね。
index.htmlに以下のように書く。
<webview id="foo" preload="foo.js" src="http://hatenablog.com/"> </webview>
これでfoo.jsの中ではてなブログのトップページの要素をいじることができます。その前にメインプロセス側でjsをいじる。
<script> var webview = document.getElementById('foo'); // webviewのロードが終了したら呼ばれるイベント webview.addEventListener("did-finish-load", function(){ webview.send("getContent"); }); // プロセス間通信を行う webview.addEventListener('ipc-message', function(event) { console.log(event["args"][0]); // content.innerTextが出力される }); </script>
webviewのロードが終了したら、webview.sendでgetContentを指定しています。
レンダリングプロセスにチャネル経由で非同期メッセージを送信すると、任意の引数を送信することもできます。 レンダラープロセスは、ipcRendererモジュールを使用してチャネルイベントをリッスンすることによってメッセージを処理できます。
sendの引数でチャネルイベントを指定して、レンダラープロセス側では、そのイベントを指定することで受け取ることが可能なようですね。
こっちはfoo.jsです。
const {ipcRenderer} = require('electron') ipcRenderer.on('getContent', function(){ title = document.getElementsByClassName('serviceTop-entry-title')[0].firstElementChild.innerText; ipcRenderer.sendToHost('hogehoge', title); });
ipcRendererのイベント名はさっきメインプロセス側で指定したチャネル名getContentですね。ここでは、はてなのトップページからおすすめ記事のタイトルを取得し、それをメインプロセス側に送信しています。
それを受け取るときには、ipc-messageというものが使えそうです。
webview.addEventListener('ipc-message', function(event) { console.log(event["args"][0]); });
これでコンソールに表示されます。
ちなみにrendererの方で指定したhogehogeという名前のchannelは受け取り側のeventの中に入っています。
ipcRenderer.sendToHost('hogehoge', title);
webview.addEventListener('ipc-message', function(event) { console.log(event.channel); // hogehogeが出力される });
表示されますが、ちょっと面倒ですね。