「PythonでHTMLを解析したいけど、処理が遅い…」
「lxmlって聞いたことあるけど、何が違うの?」
Webスクレイピングやデータ処理をしていると、必ず出てくるのがlxml(エルエックスエムエル)ライブラリです。
この記事では、lxmlとは何か、どうやって使うのか、そしてBeautifulSoupとの違いや使い分けまで、初心者の方にも分かりやすく解説します。
難しい専門用語は最小限にして、実際に動くコード例を交えながら説明していきますね。
PythonでのXML/HTML処理を高速化したい方は、ぜひ最後までお読みください!
lxmlライブラリとは?基本を理解しよう

lxmlの定義
lxml(エルエックスエムエル)とは、PythonでXMLやHTMLを高速に処理するためのライブラリです。
正式名称:
- lxml(小文字で書くのが一般的)
- 「library XML」の略
開発:
- C言語で書かれた高速なライブラリ
- libxml2とlibxsltという既存のライブラリをベースにしている
- Pythonから使いやすいインターフェースを提供
なぜlxmlが必要なのか?
Pythonには標準でxml.etree.ElementTreeというXML処理ライブラリがあります。
でも、lxmlには大きなメリットがあるんです。
lxmlの強み:
- 圧倒的な速度(標準ライブラリより数倍~数十倍速い)
- XPathとCSSセレクタに対応
- 壊れたHTMLも処理できる
- 大きなファイルも効率的に処理
XMLとHTMLって何?
念のため、基本用語を確認しましょう。
XML(Extensible Markup Language):
- データを構造的に表現する形式
- タグで要素を囲む
- 設定ファイルやデータ交換に使われる
例:
<book>
<title>Pythonの教科書</title>
<author>山田太郎</author>
<price>2800</price>
</book>
HTML(HyperText Markup Language):
- Webページを作るための言語
- XMLと似た構造
- ブラウザで表示される
例:
<div class="product">
<h2>商品名</h2>
<p class="price">3,000円</p>
</div>
lxmlのインストール方法
実際に使ってみましょう。
pipでインストール
最も簡単な方法:
pip install lxml
バージョンを指定する場合:
pip install lxml==4.9.3
インストールの確認
正しくインストールできたか確認しましょう。
import lxml
print(lxml.__version__)
実行結果(例):
4.9.3
バージョン番号が表示されれば成功です。
インストール時のよくある問題
問題1:「error: command ‘gcc’ failed」と表示される
原因:
- C言語のコンパイラが必要
- 開発用ツールがインストールされていない
解決策(Linux):
# Ubuntu/Debian
sudo apt-get install python3-dev libxml2-dev libxslt1-dev
# CentOS/RHEL
sudo yum install python3-devel libxml2-devel libxslt-devel
解決策(Windows):
- Visual Studio Build Toolsをインストール
- または、事前コンパイル済みのwheelファイルを使う
問題2:「No matching distribution found」
原因:
- Pythonのバージョンが古すぎる、または新しすぎる
解決策:
- Python 3.6以上を使用
- lxmlの対応バージョンを確認
lxmlの基本的な使い方
実際のコード例を見ていきましょう。
XMLファイルの読み込み
基本的な読み込み:
from lxml import etree
# XMLファイルを読み込む
tree = etree.parse('data.xml')
# ルート要素を取得
root = tree.getroot()
# タグ名を表示
print(root.tag)
XML文字列のパース(解析)
ファイルではなく、文字列からXMLを読み込むこともできます。
from lxml import etree
# XML文字列
xml_string = """
<bookstore>
<book category="cooking">
<title>毎日のおかず</title>
<author>佐藤花子</author>
<price>1800</price>
</book>
<book category="programming">
<title>Python入門</title>
<author>田中一郎</author>
<price>2800</price>
</book>
</bookstore>
"""
# パース(解析)する
root = etree.fromstring(xml_string.encode('utf-8'))
# 結果を確認
print(root.tag) # → bookstore
要素の取得
子要素を取得:
# 全ての子要素を取得
for child in root:
print(child.tag) # → book, book
# 特定の子要素を取得
first_book = root[0]
print(first_book.tag) # → book
タグのテキスト内容を取得
# 最初の本のタイトルを取得
first_book = root[0]
title = first_book.find('title')
print(title.text) # → 毎日のおかず
# 価格を取得
price = first_book.find('price')
print(price.text) # → 1800
属性(アトリビュート)の取得
# 最初の本のカテゴリ属性を取得
first_book = root[0]
category = first_book.get('category')
print(category) # → cooking
XPathの使い方
lxmlの強力な機能の一つがXPath(エックスパス)です。
XPathとは?
XPathとは、XML/HTMLから要素を探すための言語です。
ファイルシステムのパスに似た書き方で、要素を指定できます。
基本的なXPath
例:全ての本のタイトルを取得
from lxml import etree
xml_string = """
<bookstore>
<book>
<title>毎日のおかず</title>
<price>1800</price>
</book>
<book>
<title>Python入門</title>
<price>2800</price>
</book>
</bookstore>
"""
root = etree.fromstring(xml_string.encode('utf-8'))
# XPathで全てのtitle要素を取得
titles = root.xpath('//title')
for title in titles:
print(title.text)
# 実行結果:
# 毎日のおかず
# Python入門
よく使うXPath表現
パターン1:特定のパスを指定
# bookstore直下のbook要素
books = root.xpath('/bookstore/book')
パターン2:どこにあっても探す
# どこにあってもtitle要素を全て取得
titles = root.xpath('//title')
パターン3:条件で絞り込む
# 価格が2000円以上の本
expensive_books = root.xpath('//book[price >= 2000]')
# cooking カテゴリの本
cooking_books = root.xpath('//book[@category="cooking"]')
パターン4:テキストを直接取得
# 全てのタイトルのテキストをリストで取得
title_texts = root.xpath('//title/text()')
print(title_texts) # → ['毎日のおかず', 'Python入門']
HTMLの処理

