ElementTree、lxml、SAX などのライブラリを使用してPythonでXMLをパースし、データ処理プロジェクトを強化する方法を学びます。
PythonでXMLをパースする方法に入る前に、まずXML Schema Definition(XSD)とは何か、そしてXMLファイルを構成する基本要素を理解することが重要です。この基礎知識により、パースのニーズに適したPythonライブラリを選択する指針になります。
XSD は、XMLドキュメントで許可される構造、内容、データ型を定義するスキーマ仕様です。検証ルールのセットとして機能し、XMLファイルが一貫した形式に従うことを保証します。
XMLファイルには通常、Namespace、root、attributes、elements、text content といった要素が含まれており、これらが組み合わさって構造化データを表現します。
Namespaceは、XMLドキュメント内の要素と属性を一意に識別します。命名の衝突を防ぎ、異なるXMLデータセット間の相互運用性を支援します。rootはXMLドキュメントの最上位要素です。XML構造への入口として機能し、他のすべての要素を包含します。attributesは要素に関する追加のコンテキストを提供します。要素の開始タグ内で定義され、名前と値のペアで構成されます。elementsはXMLファイルの中核単位で、実データまたは構造タグを表します。要素は入れ子にでき、階層を構築できます。text contentは、要素の開始タグと終了タグの間にある実際のテキストデータを指します。これにはプレーンテキスト、数値、その他の文字が含まれます。
たとえば、Bright Data sitemap は次のXML構造に従っています。
urlsetがroot要素として機能します。<urlset xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd">はurlset要素のNamespace宣言です。これはスキーマルールがurlsetおよびネストされたすべての要素に適用されることを示します。urlはroot要素の直接の子です。locはurl要素内の子要素です。
XSDとXML構造をより明確に把握できたところで、いくつかの便利なPythonライブラリを使ってXMLファイルをパースし、この知識を活用していきます。
Bright Data sitemapを使用します。以下の例では、Pythonの requests ライブラリを使用してBright Data sitemapのコンテンツを取得します。
Pythonのrequestsライブラリは標準搭載ではないため、先にインストールする必要があります。次のコマンドでインストールできます。
pip install requestsElementTree XML API は、PythonでXMLデータをパースおよび生成するための、シンプルでユーザーフレンドリーな方法を提供します。Pythonの標準ライブラリの一部であるため、追加のインストールは不要です。
たとえば、findall() メソッドを使用してrootからすべての url 要素を取得し、各 loc 要素のtext contentを次のように出力できます。
import xml.etree.ElementTree as ET
import requests
url = 'https://brightdata.jp/post-sitemap.xml'
response = requests.get(url)
if response.status_code == 200:
root = ET.fromstring(response.content)
for url_element in root.findall('.//{http://www.sitemaps.org/schemas/sitemap/0.9}url'):
loc_element = url_element.find('{http://www.sitemaps.org/schemas/sitemap/0.9}loc')
if loc_element is not None:
print(loc_element.text)
else:
print("Failed to retrieve XML file from the URL.")sitemap内のすべてのURLが出力に表示されます。
https://brightdata.jp/case-studies/powerdrop-case-study
https://brightdata.jp/case-studies/addressing-brand-protection-from-every-angle
https://brightdata.jp/case-studies/taking-control-of-the-digital-shelf-with-public-online-data
https://brightdata.jp/case-studies/the-seo-transformation
https://brightdata.jp/case-studies/data-driven-automated-e-commerce-tools
https://brightdata.jp/case-studies/highly-targeted-influencer-marketing
https://brightdata.jp/case-studies/data-driven-products-for-smarter-shopping-solutions
https://brightdata.jp/case-studies/workplace-diversity-facilitated-by-online-data
https://brightdata.jp/case-studies/alternative-travel-solutions-enabled-by-online-data-railofy
https://brightdata.jp/case-studies/data-intensive-analytical-solutions
https://brightdata.jp/case-studies/canopy-advantage-solutions
https://brightdata.jp/case-studies/seamless-digital-automations
ElementTreeはPythonのシンプルで直感的なXMLパーサーで、RSSフィードを読むような小規模スクリプトに最適です。ただし、強力なスキーマ検証が不足しており、複雑または大規模なXMLパースには適さない場合があります。そのようなケースでは lxml のようなライブラリの方が適しています。
lxml は、PythonでXMLファイルをパースするための高速で使いやすく、機能が豊富なAPIです。pip を使用して lxml をインストールできます。
pip install lxmlインストール後、lxml を使用して、find()、findall()、findtext()、get()、get_element_by_id() などの various API メソッドでXMLファイルをパースできます。
たとえば、findall() メソッドで url 要素を反復し、(url 要素の子要素である)loc 要素を見つけ、次のコードでlocationのテキストを出力できます。
from lxml import etree
import requests
url = "https://brightdata.jp/post-sitemap.xml"
response = requests.get(url)
if response.status_code == 200:
root = etree.fromstring(response.content)
for url in root.findall(".//{http://www.sitemaps.org/schemas/sitemap/0.9}url"):
loc = url.find("{http://www.sitemaps.org/schemas/sitemap/0.9}loc").text.strip()
print(loc)
else:
print("Failed to retrieve XML file from the URL.")出力にはsitemapで見つかったすべてのURLが表示されます。
https://brightdata.jp/case-studies/powerdrop-case-study
https://brightdata.jp/case-studies/addressing-brand-protection-from-every-angle
https://brightdata.jp/case-studies/taking-control-of-the-digital-shelf-with-public-online-data
https://brightdata.jp/case-studies/the-seo-transformation
https://brightdata.jp/case-studies/data-driven-automated-e-commerce-tools
https://brightdata.jp/case-studies/highly-targeted-influencer-marketing
https://brightdata.jp/case-studies/data-driven-products-for-smarter-shopping-solutions
https://brightdata.jp/case-studies/workplace-diversity-facilitated-by-online-data
https://brightdata.jp/case-studies/alternative-travel-solutions-enabled-by-online-data-railofy
https://brightdata.jp/case-studies/data-intensive-analytical-solutions
https://brightdata.jp/case-studies/canopy-advantage-solutions
https://brightdata.jp/case-studies/seamless-digital-automations
ここまでは、要素を特定して値を表示する方法を見てきました。次は、パースする前にXMLファイルをスキーマに対して検証する方法を見ていきます。この手順により、ファイルがXSDで定義された構造に従っていることを確認できます。
sitemapのXSDは次のとおりです。
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.sitemaps.org/schemas/sitemap/0.9"
xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
elementFormDefault="qualified"
xmlns:xhtml="http://www.w3.org/1999/xhtml">
<xs:element name="urlset">
<xs:complexType>
<xs:sequence>
<xs:element ref="url" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="url">
<xs:complexType>
<xs:sequence>
<xs:element name="loc" type="xs:anyURI"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>スキーマ検証にこのsitemapを使用するには、手動でコピーして schema.xsd という名前のファイルを作成してください。
次に、このXSDを使用してXMLファイルを検証します。
from lxml import etree
import requests
url = "https://brightdata.jp/post-sitemap.xml"
response = requests.get(url)
if response.status_code == 200:
root = etree.fromstring(response.content)
try:
print("Schema Validation:")
schema_doc = etree.parse("schema.xsd")
schema = etree.XMLSchema(schema_doc)
schema.assertValid(root)
print("XML is valid according to the schema.")
except etree.DocumentInvalid as e:
print("XML validation error:", e)この手順では、etree.parse() メソッドを使用してXSDファイルをパースし、パースした内容からXML Schemaを構築します。最後に assertValid() を使用して、そのスキーマに対してXML rootを検証します。XMLが検証に合格すると XML is valid according to the schema のようなメッセージが表示され、そうでない場合は DocumentInvalid 例外がスローされます。
出力は次のようになります。
Schema Validation:
XML is valid according to the schema.
次に、xpath メソッドを使って、パスで要素を見つけるXMLファイルの読み取りを行います。
xpath() メソッドで要素を読み取るには、次のコードを使用します。
from lxml import etree
import requests
url = "https://brightdata.jp/post-sitemap.xml"
response = requests.get(url)
if response.status_code == 200:
root = etree.fromstring(response.content)
print("XPath Support:")
root = etree.fromstring(response.content)
namespaces = {"ns": "http://www.sitemaps.org/schemas/sitemap/0.9"}
for url in root.xpath(".//ns:url/ns:loc", namespaces=namespaces):
print(url.text.strip())このスニペットでは、ns プレフィックスを登録し、Namespace URI http://www.sitemaps.org/schemas/sitemap/0.9 に紐付けます。その後、XPath 式がこのプレフィックスを使用してNamespace付き要素をターゲットにします。具体的には、.//ns:url/ns:loc が、そのNamespace内の url 要素の子であるすべての loc 要素を選択します。
出力は次のようになります。
XPath Support:
https://brightdata.jp/case-studies/powerdrop-case-study
https://brightdata.jp/case-studies/addressing-brand-protection-from-every-angle
https://brightdata.jp/case-studies/taking-control-of-the-digital-shelf-with-public-online-data
https://brightdata.jp/case-studies/the-seo-transformation
https://brightdata.jp/case-studies/data-driven-automated-e-commerce-tools
https://brightdata.jp/case-studies/highly-targeted-influencer-marketing
https://brightdata.jp/case-studies/data-driven-products-for-smarter-shopping-solutions
https://brightdata.jp/case-studies/workplace-diversity-facilitated-by-online-data
https://brightdata.jp/case-studies/alternative-travel-solutions-enabled-by-online-data-railofy
https://brightdata.jp/case-studies/data-intensive-analytical-solutions
https://brightdata.jp/case-studies/canopy-advantage-solutions
https://brightdata.jp/case-studies/seamless-digital-automations
find() と findall() は xpath() よりも高速です。これは xpath() がすべての結果をメモリにロードするためです。より複雑なクエリが必要でない限り、find() を使用してください。
lxml はXMLとHTMLをパースするための強力なライブラリで、XPath、スキーマ検証、XSLT などの高度な機能をサポートします。高性能または複雑なタスクに最適ですが、別途インストールが必要です。
金融フィードのような大規模または複雑なXMLデータを扱う場合、lxml は効率的なクエリ、検証、変換のための有力な選択肢です。
minidom は、Pythonの標準ライブラリに含まれるシンプルで軽量なXMLパースライブラリです。lxml ほど機能が豊富でも効率的でもありませんが、XMLデータを簡単にパースして操作する方法を提供します。
要素へアクセスするために、さまざまなDOMメソッドを使用できます。たとえば、getElementsByTagName() method を使用すると、タグ名で要素を取得できます。
次は minidom ライブラリを使用してXMLファイルをパースし、タグ名で要素を取得する例です。
import requests
import xml.dom.minidom
url = "https://brightdata.jp/post-sitemap.xml"
response = requests.get(url)
if response.status_code == 200:
dom = xml.dom.minidom.parseString(response.content)
urlset = dom.getElementsByTagName("urlset")[0]
for url in urlset.getElementsByTagName("url"):
loc = url.getElementsByTagName("loc")[0].firstChild.nodeValue.strip()
print(loc)
else:
print("Failed to retrieve XML file from the URL.")出力は次のようになります。
https://brightdata.jp/case-studies/powerdrop-case-study
https://brightdata.jp/case-studies/addressing-brand-protection-from-every-angle
https://brightdata.jp/case-studies/taking-control-of-the-digital-shelf-with-public-online-data
https://brightdata.jp/case-studies/the-seo-transformation
https://brightdata.jp/case-studies/data-driven-automated-e-commerce-tools
https://brightdata.jp/case-studies/highly-targeted-influencer-marketing
https://brightdata.jp/case-studies/data-driven-products-for-smarter-shopping-solutions
https://brightdata.jp/case-studies/workplace-diversity-facilitated-by-online-data
https://brightdata.jp/case-studies/alternative-travel-solutions-enabled-by-online-data-railofy
https://brightdata.jp/case-studies/data-intensive-analytical-solutions
https://brightdata.jp/case-studies/canopy-advantage-solutions
https://brightdata.jp/case-studies/seamless-digital-automations
minidom はXMLデータをDOMツリーとして表現するため、ナビゲーションや操作が容易です。単純なXML構造の読み取り、変更、作成といった基本的なタスクに最適です。
プログラムがXMLファイルから設定を読み取る必要がある場合、minidom は子ノードや属性を見つけるなど、特定の要素へ容易にアクセスできます。たとえば、font-size ノードを素早く取得し、その値をアプリケーション内で使用できます。
SAX parser はイベント駆動型のXMLパーサーで、ドキュメントを順次処理し、開始タグ、終了タグ、text content などのイベントを発行します。DOMパーサーとは異なり、SAXはドキュメント全体をメモリにロードしないため、メモリ効率が重要な大きなXMLファイルに最適です。
SAXを使用するには、startElement や endElement などの特定のXMLイベントに対するイベントハンドラーを定義し、ドキュメントの構造と内容を処理できるようにカスタマイズします。
次はSAXパーサーを使用してXMLファイルを処理し、イベントハンドラーを定義してsitemapからURL情報を抽出する例です。
import requests
import xml.sax.handler
from io import BytesIO
class MyContentHandler(xml.sax.handler.ContentHandler):
def __init__(self):
self.in_url = False
self.in_loc = False
self.url = ""
def startElement(self, name, attrs):
if name == "url":
self.in_url = True
elif name == "loc" and self.in_url:
self.in_loc = True
def characters(self, content):
if self.in_loc:
self.url += content
def endElement(self, name):
if name == "url":
print(self.url.strip())
self.url = ""
self.in_url = False
elif name == "loc":
self.in_loc = False
url = "https://brightdata.jp/post-sitemap.xml"
response = requests.get(url)
if response.status_code == 200:
xml_content = BytesIO(response.content)
content_handler = MyContentHandler()
parser = xml.sax.make_parser()
parser.setContentHandler(content_handler)
parser.parse(xml_content)
else:
print("Failed to retrieve XML file from the URL.")出力は次のようになります。
https://brightdata.jp/case-studies/powerdrop-case-study
https://brightdata.jp/case-studies/addressing-brand-protection-from-every-angle
https://brightdata.jp/case-studies/taking-control-of-the-digital-shelf-with-public-online-data
https://brightdata.jp/case-studies/the-seo-transformation
https://brightdata.jp/case-studies/data-driven-automated-e-commerce-tools
https://brightdata.jp/case-studies/highly-targeted-influencer-marketing
https://brightdata.jp/case-studies/data-driven-products-for-smarter-shopping-solutions
https://brightdata.jp/case-studies/workplace-diversity-facilitated-by-online-data
https://brightdata.jp/case-studies/alternative-travel-solutions-enabled-by-online-data-railofy
https://brightdata.jp/case-studies/data-intensive-analytical-solutions
https://brightdata.jp/case-studies/canopy-advantage-solutions
https://brightdata.jp/case-studies/seamless-digital-automations
ファイル全体をメモリにロードする他のパーサーとは異なり、SAXはファイルをインクリメンタルに処理するため、メモリを節約しパフォーマンスを向上させます。ただし、各データセグメントを処理するためにより多くのコードが必要であり、後から分析するためにデータの一部へ戻って再参照することはできません。
SAXは、大きなXMLファイル(例:ログファイル)を効率的にスキャンして、特定の情報(例:エラーメッセージ)を抽出するのに最適です。しかし、分析で異なるデータセグメント間の関係を探索する必要がある場合、SAXは最適な選択肢ではない可能性があります。
PythonはXMLのパースを簡素化するための多用途なライブラリを提供します。ただし、requestsライブラリを使用してオンラインのファイルへアクセスする場合、クォータやスロットリングの問題に直面する可能性があります。Bright Data は、これらの制限を回避するのに役立つ信頼性の高いプロキシソリューションを提供しています。
スクレイピングやパースを省略したい場合は、無料の dataset marketplace をご覧ください。
