用户在使用 lxml xpath 时遇到了一个问题。当使用正确的 xpath 表达式和通常工作的情况下去查找元素时,却遇到了 AttributeError 异常,提示 'NoneType' object has no attribute 'text'。
问题的根源在于下载并使用 TagSoup 处理的 HTML 源文件中存在一个额外的 <br> 标签,导致 xpath 表达式无法找到预期的元素。此外,有时所需信息的所在表格也会发生变化,导致 xpath 表达式无法正确获取数据。
2、解决方案
-
修复 HTML 文件: 将 HTML 文件中的额外
<br>标签去除,或者使用更健壮的 HTML 解析器,如lxml.html,以便正确解析具有额外或多个<br>、<hr>和<p>标签的 HTML 文件。 -
使用更健壮的 xpath 表达式: 使用更健壮的 xpath 表达式来查找目标元素,例如
/html/body/table[tr/td[@width="20%"]]/tr[position()>1],以确保能够在不同的 HTML 结构中找到目标元素。 -
处理不同表格的情况: 编写一个函数来确定信息的所在表格,并根据表格的位置调整 xpath 表达式,以确保能够从正确的表格中获取数据。
-
添加编码处理: 在解析 HTML 文件时,添加编码处理代码,以确保能够正确处理具有非 UTF-8 编码的 HTML 文件。
-
使用
lxml.html: 考虑使用lxml.html解析 HTML 文件,以获得更健壮的解析和查找元素的能力。
代码示例:
from lxml import etree
forumfile = "morethread-alte-korken-fruchtweinkeller-89069-6046822-0.html"
parser = etree.XMLParser(encoding='ISO-8859-15')
t = etree.parse(forumfile, parser)
XPOSTS = "/html/body/table[tr/td[@width='20%']]/tr[position()>1]"
allposts = t.xpath(XPOSTS)
XUSER = "td[1]/a[3]/b"
XREG = "td/span"
XTIME = "td[2]/table/tr/td[1]/span"
XTEXT = "td[2]/p"
XSIG = "td[2]/i"
XAVAT = "td/img[last()]"
XPOSTITEL = "/html/body/table[3]/tr/td/table/tr/td/div/h3"
XSUBF = "/html/body/table[3]/tr/td/table/tr/td/div/strong[position()=1]"
for p in allposts:
# 处理可能不存在的元素
username = p.find(XUSER)
if username is not None:
username = username.text
else:
username = "Unknown"
# 处理可能不存在的元素
regdate = p.find(XREG)
if regdate is not None:
regdate = regdate.text
else:
regdate = "Unknown"
# 处理可能不存在的元素
posttime = p.find(XTIME)
if posttime is not None:
posttime = posttime.text
else:
posttime = "Unknown"
# 处理可能不存在的元素
posttext = p.find(XTEXT)
if posttext is not None:
posttext = etree.tostring(posttext, pretty_print=True)
else:
posttext = "Unknown"
# 处理可能不存在的元素
signature = p.find(XSIG)
if signature is not None:
signature = signature.text
else:
signature = "Unknown"
# 处理可能不存在的元素
avatar = p.find(XAVAT)
if avatar is not None:
avatar = avatar.get('src')
else:
avatar = "Unknown"
# 处理可能不存在的元素
post_title = p.find(XPOSTITEL)
if post_title is not None:
post_title = post_title.text
else:
post_title = "Unknown"
# 处理可能不存在的元素
sub_forum = p.find(XSUBF)
if sub_forum is not None:
sub_forum = sub_forum.text
else:
sub_forum = "Unknown"
# 输出处理后的数据
print(f"Username: {username}")
print(f"Registration Date: {regdate}")
print(f"Post Time: {posttime}")
print(f"Post Text: {posttext}")
print(f"Signature: {signature}")
print(f"Avatar: {avatar}")
print(f"Post Title: {post_title}")
print(f"Sub-Forum: {sub_forum}")
print("--------------------------------------------------")