悠悠楠杉
PythonlxmlETree与XPath:可靠地提取HTML元素内文本
lxml是基于C语言库libxml2和libxslt的高性能Python绑定,它不仅支持完整的XML和HTML解析,还具备出色的容错能力——即使面对现实中常见的不规范HTML代码(如未闭合标签、嵌套错误),也能准确构建DOM树。这使得它在处理真实世界网页时表现远超正则表达式或简单字符串匹配方法。
使用etree.HTML()函数可以将原始HTML字符串转换为可操作的Element对象树。例如:
python
from lxml import etree
html_content = """
深度学习模型迎来新突破
"""
tree = etree.HTML(html_content)
一旦获得ElementTree对象,便可通过XPath语法精确定位所需节点。XPath是一种用于在XML/HTML文档中导航和查询节点的强大语言,其路径表达式直观且功能丰富。比如提取页面标题,只需一条简洁的XPath:
python
title = tree.xpath('//title/text()')[0]
这条语句的意思是:查找文档中任意层级下的<title>标签,并取出其内部的文本内容。若需提取带有特定类名的文章标题,则可写成:
python
article_title = tree.xpath('//h1[@class="article-title"]/text()')
这里利用了属性匹配[@class="..."]来确保只选中目标元素,避免误抓其他同名标签。对于元数据如关键词和描述,通常存在于<meta>标签的content属性中,此时需使用@content来提取属性值:
python
keywords = tree.xpath('//meta[@name="keywords"]/@content')[0]
description = tree.xpath('//meta[@name="description"]/@content')[0]
这些表达式体现了XPath在处理属性与文本节点上的灵活性。值得注意的是,XPath返回的是列表,即便预期只有一个结果也应合理处理索引越界问题,建议配合条件判断或默认值机制增强健壮性。
正文内容的提取往往更具挑战性。不同网站结构差异巨大,有的使用<div class="content">,有的用<article>或<section>标签。此时可采用多策略组合方式,优先尝试高置信度的选择器,逐步降级到通用规则。例如:
python
candidates = [
'//article//text()',
'//div[@class="content"]//text()',
'//div[contains(@class, "article")]//text()'
]
for xpath in candidates:
texts = tree.xpath(xpath)
if len(texts) > 5: # 简单启发式判断:足够多段落视为正文
body_text = ''.join(t.strip() for t in texts if t.strip())
break
通过contains()函数模糊匹配类名,能有效应对动态生成的CSS类(如包含时间戳或哈希值的情况)。同时,使用//text()而非直接取元素文本,可捕获所有后代文本节点,包括被<p>、<br>等分隔的内容片段。
在整个提取流程中,编码一致性也不可忽视。某些老旧网页可能使用GBK或GB2312编码,需在解析前正确解码,否则会出现乱码。此外,去除广告、侧边栏、评论区等干扰内容,可借助长度统计、密度分析或机器学习分类器进一步优化结果。

