Python の lxml モジュールの使用:
1. lxml について知る
lxml は高性能 Python XML ライブラリであり、主に XML ファイルと HTML ファイルの解析と生成 (解析、シリアル化、変換) に使用されます。XPath1.0、XSLT1.0、カスタム要素クラス、さらには Python スタイルのデータ バインディング インターフェイスもネイティブにサポートしています。lxml は Cpython に基づいて実装されており、その最下層は 2 つの C 言語ライブラリ、libxml2 と libxslt です。したがって、より高いパフォーマンスを持っています。
公式ドキュメント: https://lxml.de/
2. lxmlの基本的な使い方
lxml では、lxml.etree モジュールが最も一般的に使用される HTML および XML ドキュメント解析モジュールです。このうち lxml.etree.Element は xml を処理するためのコアクラスであり、Element オブジェクトは XML のノードとして直感的に理解できます。Element クラスを使用すると、XML ノード、ノード属性、およびノード内のテキストに対する操作を実装できます。
2.1 lxml モジュールのインストールとインポート
pip install lxml
from lxml import etree
2.2 ノードの操作:
1. ノードを作成します (Element オブジェクトを作成します)。
root = etrre.Element('root')
print(root)
2. ノード名を取得する
print(root.tag)
3. 子ノードの追加
サブノードを追加するには 3 つの方法があります。 1. SubElement メソッドを直接使用してサブノードを追加します。2. Element オブジェクトを作成し、append メソッドを使用してオブジェクトを親ノードに追加します。3. Element オブジェクトを作成し、insert メソッドを使用して、親ノードの指定された位置にオブジェクトを追加します。
- SubElement メソッドを使用して以下を追加します。
child_sub = etree.SubElement(root, 'child_sub')
- append メソッドを使用して以下を追加します。
child_append = etree.Element('child_append')
root.append(child_append)
- insert メソッドを使用して以下を追加します。
child_insert = etree.Element('child_insert')
root.insert(0, child_append) # 第一个参数为添加的位置,第二个参数为添加的Element对象
4. 子ノードを削除します。
Remove() メソッドを使用して、指定した子ノードを削除できます。すべての子ノードをクリアするには、clear() メソッドを使用します。
root.remove(child_sub) # 删除名字为child_sub节点
root.clear() # 清空root的所有子节点
5. ノードにアクセスします
Element オブジェクトでは、ノードにアクセスする方法がいくつかあります。
- ノードはリストを使用して方向付けできます。
- ノードには getparent() などのメソッドを通じてアクセスできます。
- xpath 構文 (まだ導入されていません) を使用して、指定したノードを見つけることができます。
(1) リストを使用してノードにアクセスします。
child_sub = root[0] # 通过下标来访问子节点
child_sub = root[0: 1][0] # 通过切片的方式来访问节点
for c in root: # 通过遍历来获取所有节点
print(c.tag)
c_append_index = root.index(child_append) # 获取节点的索引
print(len(root)) # 获取子节点的数量
(2) 次の方法でノードにアクセスします。
- 親ノードを取得します: getarent()
- すべての子ノードを取得: getchildren()
- ルートノードを取得します: getroot()
- findall(): 一致するすべての要素を返し、リストを返します。
- find(): 一致する最初の要素を返します。
print(child_sub.getparent().tag) # 查询父节点
print(root.getchildren()) # 查询所有子节点
print(root.getroot()) # 获取根节点
print(root.find('b')) # 查询第一个b标签
print(root.findall('.//b')) # 查询所有b标签
2.3 属性の操作:
Element では、ノードの属性が辞書の形式で格納されます。
プロパティを作成します。
属性を作成するには 2 つの方法があります。1. ノードの作成時に属性を作成します。2. set() メソッドを使用して属性を作成します。
root = etree.Element('root', language='中文') # 创建节点时创建属性
root.set('hello', 'python') # 使用set方法为root节点添加属性
プロパティを取得します。
print(root.get('language')) # 使用get方法获取属性
print(root['language'])
print(root.keys())
print(root.values())
print(root.items())
プロパティを変更します。
root['language'] = 'English'
2.4 テキストの操作
lxml の XML テキストにアクセスするにはさまざまな方法があり、text 属性と tail 属性を使用してテキストにアクセスできます。XPath 構文を使用してテキストにアクセスすることもできます。ここでは、text と tail を使用してテキストのプロパティを取得および設定する方法のみを紹介します。xpathについては後ほど詳しく紹介します。
text 属性と tail 属性の違いは次のとおりです。
XML 内のタグは通常、ペアで表示されます。ただし、HTML では、 などの単一のタグが存在する場合があります<html><body>text<br/>tail</body></html>
。
- text 属性は、ペアになったメモの読み取りと設定に使用されます
- tail 属性は、単一のタグの読み取りと設定に使用されます。
html = etree.Element('html')
body = etree.SubElement(html, 'body')
body.text = 'text' # 给body标签内写入text文本内容
br = etree.SubElement('body', 'br')
br.tail = 'tail' # 在br标签中写入tail文本内容
2.5 XML ファイルの解析とシリアル化
1. XML ファイルを解析する方法:
XML ファイルを解析する方法は多数あり、一般的に使用されるのは fromstring、XML、HTML、および parse です。XML および HTML のパラメータには、文字列またはバイナリ バイトコードを使用できます。
-
fromstring、XML、parse: ノードである Element オブジェクトを返します。主に文書の断片を解析するために使用されます。
-
parse(): 戻り値は、ElementTree 型のオブジェクト、つまり完全な XML ツリー構造です。parse は主に、Element オブジェクトではなく、完全なドキュメントを解析するために使用されます。
-
パラメータ:
ファイルを開くか、ファイル タイプ オブジェクト (バイナリ形式の
ファイル名または文字列
HTTP または FTP URL で開くことをお勧めします。)注: 通常、ファイル名または URL からの解析は、ファイル オブジェクトからの解析よりも高速です。
xml_data = '<root>data</root>'
# fromstring
root_str = etree.formstring(xml_data)
print(root_str.tag)
# XML
root_xml = etree.XML(xml_data)
print(root_xml.tag)
# HTML,如果没有<html>和<body>标签,则会自动补上
root_html = etree.HTML(xml_data)
print(root_html.tag)
# parse中的参数应该是一个完整的xml或html,同样返回值是一个ElementTree类型的对象,完整的xml树结构。parse主要用来解析完整的文档。
tree =etree.parse('text') #文件解析成元素树
root = tree.getroot() #获取元素树的根节点
print etree.tostring(root, pretty_print=True)
2. XML ファイルのシリアル化方法:
XML ファイルを生成するには 2 つの方法があります。 1. Element オブジェクトを XML 文字列に変換し、それをファイルに書き込みます。2. ElementTreee オブジェクトの write() メソッドを使用して、xml をファイルに直接書き込みます。
root = '<root>data</root>'
# 将Element对象转换成xml字符串写入文件
root_str = element.tostring(root, pretty_print=True, xml_declartion=True, encoding='utf-8')
with open('text.xml', 'w', encoding='utf-8') as f:
f.write(root_str)
# 将节点(Element对象)转为ElementTree对象。
tree = etree.ElementTree(root)
tree.write('text.xml', pretty_print=True, xml_declartion=True, encoding='utf-8')
パラメータの意味:
- 最初のパラメータは、XML が保存されているパス (ファイル名を含む) です。
- pretty_print: XML をフォーマットするかどうか (美化)
- xml_declaration: xml 宣言 (xml の先頭のテキストの 1 行目) を記述するかどうか。
- エンコーディング:エンコーディング形式
補足: ElementTree オブジェクトは完全な XML ツリーとして理解でき、各ノードは Element オブジェクトです。ElementPath は、XML の XPath に相当します。Element 要素を検索して見つけるために使用されます。
2.6 lxml名前空間の処理
ネームスペースとは何ですか? https://www.w3school.com.cn/xml/xml_namespaces.asp
名前空間を使用した XML 解析処理:
from lxml import etree
str_xml = """
<A xmlns="http://This/is/a/namespace">
<B>dataB1</B>
<B>dataB2</B>
<B><C>datac</C></B>
</A>
"""
xml = etree.fromstring(str_xml) # 解析字符串
ns = xml.nsmap # 获取命名空间
print(ns)
print(ns[None])
>>> {
None: 'http://This/is/a/namespace'}
>>> http://This/is/a/namespace
ns = xml.nsmap[None] # 获取命名空间xmlns
# 1. 使用findall方法查找指定节点。
for item in xml.findall(f'{
ns}b')
print(item.text)
# 2. 使用xpath语法加命名空间查找指定节点
ns = {
'x':root.nsmap[None]} # 获取命名空间
b = root.xpath("//x:B", namespaces=ns)
print(b)
C = root.xapth("//x:B/X:C", namespaces=ns)
print(c)
注: XML が名前空間 (xmlns) を保持する場合、ノードを検索するときに、ノードの各レベルで名前空間を追加する必要があります。名前空間が含まれていない場合、ノードをクエリできません。
さらに、名前空間を処理するための非常に優れた方法があります。これは、すべての名前空間を空の名前空間に置き換え、通常のノードとして扱うことです。
参考:https://blog.csdn.net/rhx_qiuzhi/article/details/105345624
3. lxml を使用して XML ケースを解析する
(1) lxmlのetreeライブラリをインポートする
from lxml import etree
(2) etree.HTMLを使用してhtml文字列(bytes型またはstr型)をxpathメソッドを持つElementオブジェクトに変換し、結果のリストを返す
html = etree.HTML(text)
ret_list = html.xpath("xpath语法规则字符串")
(3) xpath メソッドがリストを返す 3 つの状況
- 空のリストを返します。xpath 構文ルール文字列に従って、要素が見つかりません。
- 文字列のリストを返します: xpath 文字列ルールはテキストの内容または属性の値と一致する必要があります
- Element オブジェクトのリストを返します。xpath ルール文字列がラベルと一致し、リスト内の Element オブジェクトは引き続き xpath に使用できます。
from lxml import etree
text = '''
<div>
<ul>
<li class="item-1">
<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) # 也可以使用XML和fromstring方法
# 获取所有的class属性为item-1的href属性
href_list = html.xpath('//li[@class="item-1"]/a/@href')
# 获取所有的class属性为item-1的text内容
text_list = html.xpath('//li[@class="item-1"]/a/text()')
# 组装成字典
for href, title in zip(href_list, title_list):
print({
f'{
href}': f'{
title}'})
注: lxml.etree.HTML(html_str) メソッドは、不完全なタグを自動的に補完できます。
4. lxml を使用して XML ファイルの例を生成します。
from lxml import etree
# 创建element对象
root = etree.Element('root')
print(root.tag)
# 添加子节点
child_sub = etree.SubElement(root, 'child_sub')
child = etree.Element('child')
child_append = root.append(child) # 通过append向root节点里面追加子节点
child_insert = root.insert(0, child) # 通过insert向root节点开始的位置添加子节点
# 3.删除子节点
# root.remove(child2)
# 4.删除所有子节点
# root.clear()
# 5.以列表的方式操作子节点
print(len(root))
print root.index(child) # 索引号
# 6.生成xml字符串写入xml文件
# 将Element对象转换成xml字符串写入文件
root_str = etree.tostring(root, pretty_print=True, xml_declaration=True, encoding='utf-8')
with open('text.xml', 'wb') as f:
f.write(root_str)
# 将节点(Element对象)转为ElementTree对象。
tree = etree.ElementTree(root)
tree.write('text.xml', pretty_print=True, xml_declartion=True, encoding='utf-8')
参考リンク:https://blog.csdn.net/ydw_ydw/article/details/82227699
5. 補足: xPath 構文
- XPath (XML パス言語) は、HTML\XML ドキュメント内の情報を検索するための言語であり、 HTML\XML ドキュメント内の要素と属性を走査するために使用できます。
- W3School 公式ドキュメント: http://www.w3school.com.cn/xpath/index.asp
- XML および HTML 内のデータを抽出するには、通常、lxml モジュールおよび xpath 構文を使用する必要があります。
5.1 ノード選択構文:
xpath でノードを検索し、属性またはテキスト コンテンツを抽出するための構文:
表現 | 説明 |
---|---|
ノード名 | 要素を選択します。 |
/ | ルート ノードから選択するか、要素から要素に遷移します。 |
// | 位置に関係なく、選択内容に一致する現在のノードからドキュメント内のノードを選択します。 |
. |
現在のノードを選択します。 |
.. |
現在のノードの親ノードを選択します。 |
@ | プロパティを選択します。 |
文章() | テキストを選択します。 |
注: @ 記号が最後に表示される場合は属性の抽出に使用され、[] 内に表示される場合は属性の一致に使用されます。
不明なノードを選択するための構文:
不明な html および xml 要素はワイルドカードを使用して選択できます。
ワイルドカード | 説明 |
---|---|
* | 任意の要素ノードと一致します。 |
ノード() | あらゆるタイプのノードに一致します。 |
- すべてのタグ:
//*
- すべてのプロパティ:
//node()
5.2 ノード装飾構文:
ラベルの属性値や添え字などに応じて特定のノードを取得できます
パス式 | 結果 |
---|---|
//title[@lang="eng"] | lang 属性値が eng であるすべての title 要素を選択します |
/書店/本[1] | 書店要素の子である最初の書籍要素を選択します。 |
/bookstore/本[last()] | 書店の子である最後の book 要素を選択します。 |
/bookstore/book[last()-1] | 書店要素の子である最後から 2 番目の書籍要素を選択します。 |
/bookstore/book[位置()>1] | 本屋の下の book 要素を 2 番目から選択します |
//book/title[text()='ハリー・ポッター'] | 本の下にあるすべてのタイトル要素を選択し、テキストがハリー・ポッターであるタイトル要素のみを選択します |
//book/title[contains(text(), “ハリー”)] | ハリーのタイトル要素を含む本の下のテキストをすべて選択します |
/bookstore/本[価格>35.00]/タイトル | 書店要素の book 要素のすべての title 要素を選択し、price 要素の値は 35.00 より大きくなければなりません。 |
xpathの添字について:
- xpath では、最初の要素の位置は 1 です。
- 最後の要素の位置は last() です
- 最後から 2 番目は last()-1 です
5.3 Google Chrome xpath ヘルパー プラグインのインストールと使用
lxml モジュールを使用してデータを抽出するには、xpath 構文ルールをマスターする必要があります。次に、xpath 構文の練習に役立つ xpath ヘルパー プラグインを見てみましょう。
xpath ヘルパー プラグインのインストール:
1. Chrome プラグイン XPath Helper をダウンロードします。
- Chromeアプリケーションストアからダウンロードできます。ダウンロードできない場合は、以下のリンクからダウンロードすることもできます。
- ダウンロードアドレス:https ://pan.baidu.com/s/1UM94dcwgus4SgECuoJ-Jcgパスワード:337b
2. ファイルの拡張子を crx から rar に変更し、同じ名前のフォルダーに解凍します。
3. 開発者モードがオンになっている状態で、解凍したフォルダーを Chrome ブラウザ拡張機能インターフェイスにドラッグします。
4. ブラウザを再起動し、URL にアクセスしてページ上の xpath アイコンをクリックすると、使用できるようになります。
5. Linux または macOS オペレーティング システムの場合は、上記の手順 2 を操作する必要はなく、開発者モードをオンにした Chrome ブラウザ拡張機能のインターフェイスに crx ファイルを直接ドラッグします。