lxml xpath 找不到元素的解决方案

108 阅读2分钟

用户在使用 lxml xpath 时遇到了一个问题。当使用正确的 xpath 表达式和通常工作的情况下去查找元素时,却遇到了 AttributeError 异常,提示 'NoneType' object has no attribute 'text'

问题的根源在于下载并使用 TagSoup 处理的 HTML 源文件中存在一个额外的 <br> 标签,导致 xpath 表达式无法找到预期的元素。此外,有时所需信息的所在表格也会发生变化,导致 xpath 表达式无法正确获取数据。

2、解决方案

  1. 修复 HTML 文件: 将 HTML 文件中的额外 <br> 标签去除,或者使用更健壮的 HTML 解析器,如 lxml.html,以便正确解析具有额外或多个 <br><hr><p> 标签的 HTML 文件。

  2. 使用更健壮的 xpath 表达式: 使用更健壮的 xpath 表达式来查找目标元素,例如 /html/body/table[tr/td[@width="20%"]]/tr[position()>1],以确保能够在不同的 HTML 结构中找到目标元素。

  3. 处理不同表格的情况: 编写一个函数来确定信息的所在表格,并根据表格的位置调整 xpath 表达式,以确保能够从正确的表格中获取数据。

  4. 添加编码处理: 在解析 HTML 文件时,添加编码处理代码,以确保能够正确处理具有非 UTF-8 编码的 HTML 文件。

  5. 使用 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("--------------------------------------------------")