Python Webクローラー研究ノート(8):XPathの使用

XPathを使用する

XMLパス言語のフルネームであるXPathは、XMLドキュメント内の情報を検索するための言語であるXMLパス言語です。

1.XPathの一般的なルール

ここに写真の説明を挿入

XPathの一般的なマッチングルールをここに示します。例は次のとおりです。

//title[@lang='eng']

これはXPathルールであり、名前がtitleで、属性langがengであるすべてのノードを選択することを意味します。

後で、XPathを使用してPythonのlxmlライブラリを介してHTMLを解析します。

例を見てみましょう:

from lxml import etree
text = '''
<div>
    <ul>
         <li class="item-0"><a href="link1.html">first item</a></li>
         <li class="item-1"><a href="link2.html">second item</a></li>
         <li class="item-inactive"><a href="link3.html">third item</a></li>
         <li class="item-1"><a href="link4.html">fourth item</a></li>
         <li class="item-0"><a href="link5.html">fifth item</a>
     </ul>
 </div>
'''
html = etree.HTML(text)
result = etree.tostring(html)
print(result.decode('utf-8'))
<html><body><div>
    <ul>
         <li class="item-0"><a href="link1.html">first item</a></li>
         <li class="item-1"><a href="link2.html">second item</a></li>
         <li class="item-inactive"><a href="link3.html">third item</a></li>
         <li class="item-1"><a href="link4.html">fourth item</a></li>
         <li class="item-0"><a href="link5.html">fifth item</a>
     </li></ul>
 </div>
</body></html>

ここでは、最初にlxmlライブラリのetreeモジュールをインポートし、次にHTMLテキストの一部を宣言し、HTMLクラスを呼び出して初期化し、XPath解析オブジェクトが正常に構築されるようにします。HTMLテキストの最後のliノードは閉じられていませんが、etreeモジュールはHTMLテキストを自動的に修正できます。

ここでは、tostring()メソッドを呼び出して、改訂されたHTMLコードを出力しますが、結果はバイト型になります。ここでは、decode()メソッドを使用してstrタイプに変換し、結果は次のようになります。

<html><body><div>
    <ul>
         <li class="item-0"><a href="link1.html">first item</a></li>
         <li class="item-1"><a href="link2.html">second item</a></li>
         <li class="item-inactive"><a href="link3.html">third item</a></li>
         <li class="item-1"><a href="link4.html">fourth item</a></li>
         <li class="item-0"><a href="link5.html">fifth item</a>
     </li></ul>
 </div>
</body></html>

ご覧のとおり、処理後、liノードラベルが完成し、bodyノードとhtmlノードが自動的に追加されます。

さらに、分析のためにテキストファイルを直接読み取ることもできます。例は次のとおりです。

from lxml import etree
 
html = etree.parse('test.html', etree.HTMLParser())
result = etree.tostring(html)
print(result.decode('utf-8'))
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html><body><div>&#13;
    <ul>&#13;
         <li class="item-0"><a href="link1.html">first item</a></li>&#13;
         <li class="item-1"><a href="link2.html">second item</a></li>&#13;
         <li class="item-inactive"><a href="link3.html">third item</a></li>&#13;
         <li class="item-1"><a href="link4.html">fourth item</a></li>&#13;
         <li class="item-0"><a href="link5.html">fifth item</a>&#13;
     </li></ul>&#13;
 </div></body></html>

今回の出力結果は、DOCTYPE宣言が追加されてわずかに異なりますが、分析には影響しません。

2.すべてのノード

通常、//で始まるXPathルールを使用して、要件を満たすすべてのノードを選択します。前のHTMLテキストを例として取り上げます。すべてのノードを選択する場合は、次のようにします。

from lxml import etree
html = etree.parse('./test.html', etree.HTMLParser())
result = html.xpath('//*')
print(result)

[<Element html at 0x1f6c0205648>, <Element body at 0x1f6c0019bc8>, <Element div at 0x1f6c0019c88>, <Element ul at 0x1f6c0205348>, <Element li at 0x1f6c0205688>, <Element a at 0x1f6c0205708>, <Element li at 0x1f6c0205748>, <Element a at 0x1f6c0205788>, <Element li at 0x1f6c02057c8>, <Element a at 0x1f6c02056c8>, <Element li at 0x1f6c0205808>, <Element a at 0x1f6c0205848>, <Element li at 0x1f6c0205888>, <Element a at 0x1f6c02058c8>]

ここで*を使用して、すべてのノードを照合します。つまり、HTMLテキスト全体のすべてのノードが取得されます。ご覧のとおり、戻りフォームはリストであり、各要素は要素タイプであり、その後にhtml、body、div、ul、li、aなどのノードの名前が続きます。すべてのノードがリストに含まれます。

もちろん、ここで照合するためにノード名を指定することもできます。すべてのliノードを取得する場合の例は次のとおりです。

from lxml import etree
html = etree.parse('./test.html', etree.HTMLParser())
result = html.xpath('//li')
print(result)
print(result[0])
[<Element li at 0x1f6c01e6f88>, <Element li at 0x1f6c0205cc8>, <Element li at 0x1f6c0205d08>, <Element li at 0x1f6c0205d48>, <Element li at 0x1f6c0205d88>]
<Element li at 0x1f6c01e6f88>

ここでは、抽出結果がリストの形式であり、各要素がElementオブジェクトであることがわかります。オブジェクトの1つを取り出したい場合は、角括弧を直接使用して、[0]などのインデックスを追加できます。

