「Web操作」ではIEを使ったVBAの基本機能だけで可能なweb操作の基礎について、「Web操作2」ではchromedriverを使ったseleniumによるweb操作について紹介しました。
Webページから必要な情報を取得するためには、まず対象のページの構造を理解する必要があります。ウェブページは階層的なツリー構造を持っており、要素やその親要素の関係性を理解することで、目的の要素を特定できます。
idを目印にして全ての要素を特定することができれば簡単ですが、目的の要素やその親要素にid属性がつけられているとは限りません。
XPathを使用すると、タグや属性、テキストの内容などを組み合わせて要素を特定することができます。
ここでは、要素を特定するための一つの方法として、XPathについて説明します。
XPathとは
XPath(XML Path Language)は、HTMLやXMLの要素を指定するためのパス言語です。
XPathは階層構造や属性の値に基づいて要素を特定するため、要素の位置が変わっても安定して目的の要素にアクセスすることができます。
XPathを理解して活用することで、シンプルな記述で効率的な要素の特定とデータの取得が可能になります。
XPathによる要素の指定
XPathの構文はシンプルです。
HTML内の要素を"/"(スラッシュ)で区切って階層構造で順に示して対象を特定します。
ここでは、以下の2つのtextarea要素を使って説明します。
課題動作チェックボタンは最後に使います。
説明用の「ふたつめのtextarea」を指定するXpathは"/html/body/section/article/p[12]/textarea[2]"となります。
これは目的の要素の位置を階層構造で示しており、上から順に「html要素→body要素→section要素→article要素→12番目のp要素→2番目のtextarea要素」と辿っていくことで目的の要素に到達することができます。
この例のように同じ種類の要素が同階層や同条件に複数存在する場合、1から始まる数字でインデックスを指定することにより、要素を特定することができます。
パスの省略
上の例では先頭のhtml要素から順にパスを指定していますが、このページにはtextarea要素がこの2個しかないため、textareaさえ見つけられればそこまでのパスは省略することができます。
"//"(ダブルスラッシュ)はそこまでのパスを省略することを表し、このページ内では"//textarea[2]"と表記すればより簡潔に「ふたつめのtextarea」を指定することができます。
属性(Attribute)による指定
[]内に@に続けて属性とその値を記述することで、一致する要素を特定することができます。
上記の「ひとつめのtextarea」には"fst"というclassが設定されています。
"//textarea[1]と"数字のインデックスで指定することもできますが、要素にクラスなどの属性が設定されている場合、"//textarea[@class='fst']"のように属性の値を参照して要素を特定することができます。
文字列による指定
[]内にcontains("検索対象","検索する文字列")を記述すると、検索する文字列が含まれる検索対象に一致する要素を特定することができます。
検索対象は属性を指定して属性の値自体を検索対象とすることができ、text()を指定すると要素内の文字列を検索対象とすることができます。
上記のtextarea内にはそれぞれ異なる文字列があらかじめ入力されているため、textarea内の文字列が"ひとつめ"であることが分かれば「ひとつめのtextarea」を特定することができます。
"//textarea[contains(text(),'ひとつめ')]"のように指定することで、textarea内の文字列に"ひとつめ"が含まれる要素を特定することができます。
その他の指定
XPathの記述方法は他にもあり、組み合わせることで複雑な指定が可能です。
XPathの構文を理解することは価値がありますが、実は自分でパスを作成するよりも簡単な方法があります。
主要なブラウザでは「Ctrl+Shift+i」や「F12」を押すことで開発者ツールを使用することができます。
以下の画像はこのページをFirefoxで開き、開発ツールのインスペクターでふたつめのtextareaを選択した画面です。
この状態だと上で説明した階層構造が簡単に確認できますが、さらに便利な方法があり、右クリック→コピー→XPathを選択すると、以下のように選択している要素のXPathを直接クリップボードにコピーして取得することができます。
実際に自分でXPathを組み立てるのは手間がかかってしまうため、この方法で要素を特定するためのXPathを取得することで効率的にwebページの解析やツールの作成作業を進めることができます。
XPathで要素を指定するサンプルコード
ここで、実際にXPathで指定した要素に対する操作を行うプログラムの例を作成し、ステップ実行してみましょう。
最後の行でchromeを終了していますので、必ずステップ実行してください。
SeleniumとChromeDriverを利用するコードになりますので、よくわからない場合はWeb操作2を先にご覧ください。
以下はこのページをchromeで開き、先ほどのtextarea(disabledが設定されているためブラウザ上では通常書き換えられないようになっている)の文字列を書き換えるためのサンプルプログラムです。
ただし、「※この行はエラーになります。」というコメントの行でエラーが発生します。
Public chrome As New ChromeDriver 'Crhomeドライバ
Sub XPathtest()
URL = "https://vbasokkou.dokkoisho.com/xpath.html" 'このページのURL
chrome.Get URL 'URLを指定して初期ページを表示
'ひとつめのtextareaを書き換える処理
Set element = chrome.FindElementByXPath("//textarea[@class='fst']") 'elementオブジェクトに要素を代入
element.Clear '要素内のテキストをクリア
element.SendKeys "書き換えました。" '要素内にテキストを入力
'ふたつめのtextareaを書き換える処理
Set element = chrome.FindElementByXPath("//textarea[2]") 'elementオブジェクトに要素(ふたつめのtextarea)を代入
element.SendKeys "エラーになります" '※この行はエラーになります。
chrome.ExecuteScript "arguments[0].removeAttribute('disabled')", element 'disabled属性を削除
element.Clear '要素内のテキストをクリア
element.SendKeys "disabledを削除してから書き換えました。" '要素内にテキストを入力
chrome.ExecuteScript "arguments[0].setAttribute('disabled', 'disabled')", element ' disabled属性を"disabled"に設定(元に戻す)
chrome.Quit 'chromeを終了する
End Sub
VBAからjavascriptを直接実行するExecuteScript
エラーの原因は、ふたつめのtextareaに'disabled'というユーザーが直接操作できないようにするための属性が設定されていることです。
やや応用的な内容となりますが、その次の行がjavascriptを利用してdisabled属性を削除しているコードです。
javascriptはブラウザ上で実行可能なスクリプト言語で、webページ上で様々な機能を実現します。
ExecuteScript関数はchrome上で直接javascriptのコードを指定して実行するための関数です。
この行は、ExecuteScriptの第2引数として渡されたelement(対象のtextarea)に対して、第1引数であるjavascriptのremoveAttribute関数を実行しています。
removeAttribute関数は、引数として渡された属性(この場合は'disabled')を対象となる要素から削除します。
この行を実行することで'disabled'は削除されるため、textareaに対するテキストの入力が可能となります。
サンプルではその後textareaの文字列を削除して新しく書き込みを行い、最後に元通り'disabled'を設定しています。
練習用の課題
今、先ほどのtextareaの横にある課題動作チェックというボタンを押すと、「課題に挑戦してみましょう。」と表示されるはずです。
このボタンは、"done"というid属性が設定された要素(要素の種類は何でも可)がページ内に存在する場合は上記とは異なる内容を表示させるようになっています。
先ほどのXPathtestに必要なコード追加し、chromeを終了させる前にブレークしてボタンを押して見てください。
以下はヒントになりますので、ぜひ挑戦してみてください。
①わざとエラーを発生させていた行を削除またはコメントアウトしてみましょう。
②先ほどdisabled属性に'disabled'を設定したコードを参考に、elementに'done'というid属性を設定する行を追加してみましょう。
③chrome.Quitの行にブレークポイントを設定してそこまで実行してみましょう。(止めないとブラウザが閉じられてしまうため)
④ボタンを押して結果を確かめてみましょう。