WebView2コントロールによるHTML要素の指定
Webページのテキストボックスやボタンなどの要素を操作する為に、要素のオブジェクトを特定する必要があります。
id属性やname属性等の情報を使って要素を特定する方法について説明します。
目次
WebView2コントロールのHTML要素へのアクセス方法について
WebView2コントロールにはDOMを直接操作するメソッドはありません。
代わりの手段としてExecuteScriptAsync
メソッドを使います。
ExecuteScriptAsync
メソッドは、表示しているWebページに対してJavaScriptを実行できますので、
JavaScriptでDOMを操作するコードを作成し、実行してやります。
※WebViewコントロールでのJavaScript実行についてはこちらを参照。
ページ内のすべての要素にアクセス
name属性、id属性、インデックス番号を指定してページ内(document内)の全ての要素にアクセスする方法です。
実装方法
WebView2コントロールのDOM操作はJavaScriptを使用します。
document.all
プロパティを使用します。
all
プロパティにname属性、id属性、インデックス番号を指定して要素を特定します。
name属性を指定した場合は複数の要素が取得されるため、さらに要素を特定するためにインデックス番号も指定する必要があります。
all
プロパティは「HTMLAllCollection」を取得します。
allプロパティにname属性を指定すると、1件見つかった場合は「Element」が取得され、
複数見つかった場合は「HTMLCollection」が取得され、見つからない場合はnullが返却されます。
allプロパティにid属性やインデックスを指定すると「Element」が取得され、見つからない場合はnullが返却されます。
サンプル
'下記コードの動作確認はテストページ(https://web.biz-prog.net/test/testpage.html)で Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles btnAllProperty.Click Await WebView2.ExecuteScriptAsync("document.all('inputid2').value = 'テキスト2 all id';") Await WebView2.ExecuteScriptAsync("document.all.item('inputid3').value = 'テキスト3 all item id';") End Sub
//下記コードの動作確認はテストページ(https://web.biz-prog.net/test/testpage.html)で private async void btnAllProperty_Click(object sender, EventArgs e) { await webView2.ExecuteScriptAsync("document.all('inputid2').value = 'テキスト2 all id';"); await webView2.ExecuteScriptAsync("document.all.item('inputid3').value = 'テキスト3 all item id';"); }
参考
id属性を指定して要素にアクセス
id属性を指定して一致する要素にアクセスする方法です。
実装方法
JavaScriptのdocument.getElementById
メソッドの引数にid属性を指定することで、要素を特定します。
特定した要素は「Element」オブジェクトまたはnull(一致する要素がない場合)で取得されます。
document.getElementById("id").~
サンプル
'下記コードの動作確認はテストページ(https://web.biz-prog.net/test/testpage.html)で Private Async Sub btnGetID_Click(sender As Object, e As EventArgs) Handles btnGetID.Click Await WebView2.ExecuteScriptAsync("document.getElementById('inputid2').value = 'テキスト2 all id';") End Sub
//下記コードの動作確認はテストページ(https://web.biz-prog.net/test/testpage.html)で private async void btnGetId_Click(object sender, EventArgs e) { await webView2.ExecuteScriptAsync("document.getElementById('inputid2').value = 'テキスト2 all id';"); }
参考
name属性を指定して要素にアクセス
name属性を指定して一致する複数の要素にアクセスする方法です。
実装方法
JavaScriptのdocument.getElementsByName
メソッドの引数にname属性を指定することで、要素を特定します。
name属性は同名が複数存在しますので、結果も複数取得されます。
特定した要素は「HTMLCollection/NodeList」またはnull(一致する要素がない場合)が取得されます。
document.getElementsByName("name属性")[n].~
※nは0~の数値
サンプル
Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click 'Yahooの検索欄に文字を設定する Await WebView2.ExecuteScriptAsync($"document.getElementsByName('p')[0].value = 'プログラムでネットサーフィン!';") End Sub '下記コードの動作確認はテストページ(https://web.biz-prog.net/test/testpage.html)で Private Async Sub btnGetName_Click(sender As Object, e As EventArgs) Handles btnGetName.Click Await WebView2.ExecuteScriptAsync("document.getElementsByName('inputname')[0].value = 'テキスト1 all name 0';") End Sub
async private void button1_Click(object sender, EventArgs e) { //Yahooの検索欄に文字を設定する await webView2.ExecuteScriptAsync("document.getElementsByName('p')[0].value = 'プログラムでネットサーフィン!';"); } //下記コードの動作確認はテストページ(https://web.biz-prog.net/test/testpage.html)で private async void btnGetName_Click(object sender, EventArgs e) { await webView2.ExecuteScriptAsync("document.getElementsByName('inputname')[1].value = 'テキスト2 all name 1';"); }
参考
class属性を指定して要素にアクセス
class属性を指定して一致する複数の要素にアクセスする方法です。
実装方法
JavaScriptのdocument.getElementsByClassName
メソッドの引数にclass属性を指定することで、要素を特定します。
class属性は同名が複数存在しますので、結果も複数取得されます。
特定した要素は「HTMLCollection」またはnull(一致する要素がない場合)が取得されます。
document.getElementsByClassName('inputclass')[0].~
サンプル
'下記コードの動作確認はテストページ(https://web.biz-prog.net/test/testpage.html)で Private Async Sub btnGetClass_Click(sender As Object, e As EventArgs) Handles btnGetClass.Click '指定するclass属性の0番目にアクセス Await WebView2.ExecuteScriptAsync("document.getElementsByClassName('inputclass')[0].value = 'テキスト1 class 0';") End Sub
//下記コードの動作確認はテストページ(https://web.biz-prog.net/test/testpage.html)で private async void btnClass_Click(object sender, EventArgs e) { //指定するclass属性の0番目にアクセス await webView2.ExecuteScriptAsync("document.getElementsByClassName('inputclass')[0].value = 'テキスト1 class 0';" ); }
参考
タグ名を指定して要素にアクセス
タグ名を指定して一致する複数の要素にアクセスする方法です。
実装方法
JavaScriptのdocument.getElementsByTagName
メソッドの引数にタグ名を指定することで、一致する要素を全て抽出します。
タグは同名が複数存在しますので、結果も複数取得されます。
特定した要素は「HTMLCollection」またはnull(一致する要素がない場合)が取得されます。
document.getElementsByTagName('tag')[0].~
サンプル
'下記コードの動作確認はテストページ(https://web.biz-prog.net/test/testpage.html)で Private Async Sub btnGetTag_Click(sender As Object, e As EventArgs) Handles btnGetTag.Click 'inputタグの0番目にアクセス Await WebView2.ExecuteScriptAsync("document.getElementsByTagName('input')[0].value = 'テキスト1 tag 0';") End Sub
//下記コードの動作確認はテストページ(https://web.biz-prog.net/test/testpage.html)で private async void btnTag_Click(object sender, EventArgs e) { //inputタグの0番目にアクセス await webView2.ExecuteScriptAsync("document.getElementsByTagName('input')[0].value = 'テキスト1 tag 0';"); }
参考
アンカー要素にアクセス
href属性を持つすべてのarea要素とアンカー要素にアクセスする方法です。
実装方法
JavaScriptのdocument.links
プロパティで全てのアンカー要素が取得できます。
インデックス番号を指定すると該当するアンカー要素を取得します。
特定した要素は「HTMLCollection」またはnull(一致する要素がない場合)が取得されます。
//アンカー要素を全て取得する
document.links
//nに0~の数値を指定することで、該当するアンカー要素を取得する
document.links(n)
//アンカー要素の数を取得する。
document.links.length
サンプル
'下記コードの動作確認はテストページ(https://web.biz-prog.net/test/testpage.html)で Private Async Sub btnAnchr_Click(sender As Object, e As EventArgs) Handles btnAnchr.Click Dim js As New System.Text.StringBuilder js.AppendLine("var str = '';") js.AppendLine("for (let i = 0; i < document.links.length; i++)") js.AppendLine("{") js.AppendLine(" str += document.links[i].href + '\n';") js.AppendLine(" str += document.links[i].innerText + '\n';") js.AppendLine(" if(document.links[i].innerText == 'リンク1') document.links[i].click();") js.AppendLine("}") js.AppendLine("alert(str);") Await WebView2.ExecuteScriptAsync(js.ToString()) End Sub
//下記コードの動作確認はテストページ(https://web.biz-prog.net/test/testpage.html)で private async void btnAnchr_Click(object sender, EventArgs e) { System.Text.StringBuilder js = new System.Text.StringBuilder(); js.AppendLine("var str = '';"); js.AppendLine("for (let i = 0; i < document.links.length; i++)"); js.AppendLine("{"); js.AppendLine(" str += document.links[i].href + '\\n';"); js.AppendLine(" str += document.links[i].innerText + '\\n';"); js.AppendLine(" if(document.links[i].innerText == 'リンク1') document.links[i].click();"); js.AppendLine("}"); js.AppendLine("alert(str);"); await webView2.ExecuteScriptAsync(js.ToString()); }
参考
form内の要素にアクセス
form要素内の全ての要素にアクセスする方法です。
form要素の指定は、name属性、id属性、インデックス番号が使用できます。
submit/resetの実行が行えます。
実装方法
document.forms
プロパティの引数にname属性/id属性/インデックス番号を指定することで、form要素を特定できす。
特定したform内の全ての要素は「HtmlCollection」で取得できます。
//ページの先頭からn番目のform要素にアクセスします。(nは0~の数値)
document.forms[index]
//form要素に定義されているid/name属性を指定します。
document.forms["name属性またはid属性"]
サンプル
Private Async Sub btnForm_Click(sender As Object, e As EventArgs) Handles btnForm.Click Dim js As New System.Text.StringBuilder js.AppendLine("document.forms['testform1'].reset();") js.AppendLine("document.forms['testform1'][0].value = 100;") js.AppendLine("document.forms['testform1']['checkname'].checked = true;") js.AppendLine("document.forms['testform1'].submit();") Await WebView2.ExecuteScriptAsync(js.ToString()) End Sub
private async void btnForm_Click(object sender, EventArgs e) { System.Text.StringBuilder js = new System.Text.StringBuilder(); js.AppendLine("document.forms['testform1'].reset();"); js.AppendLine("document.forms['testform1'][0].value = 100;"); js.AppendLine("document.forms['testform1']['checkname'].checked = true;"); js.AppendLine("document.forms['testform1'].submit();"); await webView2.ExecuteScriptAsync(js.ToString()); }
参考
CSSセレクタによる要素へのアクセス
CSSセレクタを指定して一致する要素にアクセスする方法です。
実装方法
JavaScriptのquerySelector
/querySelectorAll
メソッドを使うことで、CSSセレクタによる要素の取得が行なえます。
CSSセレクタは、要素を特定するための簡易なCSSの指定方法のようなものです。
querySelectorメソッドは指定されたセレクタに最初に一致した要素を返却します。見つからない場合はnullを返却します。
querySelectorAllメソッドは指定されたセレクタに一致した要素をすべて返却します。見つからない場合は空のリストを返却します。
サンプル
//下記コードの動作確認はテストページ(https://web.biz-prog.net/test/testpage.html)で //id指定 document.querySelector('#inputid2').value = "bbbb"; //class指定 document.querySelector('.inputclass').value = "aaaa"; //最初に見つかった要素 //クラスを複数指定する場合は'.inputclass, .inputclass2'のようにカンマで記述する //class指定 document.querySelectorAll('.inputclass')[4].click(); //見つかった要素の番号を指定 //type指定 document.querySelectorAll('input[type="text"]')[2].value = "cccc";
JavaScriptのコードが期待通りマッチするか確認するには、ブラウザの開発者ツールを使うのが簡単です。
例えばChromeのデベロッパーツールだと、ConsoleでJavaScriptのコードを入力して実行できます。
下記はセレクターのJavaScriptを実行して、期待通りに結果が得られていることが確認できます。
参考
座標から要素にアクセス
ブラウザの左上を基準として、指定した座標にあるHTML要素を取得します。
マウスカーソル上にあるHTML要素を取得したい場合などに使えます。
実装方法
document.elementFromPoint
メソッドを使用します。
//xとyで指定した座標に位置する要素のオブジェクトが取得されます。
element = document.elementFromPoint(x,y);
サンプル
Private Async Sub btnPoint_Click(sender As Object, e As EventArgs) Handles btnPoint.Click Dim js As New System.Text.StringBuilder js.AppendLine("var str = '';") js.AppendLine("document.addEventListener('click', (event) => {") js.AppendLine("const element = document.elementFromPoint(event.x, event.y);") js.AppendLine("str = element.tagName;") js.AppendLine("window.chrome.webview.postMessage(str);") js.AppendLine("});") Await WebView2.ExecuteScriptAsync(js.ToString()) End Sub Private Sub MessageReceived(sender As Object, args As Microsoft.Web.WebView2.Core.CoreWebView2WebMessageReceivedEventArgs) Handles WebView2.WebMessageReceived Label1.Text = args.TryGetWebMessageAsString() End Sub 'JavaScriptからの値の取得方法についてはhttps://web.biz-prog.net/readme/webview_new3.htmlを参照
private async void btnPoint_Click(object sender, EventArgs e) { System.Text.StringBuilder js = new System.Text.StringBuilder(); js.AppendLine("var str = '';"); js.AppendLine("document.addEventListener('click', (event) => {"); js.AppendLine("const element = document.elementFromPoint(event.x, event.y);"); js.AppendLine("str = element.tagName;"); js.AppendLine("window.chrome.webview.postMessage(str);"); js.AppendLine("});"); await webView2.ExecuteScriptAsync(js.ToString()); } private void MessageReceived(object sender, Microsoft.Web.WebView2.Core.CoreWebView2WebMessageReceivedEventArgs args) { label1.Text = args.TryGetWebMessageAsString(); } //JavaScriptからの値の取得方法についてはhttps://web.biz-prog.net/readme/webview_new3.htmlを参照
参考
iframe内の要素にアクセス
iframe内の要素にアクセスする方法です。
実装方法
他の要素取得と同じ方法でiframeのオブジェクトを取得してから、
その要素に対してDOMでアクセスします。
サンプル
'下記コードの動作確認はテストページ(https://web.biz-prog.net/test/testpage.html)で Private Async Sub btnForm_Click(sender As Object, e As EventArgs) Handles btnForm.Click Dim js As New System.Text.StringBuilder js.AppendLine("var iframe = document.getElementById('inline_frame');") js.AppendLine("iframe.contentWindow.document.getElementById('inputid2').value = 'テキスト2';") Await WebView2.ExecuteScriptAsync(js.ToString()) End Sub
//下記コードの動作確認はテストページ(https://web.biz-prog.net/test/testpage.html)で private async void btnForm_Click(object sender, EventArgs e) { System.Text.StringBuilder js = new System.Text.StringBuilder(); js.AppendLine("var iframe = document.getElementById('inline_frame');"); js.AppendLine("iframe.contentWindow.document.getElementById('inputid2').value = 'テキスト2';"); await webView2.ExecuteScriptAsync(js.ToString()); }
iframeのサイトがクロスドメインの場合
iframeで表示しているサイトのドメインが異なる場合(クロスドメイン)は、
ブラウザのセキュリティによりプログラムからはアクセスすることができません。
(例:「example.com」の中でiframeで「sample.com」を表示している場合、「sample.com」にはアクセスできない)
この制限は、WebView2の初期化時にセキュリティを無効にするオプションを指定すれば回避できます。
注意として、安全性が低下するのと、WebView2のバージョンが上がると使えなくなる可能性があります。
サンプル
'WebView2を初期化する処理を以下のように変更します Private Async Sub InitializeAsync() Dim options As New CoreWebView2EnvironmentOptions("--disable-web-security --user-data-dir --disable-site-isolation-trials") Dim environment As CoreWebView2Environment = Await CoreWebView2Environment.CreateAsync(Nothing, Nothing, options) Await WebView2.EnsureCoreWebView2Async(environment) End Sub '下記コードの動作確認はテストページ(https://web.biz-prog.net/test/testpage.html)で Private Async Sub btnForm_Click(sender As Object, e As EventArgs) Handles btnForm.Click Await WebView2.ExecuteScriptAsync("document.getElementById('cross_frame').contentWindow.document.getElementsByName('keyword')[0].value='テスト';") End Sub
//WebView2を初期化する処理を以下のように変更します async void InitializeAsync() { CoreWebView2EnvironmentOptions options = new CoreWebView2EnvironmentOptions("--disable-web-security --user-data-dir --disable-site-isolation-trials"); CoreWebView2Environment environment = await CoreWebView2Environment.CreateAsync(null, null, options); await wv2.EnsureCoreWebView2Async(environment); } //下記コードの動作確認はテストページ(https://web.biz-prog.net/test/testpage.html)で private async void button2_Click(object sender, EventArgs e) { await wv2.ExecuteScriptAsync("document.getElementById('cross_frame').contentWindow.document.getElementsByName('keyword')[0].value='テスト';"); }
shadow-root内の要素にアクセス
shadow-root(open)内の要素にアクセスする方法です。
実装方法
まず、他の要素取得と同じ方法でshadow-rootの親となる要素を取得します。
その要素に対してDOMでアクセスします。
サンプル
'下記コードの動作確認はテストページ(https://web.biz-prog.net/test/testpage.html)で Private Async Sub btnForm_Click(sender As Object, e As EventArgs) Handles btnForm.Click Dim js As New System.Text.StringBuilder js.AppendLine("var shadowroot = document.getElementById('sr');") js.AppendLine("shadowroot.shadowRoot.getElementById('inputid1').value = 'テキスト';") Await WebView2.ExecuteScriptAsync(js.ToString()) End Sub
//下記コードの動作確認はテストページ(https://web.biz-prog.net/test/testpage.html)で private async void btnForm_Click(object sender, EventArgs e) { System.Text.StringBuilder js = new System.Text.StringBuilder(); js.AppendLine("var shadowroot = document.getElementById('sr');"); js.AppendLine("shadowroot.shadowRoot.getElementById('inputid1').value = 'テキスト';"); await webView2.ExecuteScriptAsync(js.ToString()); }