PythonのlxmlライブラリにおけるXPathの実践的使い方

1. ワイルドカードの応用

記号 用途
* 任意の要素名を同階層でマッチ
@* 任意の属性を同階層でマッチ
node() ノードタイプに関係なく同階層でマッチ
*/ 複数階層の任意要素をマッチ
// 任意階層の要素を圧縮的にマッチ

同階層での汎用マッチ


# 例: 2つのパスを統合
/html/body/div[*]/main/article/*/div

タグ名による条件指定


# h2とh4タグをOR条件で選択
/div/*[self::h2 or self::h4]/a

多階層マッチ


# 階層数が異なるパスを統一
/html/body/div/div/*//main/article/div/div

部分文字列マッチ


# class属性にitem-articleを含むdiv
//div[contains(@class, 'item-article')]

2. 要素の走査方法

XPath式 動作
./* 直下の子ノードのみ走査
.//* すべての子孫ノードを再帰的に走査
//* ルートからすべてのノードを走査

XML要素の操作例


from lxml import etree
xml_data = """
<div>
    <child1>
        <subchild1>Value1</subchild1>
        <subchild2>Value2</subchild2>
    </child1>
    <child2 class="2">
        <subchild3>Value3</subchild3>
    </child2>
    <a href="#"></a>
</div>
"""
div = etree.fromstring(xml_data)

elements = div.xpath('./*')
for element in elements:
    if element.tag == 'a':
        etree.strip_attributes(element, ["href"])
    if element.tag == 'child2' and element.get('class') == "2":
        element.getparent().remove(element)
content_html = etree.tostring(div, method='html', encoding='utf-8').decode('utf-8')
print(content_html)

3. 属性条件の指定


# ID属性で指定
div[@id="a123456"]

# 複数属性のAND条件
div[@class="article-content" and as="abc"]

4. 不要要素の削除


html = etree.HTML(resp.text)
[element.getparent().remove(element) for element in html.xpath("/html/body/div/div/div/main/article")]

5. 要素置換による削除


from lxml import etree
txt = '''
<div>
<div >兄弟1</div>
<div class="target"><p>子要素1</p><p>子要素2</p><p>子要素3</p></div>
<div >兄弟2</div>
</div>
'''
html = etree.HTML(txt)
target = html.xpath('/html/body/div/div[@class="target"]')[0]
[target.addprevious(child) for child in target]
target.getparent().remove(target)
print(etree.tostring(html,encoding='utf-8').decode('utf-8'))

6. 要素情報の取得


element = html.xpath("/html/body/div/div/div/main/article")
print(element.tag)  # タグ名
print(element.get('href'))   # 属性値
print(element.items())  # 全属性
print(element.text)  # テキスト
print(element.xpath("//*"))  # 子孫全要素

7. 属性の削除


from lxml import etree
etree.strip_attributes(element,["href"])

8. 要素のXPath取得


element_path = []
element_path_attr = []
element_path_index = []
while element:
    attr = '['+' and '.join(["@"+str(i[0])+'="'+str(i[1])+'"' for i in element.items() if i[0] in ['class','id','name','type','title','target','rel']])+']'
    element_path.insert(0,'/'+element.tag)
    element_path_attr.insert(0,'/'+element.tag + attr.replace('[]',''))
    element_path_index.insert(0, '/' + element.tag + ('['+str(element.getparent().index(element)+1)+']' if element.getparent() else ''))
    element = element.getparent()
print(''.join(element_path))
print(''.join(element_path_attr))
print(''.join(element_path_index))

9. Xpath Helper拡張機能

ブラウザ拡張機能としてXPath Helperが非常に有効

10. HTML形式での出力


from lxml import etree
etree.tostring(element,encoding='unicode',method='html')

タグ: Python lxml XPath Webスクレイピング XML処理

6月7日 22:07 投稿