pythonを用いたスクレイピング手法であるBeautifulsoup4が有名です。このライブラリで得られたhtmlデータから、XPathを用いて欲しい情報を抽出する際に起きた瑣末なエラーについてメモします。
結論: Xpathの末尾に余計な文字をつけてはいけない
XPathを指定する際、末尾に余計なスラッシュ /
が残っていると表題のエラーが発生します。
#エラーが出るコード
root = html.fromstring(str(soup))
titles = root.xpath("//p/")
#正常に動作するコード
root = html.fromstring(str(soup))
titles = root.xpath("//p")
エラーの再現
テストとして、手元にある htmlファイル test.html
からpタグ の情報を取り出してターミナルに表示するコードを書いてみます。
.
├── bs_test.py #正常なコード
├── bs_test_error.py #エラーが起きるコード
└── test.html #解析対象
test.htmlの中身は以下の通りです。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
</head>
<body>
<h1>タイトル</h1>
<h2 id="headline">見出し1</h2>
<p id="content" name="content_name">コンテンツの内容1</p>
<h2 id="headline">見出し1</h2>
<p id="content" name="content_name">コンテンツの内容2</p>
</body>
</html>
コンテンツの内容1, コンテンツの内容2という文字列を取り出したいと思います。
エラーが発生する場合
bs_test_error.py(エラーが発生するコード)
from lxml import html
from bs4 import BeautifulSoup
#htmlファイルを読み込む
with open("test.html") as file:
soup = BeautifulSoup(file, 'html.parser')
#lxmlを用いて、xpathで指定した要素を抽出する。
root = html.fromstring(str(soup))
titles = root.xpath("//p/") #<- pの末尾にスラッシュが付随
for i in range(len(titles)):
print(titles[i].text)
ターミナルで実行すると、
$python bs_test.py
Traceback (most recent call last):
File "/Users/yosid/Documents/blg/SQL/mongoDB/bs_test.py", line 10, in <module>
titles = root.xpath("//p/") #リスト形式で返される
File "src/lxml/etree.pyx", line 1599, in lxml.etree._Element.xpath
File "src/lxml/xpath.pxi", line 305, in lxml.etree.XPathElementEvaluator.__call__
File "src/lxml/xpath.pxi", line 225, in lxml.etree._XPathEvaluatorBase._handle_result
lxml.etree.XPathEvalError: Invalid expression
正常に動作する場合の例
from lxml import html
from bs4 import BeautifulSoup
#htmlファイルを読み込む
with open("test.html") as file:
soup = BeautifulSoup(file, 'html.parser')
#lxmlを用いて、xpathで指定した要素を抽出する。
root = html.fromstring(str(soup))
titles = root.xpath("//p") #<-末尾のスラッシュを消去
for i in range(len(titles)):
print(titles[i].text)
ターミナルで実行すると、
$python bs_test.py
コンテンツの内容1
コンテンツの内容2
両コードの差分の確認
念の為、二つのコードの差分も見てみると、xpathを記述している部分しか差がないのが確認できます。
$diff bs_test_error.py bs_test.py
10c10
< titles = root.xpath("//p/")
---
> titles = root.xpath("//p")
まとめ
Beautifulsoup4とlxmlを利用した際に起きたエラーについてメモを共有しました。
僕はXPathの末尾の違いに気づくのに結構時間がかかったのですが(アホ)、使い慣れていない人などは気をつけてください。
以下に使用したライブラリのドキュメントを添付しています。
Beautifulsoup4の公式ドキュメント
Beautiful Soup Documentation — Beautiful Soup 4.12.0 documentation
lxmlの公式ドキュメント
lxml - Processing XML and HTML with Python
lxml - the most feature-rich and easy-to-use library for processing XML and HTML in the Python language
XPathの文法の解説記事
XPath基礎編(2) ー XPathの書き方 - Qiita
前回の記事では、XPathの基本概念を簡単に紹介しました。今回はXPathによるWebページ(HTML)からデータを指定・取得する方法、つまりXPathの書き方を紹介します。#1.タグ(要素)で指…
コメント