XPathとは
ブラウザ画面の要素を操作するためには、画面のHTML要素を一意に特定する必要があります。WingGoferでは要素を特定する方法としてXPathを使用します。
XPathとは
WebページはHTMLで記述され、ツリー状の構造となっています。XPathは、HTMLのツリー構造に着目して、要素を特定するための記述方法です。例えば以下のHTMLでは
HTML内容
<!DOCTYPE html>
<html>
<head> <!-- ヘッダ部は画面に表示されません -->
<title>サンプルページ</title>
<style type="text/css">
.red{color: red;}
</style>
</head>
<body>
<div id="main_container">
<h1>見出し</h1>
<p>段落1</p>
<p class="red">段落2</p>
<p>段落3</p>
</div>
<div id="footer">
<p>copyright</p>
</div>
</body>
</html>
HTMLは要素をタグ「<>」で囲み、タグ内にさらにタグを入れることができます。したがってHTML文書はツリー構造となります。
画面上の表示
見出し
段落1
段落2
段落3
copyright
「段落2」をXPathで指定すると、最上位の<htm>タグから、<body>,<div>,<p>と順番に降りていって
/html/body/div[1]/p[2]
のようになります。
p[2]は2番目のp要素を表します。(1始まり)
ただし、上記のようなXPathでは、画面が変更された場合(例えば先頭に段落を追加した場合、対象のp要素は3番目になる)XPathも変更される可能性が高くなり、そのたびに操作シナリオに記入されたXPathを変更する必要があります。
属性での指定
そこで、HTML要素が持つ「id」や「class」などの属性でXPathを記述することができます。
上の例で、段落2には「class="red"」の指定があるので、
//p[@class="red"]
と記述することができます。値を囲む記号は「”(ダブルクォーテーション)」または「’(シングルクォーテーション)」です。
//p
で、すべてのp要素を表し、
//p[@class="red"]
で、すべてのp要素の内、class属性が「red」であるものを表します。
id属性
class要素はスタイルシートを指定するために用いるため、必ずしも一意に要素を特定できるわけではありません。
一方、id属性は、HTML文書内で一意に定めることが約束されています(※1)。よってid要素を使用すれば要素を一意に特定することができます。
//div[@id="main_container"]/p[@class="red"]
のように記述すれば、div要素までは特定できるので、他のdiv要素内に、class属性がredのp要素があっても、気にする必要はありません。
※1:id属性が重複しないのは、HTMLの規約上の定めであって、ブラウザで保証されているわけではありません。もし重複したid属性を持つページであっても、エラーにならずにブラウザで表示されます。
WinGoferのXPath取得ツールは、重複チェックを行っているため、もしidが重複する場合でも、要素を一意に特定できるXPathを取得することができます。
XPathの書き方
WinGofrで使用できるXPathの記述例
XPath | 内容 |
---|---|
/html | htmlルート |
//* | すべての要素 |
//div | すべてのdiv要素 |
//div[1] | すべてのdiv要素の中で1番目のもの |
//div[last()] | すべてのdiv要素の中で最後のもの |
//div[1]/p[2] | 1番目のdiv要素の直下にあるp要素の中で2番目のもの |
//div[1]//p[2] | 1番目のdiv要素内にあるp要素の中で2番目のもの(子孫要素) |
//*[@id="id1″] | id属性が「id1」の要素 |
//div[@id="id1″] | id属性が「id1」のdiv要素 |
//input[@type="text"][@value="テキスト"] | type属性が「text」でvalue属性「テキスト」のinput要素 |
//p[a[contains(@href,"htttps://xxxxx")]] | p要素の内、href属性が「htttps://xxxxx」を含むa要素を持つもの |
//span[@class=’class1′] | class属性が「class1」のすべてのspan要素 |
//span[@class=’class1 class2′] | class属性が「class1,class2」のすべてのspan要素 |
//span[contains(@class,’class1 class2′)] | 「class1」と「class2」をclass属性に持つすべてのspan要素(他にclassがあってもOK) |
//span[@hoge=’hoge’] | hoge属性「hoge」を持つすべてのspan要素 |
//p[@text()="テキスト1″] | text(innerText)が「テキスト1」のp要素(完全一致) |
//p[contains(text(),"テキスト1")] | textが「テキスト1」を含むp要素(部分一致) |
//p[starts-with(text(),"テキスト1")] | 先頭のtextが「テキスト1」のp要素(※2) |
//input[@type="radio"][1]/following-sibling::label[1] | 1番目のradioボタンと同じ階層かつ、radioより後ろにあるlabel要素の内、1番目のもの(自分より後の兄弟要素) |
//label[@for="radio1″]/preceding-sibling::input[1] | for属性が「radio1」のlabel要素と、同一階層かつlabelより前にあるinput要素の内、1番目のもの(自分より前の兄弟要素) |
※2:ends-withは使用できません。
演算子
記号 | 説明 | 記入例 | 内容 |
---|---|---|---|
.. | 親要素 | //input[@id="id1″]/../p[1] | id属性「id1」を持つinput要素の親要素の直下で、最初のp要素(兄弟要素) |
and | 論理積 (かつ) | //*[@name="name1″ and @class="class1″] | name属性が「name1」かつ、class属性が「class1」の全ての要素 |
or | 論理和 (または) | //*[@name="name1″ or @class="class1″][1] | name属性が「name1」またはclass属性が「class1」の要素の内、1番目のもの |
not | 否定 (でない) | //table[@id="id1″]//td[not(contains(@class,"class1″))] | id属性「id1」を持つテーブル要素内にあるtd要素で、class属性に「class1」を含まないもの |