lxmlはHTMLの処理も得意です。
HTMLのパース
from lxml import html
# HTML文字列
html_string = """
<html>
<body>
<div class="product">
<h2>商品A</h2>
<p class="price">1,500円</p>
</div>
<div class="product">
<h2>商品B</h2>
<p class="price">2,300円</p>
</div>
</body>
</html>
"""
# HTMLをパース
tree = html.fromstring(html_string)
# 商品名を全て取得
products = tree.xpath('//div[@class="product"]/h2/text()')
print(products) # → ['商品A', '商品B']
# 価格を全て取得
prices = tree.xpath('//p[@class="price"]/text()')
print(prices) # → ['1,500円', '2,300円']
CSSセレクタの使用
XPathの代わりに、CSSセレクタも使えます。
from lxml import html
from lxml.cssselect import CSSSelector
html_string = """
<html>
<body>
<div class="product">
<h2>商品A</h2>
<p class="price">1,500円</p>
</div>
</body>
</html>
"""
tree = html.fromstring(html_string)
# CSSセレクタで要素を取得
selector = CSSSelector('div.product h2')
products = selector(tree)
for product in products:
print(product.text) # → 商品A
Webページのスクレイピング
実際のWebページから情報を取得してみましょう。
from lxml import html
import requests
# Webページを取得
url = 'https://example.com'
response = requests.get(url)
# HTMLをパース
tree = html.fromstring(response.content)
# タイトルを取得
title = tree.xpath('//title/text()')
print(title)
# 全てのリンクを取得
links = tree.xpath('//a/@href')
for link in links:
print(link)
BeautifulSoupとの比較
lxmlとよく比較されるのがBeautifulSoupです。
BeautifulSoupとは?
BeautifulSoupは、HTMLやXMLを解析するための人気ライブラリです。
特徴:
- 使いやすい
- 初心者に優しい
- 壊れたHTMLに強い
速度の比較
lxmlの方が圧倒的に速い!
ベンチマーク例(10,000個の要素を処理):
- lxml:0.05秒
- BeautifulSoup + lxmlパーサー:0.15秒
- BeautifulSoup + html.parser:0.80秒
結論:
大量のデータを処理する場合、lxmlが有利です。
使いやすさの比較
BeautifulSoupの方が分かりやすい:
# BeautifulSoupの例
from bs4 import BeautifulSoup
soup = BeautifulSoup(html_string, 'lxml')
title = soup.find('title').text
lxmlの例:
# lxmlの例
from lxml import html
tree = html.fromstring(html_string)
title = tree.xpath('//title/text()')[0]
結論:
簡単なタスクならBeautifulSoupが楽ですが、XPathを覚えればlxmlも十分使いやすいです。
どちらを使うべき?
lxmlを使うべき場合:
- 大量のデータを処理する
- 速度が重要
- XPathやCSSセレクタを活用したい
- XMLファイルを扱う
BeautifulSoupを使うべき場合:
- 初心者で手軽に始めたい
- 小規模なスクレイピング
- コードの可読性を重視
- 壊れたHTMLを扱う(ただしlxmlもかなり対応している)
ハイブリッド:
実は、BeautifulSoupのパーサーとしてlxmlを使うこともできます!
from bs4 import BeautifulSoup
# lxmlをパーサーとして指定
soup = BeautifulSoup(html_string, 'lxml')
これで、BeautifulSoupの使いやすさとlxmlの速度を両立できます。
実践的な使用例
実際のユースケースを見てみましょう。
例1:RSSフィードの解析
from lxml import etree
import requests
# RSSフィードを取得
url = 'https://example.com/rss'
response = requests.get(url)
# XMLとしてパース
root = etree.fromstring(response.content)
# 記事のタイトルと日付を取得
for item in root.xpath('//item'):
title = item.find('title').text
pubDate = item.find('pubDate').text
print(f'{title} - {pubDate}')
例2:設定ファイルの読み書き
from lxml import etree
# XMLファイルを読み込む
tree = etree.parse('config.xml')
root = tree.getroot()
# 設定値を変更
database_config = root.find('.//database')
database_config.find('host').text = 'localhost'
database_config.find('port').text = '3306'
# ファイルに保存
tree.write('config.xml', encoding='utf-8', xml_declaration=True)
例3:商品情報のスクレイピング
from lxml import html
import requests
def scrape_products(url):
# Webページを取得
response = requests.get(url)
tree = html.fromstring(response.content)
# 商品情報を抽出
products = []
for item in tree.xpath('//div[@class="product-item"]'):
product = {
'name': item.xpath('.//h3[@class="product-name"]/text()')[0],
'price': item.xpath('.//span[@class="price"]/text()')[0],
'rating': item.xpath('.//span[@class="rating"]/text()')[0]
}
products.append(product)
return products
# 使用例
products = scrape_products('https://example.com/products')
for product in products:
print(f"{product['name']}: {product['price']} (評価: {product['rating']})")
例4:XMLデータの作成
lxmlを使って、XMLを作成することもできます。
from lxml import etree
# ルート要素を作成
root = etree.Element('bookstore')
# 本の情報を追加
book1 = etree.SubElement(root, 'book', category='cooking')
etree.SubElement(book1, 'title').text = '毎日のおかず'
etree.SubElement(book1, 'author').text = '佐藤花子'
etree.SubElement(book1, 'price').text = '1800'
book2 = etree.SubElement(root, 'book', category='programming')
etree.SubElement(book2, 'title').text = 'Python入門'
etree.SubElement(book2, 'author').text = '田中一郎'
etree.SubElement(book2, 'price').text = '2800'
# XMLとして出力
xml_string = etree.tostring(root, encoding='utf-8', pretty_print=True)
print(xml_string.decode('utf-8'))
出力結果:
<bookstore>
<book category="cooking">
<title>毎日のおかず</title>
<author>佐藤花子</author>
<price>1800</price>
</book>
<book category="programming">
<title>Python入門</title>
<author>田中一郎</author>
<price>2800</price>
</book>
</bookstore>
よくあるエラーと解決方法

