XPathの使い方[Python/スクレイピング]

programming.jpg

こんにちは

今回はPythonのスクレイピングに使用するXPathについて学んで行きましょう。

XPathとは

XPath(XML Path Language)はXML形式文書から特定の要素を指定するための言語です。

XMLはマークアップ言語の一種です。

XPathはこのXMLから特定の要素を指定することができます。

XPathは以下のライブラリに対応しています。

ElementTree

lxml + cssselect

スクレイピングするもの

スクレイピングするものは以下の3つになります。

基本的な書き方を説明する時に使用します。

<html>
<head><title>カレーのおすすめ具材</title></head>
 <body>
  <p class="title"><h2>カレーの具材一覧</h2></p>
  <p class="food">野菜編
   <a href="http://example.com/potatoes" class="vegetable" id="link1">じゃがいも</a>,
   <a href="http://example.com/carrots" class="vegetable" id="link2">にんじん</a> ,
   <a href="http://example.com/onion" class="vegetable" id="link3">たまねぎ</a>,
  </p>
 </body>
</html>

リストの要素を取得する時に使用します。

<ul class ="potatoes">
 <li>メークイン</li>
 <li>男爵薯</li>
 <li>はるか</li>
 <li>ノーザンルビー</li>
</ul>

表の要素を取得する時に使用します。

<table class="table">
  <tbody>
    <tr>
      <th>Ingredients</th><td>じゃがいも</td>
    </tr>
    <tr>
      <th>brand</th><td>男爵芋</td>
    </tr>     
    <tr>
      <th>capacity</th><td>200g</td>
    </tr>      
    <tr>
      <th>Price</th><td>300円</td>
    </tr>
    <tr>
      <th>Tax</th><td>10%</td>
    </tr>        
  </tbody>
</table>

XPathの実行環境として、下記のサイトを使用します。

XPathの記述方法一覧

XPathの記述方法を一覧にします。

探したい要素XPath
title要素//title
body要素の直接の子であるh2要素//body/h2
クラスの属性が”food”と等しい要素//*[@class=”food”]
id属性が”link1″と等しい要素//*[@id=”link”]
直下のテキストの中に”いも”が含まれるa要素を取得//a[contains(text(),”いも”)]
テキストのみ取得*/text()

XPathの記述方法の解説

title要素を取得

title要素を取得する場合、以下のように記述します。

/html/head/title
出力

<title>カレーのおすすめ具材</title>

XPathは一番上から階層ごとに/(スラッシュ)で区切って記述します。

階層の途中から記述

途中を省略して記述する場合は、以下のように記述しましょう。

title要素を取得する場合、以下のように記述します。

//head/title
出力

<title>カレーのおすすめ具材</title>

同じ出力が得られます。

先頭にスラッシュを2つ記述することで、途中から記述することができます。

h2要素を取得

h2要素を取得する場合は、以下のように記述します。

/html/body/p/h2
出力

<h2>カレーの具材一覧</h2>

子孫要素を取得

子孫要素を取得する方法は以下になります。

/html//h2
出力

<h2>カレーの具材一覧</h2>

スラッシュを2つ記述することで、途中を省略し子孫要素を取得することができます。

クラス属性を取得

クラス属性を取得したい場合は、以下のように記述します。

/html/body/p[@class="food"]
出力

<p class=”food”>野菜編 <a href=”http://example.com/potatoes” class=”vegetable” id=”link1″>じゃがいも</a>, <a href=”http://example.com/carrots” class=”vegetable” id=”link2″>にんじん</a> , <a href=”http://example.com/onion” class=”vegetable” id=”link3″>たまねぎ</a>, </p>

要素[ @属性=”属性値”]と記述することで、取得することができる。

id属性を取得

id属性を取得したい場合は、以下のように記述します。

/html/body/p/a[@id='link1']
出力

<a href=”http://example.com/potatoes” class=”vegetable” id=”link1″>じゃがいも</a>

id属性も要素[ @属性=”属性値”]と記述することで、取得することができる。

あいまい検索で取得

リンクなどの属性値をあいまい検索したい場合は、以下のように記述します。

//a[contains(text(),"いも")]
出力

<a href=”http://example.com/potatoes” class=”vegetable” id=”link1″>じゃがいも</a>

あいまい検索したい場合は、要素[contains(@属性,”属性値”)]と記述することで取得することができる。

文字列で取得

文字列で取得したい場合は、以下のように記述します。

//a[text()="じゃがいも"]
出力

<a href=”http://example.com/potatoes” class=”vegetable” id=”link1″>じゃがいも</a>

検索したい任意の文字列のある場合、[ ](スクエアブラケット)の中でtext()に文字列を渡すことで検索が可能です。

文字列だけを取得したい場合

要素の文字列だけを取得したい場合は、以下のように記述します。

//a[contains(text(),"いも")]
出力

じゃがいも

取得した要素の末尾/text()を記述することで、文字列のみを取得することができます。

リストから取得したい場合

リストから要素を取得したい場合もあると思います。

以下の場合を想定して、リストから取得します。

<ul class ="potatoes">
 <li>メークイン</li>
 <li>男爵薯</li>
 <li>はるか</li>
 <li>ノーザンルビー</li>
</ul>

//ul/li[position()=1]
出力

<li>メークイン</li>

スクエアブラケットの中にposition() = 数字を入力することで、目的の要素を取得することができます。

andやorを用いることで、リストから複数の要素を取得することができます。

また以下のリストに括弧で囲んだ数字を渡すことでも、要素を取得することができます。

//ul/li[1]

こちらは簡易的に書けますが、複数の要素を取得することができません。

表から要素を取得したい場合

要素が表に格納されている場面を良くみませんか。

Ingredientsじゃがいも
brand男爵芋
capacity200g
Price300円
Tax10%

上のようなテーブルから要素を取得する場合、2種類の方法があります。

  • 階層を降りて要素を取得
  • 対応する要素と軸を使って要素を取得

上のテーブルをコードで記述した場合、以下のようになります。

<table class="table">
  <tbody>
    <tr>
      <th>Ingredients</th><td>じゃがいも</td>
    </tr>
    <tr>
      <th>brand</th><td>男爵芋</td>
    </tr>     
    <tr>
      <th>capacity</th><td>200g</td>
    </tr>      
    <tr>
      <th>Price</th><td>300円</td>
    </tr>
    <tr>
      <th>Tax</th><td>10%</td>
    </tr>        
  </tbody>
</table>

階層を降りて要素を取得

階層を降りて要素を取得する場合、以下のようになります。

//tbody/tr[2]/td
出力

<<td>男爵芋</td>

tr要素の数字を変えることで、取得できる要素を変えることができます。

対応する要素と軸を使って要素を取得

次に対応する要素と軸を使って要素を取得します

//th[contains(text(),"brand")]/following-sibling::td
出力

<<td>男爵芋</td>

この方法であれば、行数が増えた場合でも取得が可能になります。

ちなみに軸には多くの種類があるため、目的に合ったものを使ってみてください。

コメントを残す

メールアドレスが公開されることはありません。

CAPTCHA