3.子ノード

/または//を介して、要素の子ノードまたは子孫ノードを見つけることができます。liノードのすべての直接子ノードを選択する場合は、次のようにします。

from lxml import etree
 
html = etree.parse('./test.html', etree.HTMLParser())
result = html.xpath('//li/a')
print(result)
[<Element a at 0x1f6c01e6fc8>, <Element a at 0x1f6c0205588>, <Element a at 0x1f6c0205e08>, <Element a at 0x1f6c0205e48>, <Element a at 0x1f6c0205e88>]

/直接の子ノードを選択するために使用されます//すべての子孫ノードを取得する場合は、それを使用できますたとえばulaノードのすべての子孫を取得するには、次のようにします。

from lxml import etree
 
html = etree.parse('./test.html', etree.HTMLParser())
result = html.xpath('//ul//a')
print(result)
[<Element a at 0x1f6c02058c8>, <Element a at 0x1f6c0205908>, <Element a at 0x1f6c02070c8>, <Element a at 0x1f6c0207108>, <Element a at 0x1f6c0207148>]

ただし、ここ//ul/a使用した場合、結果は得られません。/直接の子ノードを取得するために使用され、ulノードの下に直接のaノードがなく、ノードのみliであるため、一致する結果を取得できません。コードは次のとおりです。

from lxml import etree
 
html = etree.parse('./test.html', etree.HTMLParser())
result = html.xpath('//ul/a')
print(result)
[]

4.親ノード

..達成するために使用

from lxml import etree
html = etree.parse('test.html', etree.HTMLParser())
result = html.xpath('//a[@href = "link4.html"]/../@class')
print(result)
['item-1']

親を介して親ノードを取得することもできます:::

from lxml import etree
html = etree.parse('test.html', etree.HTMLParser())
result = html.xpath('//a[@href = "link4.html"]/parent::*/@class')
print(result)
['item-1']

5.属性マッチング

@シンボルは、クラスがitem-1であるliノードの選択などの属性フィルタリングに使用されます。

from lxml import etree

html = etree.parse('test.html', etree.HTMLParser())

result = html.xpath('//li[@class = "item-0"]')
print(result)
[<Element li at 0x1f6c038cd08>, <Element li at 0x1f6c038c788>]

6.テキストの取得

XPathのtext()メソッドを使用して、liノードのテキストを取得します。

from lxml import etree

html = etree.parse('test.html', etree.HTMLParser())

result = html.xpath('//li[@class = "item-0"]/a/text()')
print(result)
['first item', 'fifth item']

//選択を使用した結果を見てみましょう

from lxml import etree

html = etree.parse('test.html', etree.HTMLParser())

result = html.xpath('//li[@class = "item-0"]//text()')
print(result)
['first item', 'fifth item', '\r\n     ']

これは、すべての子孫ノードのテキストを選択するためのものです。最初の2つは、liの子ノードのノード内のテキストであり、もう1つは、最後のliノード内のテキスト(改行)です。

7.属性の取得

@シンボルを使用して属性を取得する

from lxml import etree
 
html = etree.parse('./test.html', etree.HTMLParser())
result = html.xpath('//li/a/@href')
print(result)
['link1.html', 'link2.html', 'link3.html', 'link4.html', 'link5.html']

一部のノードの属性には複数の値がある場合があります。ここで、HTMLテキストのliノードのクラス属性には2つの値liとli-firstがあります。現時点では、以前の属性一致を使用して取得する場合、一致しません。

from lxml import etree
text = '''
<li class="li li-first"><a href="link.html">first item</a></li>
'''
html = etree.HTML(text)
result = html.xpath('//li[@class="li"]/a/text()')
print(result)
[]

contains()関数を使用して次のものを取得できます

from lxml import etree
text = '''
<li class="li li-first"><a href="link.html">first item</a></li>
'''
html = etree.HTML(text)
result = html.xpath('//li[contains(@class, "li")]/a/text()')
print(result)
['first item']

ノードに複数の属性がある場合は、を使用andして接続できます

from lxml import etree
text = '''
<li class="li li-first" name="item"><a href="link.html">first item</a></li>
'''
html = etree.HTML(text)
result = html.xpath('//li[contains(@class, "li") and @name="item"]/a/text()')
print(result)
['first item']

さらに、or、modなどの多くの演算子があります。

ここに写真の説明を挿入

8.順番に選択します

最初のliノードを選択し、角括弧内に番号1を渡し、最後のliノードを選択し、角括弧内にlast()を渡し、下から3番目のliノードを選択し、角括弧内にlast()-2を渡しました。

from lxml import etree
 
text = '''
<div>
    <ul>
         <li class="item-0"><a href="link1.html">first item</a></li>
         <li class="item-1"><a href="link2.html">second item</a></li>
         <li class="item-inactive"><a href="link3.html">third item</a></li>
         <li class="item-1"><a href="link4.html">fourth item</a></li>
         <li class="item-0"><a href="link5.html">fifth item</a>
     </ul>
 </div>
'''
html = etree.HTML(text)
result = html.xpath('//li[1]/a/text()')
print(result)
result = html.xpath('//li[last()]/a/text()')
print(result)
result = html.xpath('//li[position()<3]/a/text()')
print(result)
result = html.xpath('//li[last()-2]/a/text()')
print(result)
['first item']
['fifth item']
['first item', 'second item']
['third item']

おすすめ

転載: blog.csdn.net/qq_43328040/article/details/108808251
おすすめ