実際に使っていると、エラーに遭遇することがあります。
エラー1:「XMLSyntaxError」
エラーメッセージ:
lxml.etree.XMLSyntaxError: Start tag expected, '<' not found
原因:
- XML形式が正しくない
- HTMLをXMLとしてパースしようとしている
解決策:
# XMLの場合
from lxml import etree
root = etree.fromstring(xml_string.encode('utf-8'))
# HTMLの場合はこちらを使う
from lxml import html
tree = html.fromstring(html_string)
エラー2:「IndexError: list index out of range」
エラーメッセージ:
IndexError: list index out of range
原因:
- XPathで要素が見つからなかった
- 空のリストから要素を取得しようとした
解決策:
# 悪い例
title = tree.xpath('//title/text()')[0] # 要素がないとエラー
# 良い例
titles = tree.xpath('//title/text()')
if titles:
title = titles[0]
else:
print('タイトルが見つかりませんでした')
エラー3:文字化け
問題:
日本語が文字化けする
原因:
- エンコーディングの指定が間違っている
解決策:
# 文字列をパースする時
root = etree.fromstring(xml_string.encode('utf-8'))
# ファイルから読み込む時
parser = etree.XMLParser(encoding='utf-8')
tree = etree.parse('data.xml', parser)
# Webページをスクレイピングする時
response = requests.get(url)
response.encoding = 'utf-8'
tree = html.fromstring(response.text)
エラー4:「ImportError: cannot import name ‘etree’」
原因:
- lxmlがインストールされていない
- または古いバージョン
解決策:
# 再インストール
pip uninstall lxml
pip install lxml
# または最新版にアップグレード
pip install --upgrade lxml
パフォーマンスの最適化
大量のデータを処理する時のコツです。
iterparse()による逐次処理
大きなXMLファイルを処理する時は、iterparse()を使いましょう。
from lxml import etree
# メモリ効率の良い処理
for event, element in etree.iterparse('large_file.xml', tag='book'):
# 本の情報を処理
title = element.find('title').text
print(title)
# 処理済みの要素をメモリから削除
element.clear()
# 親要素からも参照を削除
while element.getprevious() is not None:
del element.getparent()[0]
メリット:
- ファイル全体を一度にメモリに読み込まない
- GBクラスの大きなファイルも処理可能
XPathのコンパイル
同じXPathを何度も使う場合、コンパイルすると高速化できます。
from lxml import etree
# XPathをコンパイル
find_title = etree.XPath('//title/text()')
# 何度でも使える(高速)
titles = find_title(root)
並列処理
複数のファイルやURLを処理する場合、並列処理が有効です。
from lxml import html
import requests
from concurrent.futures import ThreadPoolExecutor
def scrape_page(url):
response = requests.get(url)
tree = html.fromstring(response.content)
title = tree.xpath('//title/text()')[0]
return title
# 複数のURLを並列処理
urls = ['https://example1.com', 'https://example2.com', ...]
with ThreadPoolExecutor(max_workers=5) as executor:
results = executor.map(scrape_page, urls)
for title in results:
print(title)
よくある質問と回答
Q. lxmlとxml.etree.ElementTree、どちらを使うべき?
小規模なら標準ライブラリ、大規模ならlxml
xml.etree.ElementTreeを使う場合:
- 標準ライブラリなので追加インストール不要
- シンプルなXML処理
- 速度が重要でない
lxmlを使う場合:
- 高速処理が必要
- XPathやCSSセレクタを使いたい
- HTMLも処理したい
- 大量のデータを扱う
Q. lxmlは安全ですか?セキュリティは?
基本的には安全ですが、注意点があります。
XXE(XML External Entity)攻撃への対策:
from lxml import etree
# 安全な設定でパーサーを作成
parser = etree.XMLParser(
resolve_entities=False, # 外部エンティティを解決しない
no_network=True # ネットワークアクセスを禁止
)
# パーサーを使用
tree = etree.parse('file.xml', parser)
信頼できないXMLを扱う場合は必ず設定しましょう。
Q. XPathとCSSセレクタ、どちらを使えばいい?
好みの問題ですが、それぞれに得意分野があります。
CSSセレクタが向いている:
- Web開発の経験がある
- シンプルな要素の選択
- class、idでの指定
XPathが向いている:
- より複雑な条件指定
- テキスト内容での絞り込み
- 親要素や兄弟要素の取得
- 属性値での計算
Q. lxmlでJavaScriptで生成されるコンテンツをスクレイピングできますか?
できません。別のツールが必要です。
理由:
- lxmlは静的なHTML/XMLのみ処理
- JavaScriptは実行されない
解決策:
- Selenium(ブラウザを自動操作)
- Playwright(ブラウザ自動化ツール)
- requests-html(JavaScript実行機能付き)
これらと併用することで、動的なコンテンツも取得できます。
Q. Windowsでインストールできません
よくある原因と解決策:
原因1:Visual C++がない
# 事前ビルド済みのwheelをインストール
pip install lxml --only-binary lxml
原因2:Pythonのバージョンが合わない
- Python 3.6以上を使用
- 公式サイトで対応バージョンを確認
原因3:pip が古い
# pipをアップグレード
python -m pip install --upgrade pip
Q. 名前空間(namespace)の扱い方は?
名前空間付きのXMLを扱う場合:
from lxml import etree
xml_string = """
<root xmlns:custom="http://example.com/custom">
<custom:item>データ</custom:item>
</root>
"""
root = etree.fromstring(xml_string.encode('utf-8'))
# 名前空間を定義
namespaces = {'c': 'http://example.com/custom'}
# XPathで名前空間を指定
items = root.xpath('//c:item/text()', namespaces=namespaces)
print(items) # → ['データ']
まとめ:lxmlで高速なXML/HTML処理を
Python lxmlライブラリについて、基本から実用まで解説してきました。
この記事のポイント:
✓ lxmlは高速なXML/HTML処理ライブラリ
✓ 標準ライブラリより数倍~数十倍速い
✓ XPathとCSSセレクタに対応
✓ WebスクレイピングからRSS解析まで幅広く使える
✓ BeautifulSoupと組み合わせることも可能
✓ 大きなファイルはiterparse()で効率的に処理
✓ セキュリティ設定に注意(XXE攻撃対策)
最も大切なこと:
lxmlは、速度が重要なXML/HTML処理には欠かせないライブラリです。
最初は難しく感じるかもしれませんが、XPathを覚えれば非常に強力なツールになります。
今日から実践すること:
- まずはlxmlをインストールしてみる
- 簡単なXMLやHTMLをパースしてみる
- XPathの基本的な書き方を覚える
- 実際のWebスクレイピングに挑戦する
- 速度が必要な場面でBeautifulSoupから乗り換えを検討
Pythonでのデータ処理が、lxmlでもっと高速になりますよ!

コメント