无闭合标签)、属性值无引号等问题时,BeautifulSoup 会自动修复,而 XPath(lxml)可能解析异常:
| from bs4 import BeautifulSoup
# 不规范的 HTML(缺少 </div> 和引号)
html = "<div class=box><p>内容</div>"
soup = BeautifulSoup(html, "html5lib") # 用 html5lib 解析器修复
print(soup.p.text) # 输出:内容(成功提取,无视格式错误)
|
简单提取与遍历:对于结构简单的页面,BeautifulSoup 的 API 更直观,无需学习 XPath 语法,例如提取所有
![]()
标签的 src 属性:
| imgs = soup.find_all("img")
srcs = [img.get("src") for img in imgs] # 用 get() 方法获取属性,简洁明了
|
需要灵活处理节点关系:通过 .parent(父节点)、.next_sibling(下一个兄弟节点)等属性轻松遍历节点关系,例如获取某个标签的上一个兄弟节点:
| current_tag = soup.find("li", text="item2")
prev_tag = current_tag.previous_sibling # 获取上一个兄弟节点
|
组合使用场景
实际开发中,两者可结合发挥优势:
用 BeautifulSoup 修复不规范 HTML,再用 XPath 定位:先通过 BeautifulSoup 处理格式混乱的页面,再将修复后的文档传给 lxml 执行 XPath:
| soup = BeautifulSoup(html, "html5lib") # 修复 HTML
tree = etree.HTML(str(soup)) # 转为 lxml 可解析的对象
result = tree.xpath("//div/text()") # 用 XPath 提取
|
用 XPath 快速定位局部,再用 BeautifulSoup 处理细节:例如用 XPath 提取整个
标签,再用 BeautifulSoup 遍历其内部子节点:
| div_html = tree.xpath("//div[@class='content']")[0] # XPath 定位
div_soup = BeautifulSoup(etree.tostring(div_html), "html.parser") # 转为 BeautifulSoup 对象
for p in div_soup.find_all("p"): # 遍历子节点
print(p.text)
|
总结
选 XPath:当页面结构规范、需要复杂定位(如多条件、深层嵌套)或追求解析速度时。
选 BeautifulSoup:当页面格式混乱、提取逻辑简单,或更习惯 Python 式 API 时。
组合用:用 BeautifulSoup 处理不规范 HTML,再用 XPath 执行复杂筛选,兼顾容错性和灵活性。