python--lxml.etree解析html

转载自:悠悠博客园

 

前言

之前分享过一个python爬虫beautifulsoup框架可以解析html页面,最近看到lxml框架的语法更简洁,学过xpath定位的,可以立马上手。
使用环境:
python 3.6
lxml 4.2.4

lxml安装

使用pip安装lxml库

$ pip install lxml

pip show lxml查看版本号

$ pip show lxml

html解析

这里用到etree.HTML方法把html的文本内容解析成html对象
要打印html内容,可以用etree.tostring方法,encoding=”utf-8”参数可以正常输出html里面的中文内容。pretty_print=True是以标准格式输出

# coding:utf-8

from lxml import etree

htmldemo = '''
<meta charset="UTF-8"> <!-- for HTML5 -->
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<html><head><title>yoyo ketang</title></head>
<body>
<b><!--Hey, this in comment!--></b>
<p class="title"><b>yoyoketang</b></p>
<p class="yoyo">这里是我的微信公众号:yoyoketang
<a href="http://www.cnblogs.com/yoyoketang/tag/fiddler/" class="sister" id="link1">fiddler教程</a>,
<a href="http://www.cnblogs.com/yoyoketang/tag/python/" class="sister" id="link2">python笔记</a>,
<a href="http://www.cnblogs.com/yoyoketang/tag/selenium/" class="sister" id="link3">selenium文档</a>;
快来关注吧!</p>
<p class="story">...</p>
'''

# etree.HTML解析html内容
demo = etree.HTML(htmldemo)
# 打印解析内容str
t = etree.tostring(demo, encoding="utf-8", pretty_print=True)
print(t.decode("utf-8"))

运行结果

<html>
  <head><meta charset="UTF-8"/> <!-- for HTML5 -->
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>yoyo ketang</title>
</head>
  <body>
<b><!--Hey, this in comment!--></b>
<p class="title"><b>yoyoketang</b></p>
<p class="yoyo">这里是我的微信公众号:yoyoketang
<a href="http://www.cnblogs.com/yoyoketang/tag/fiddler/" class="sister" id="link1">fiddler教程</a>,
<a href="http://www.cnblogs.com/yoyoketang/tag/python/" class="sister" id="link2">python笔记</a>,
<a href="http://www.cnblogs.com/yoyoketang/tag/selenium/" class="sister" id="link3">selenium文档</a>;
快来关注吧!</p>
<p class="story">...</p>
</body>
</html>

soupparser解析器

soupparser解析器比上面的etree.HTML容错性要好一点,因为其处理不规范的html的能力比etree强太多。

import lxml.html.soupparser as soupparser
demo = soupparser.fromstring(htmldemo)
t = etree.tostring(demo, encoding="utf-8", pretty_print=True)

print(t.decode("utf-8"))

xpath使用案例

使用htnl解析器,最终是想获取html上的某些元素属性和text文本内容,接下来看下,用最少的代码,简单高效的找出想要的内容。
比如要获取“这里是我的微信公众号:yoyoketang”

# coding:utf-8

from lxml import etree

htmldemo = '''
复制上面的html内容
'''

# etree.HTML解析html内容
demo = etree.HTML(htmldemo)

nodes = demo.xpath('//p[@class="yoyo"]')
# 获取文本
t = nodes[0].text
print(t)

运行结果:

这里是我的微信公众号:yoyoketang

从代码量上看,简单的三行代码就能找到想要的内容了,比之前的beautifulsoup框架要简单高效的多

nodes是xpath定位获取到的一个list对象,会找出所有符合条件的元素对象。可以用for 循环查看详情

# coding:utf-8

from lxml import etree

htmldemo = '''
复制上面的html内容
'''

# etree.HTML解析html内容
demo = etree.HTML(htmldemo)

nodes = demo.xpath('//p[@class="yoyo"]')

print(nodes)  # list对象

for i in nodes:
    # 打印定位到的内容
    print(etree.tostring(i, encoding="utf-8", pretty_print=True).decode("utf-8"))
    # 元素属性,字典格式
    print(i.attrib)

运行结果

[<Element p at 0x2bcd388>]
<p class="yoyo">这里是我的微信公众号:yoyoketang
<a href="http://www.cnblogs.com/yoyoketang/tag/fiddler/" class="sister" id="link1">fiddler教程</a>,
<a href="http://www.cnblogs.com/yoyoketang/tag/python/" class="sister" id="link2">python笔记</a>,
<a href="http://www.cnblogs.com/yoyoketang/tag/selenium/" class="sister" id="link3">selenium文档</a>;
快来关注吧!</p>

{'class': 'yoyo'}

二次查找

通过xpath定位语法//p[@class=”yoyo”]定位到的是class=”yoyo”这个元素以及它的所有子节点,如果想定位其中一个子节点,可以二次定位,继续xpath查找,如获取:python笔记

nodes = demo.xpath('//p[@class="yoyo"]')

t1 = nodes[0].xpath('//a[@id="link2"]')
print(t1[0].text)

运行结果

python笔记

<think>嗯,用户遇到了一个ImportError,错误信息是关于lxml库中的某个未定义符号_PyGen_Send。我需要先弄清楚这个错误的原因。根据经验,这类错误通常与Python版本和库的兼容性有关。首先,_PyGen_Send是Python内部的一个函数,可能在Python 3.10中发生了变化,导致编译的lxml库无法找到这个符号。 接下来,我应该考虑用户是如何安装lxml的。如果用户是通过pip安装的二进制包(wheel),可能这个包是针对不同Python版本编译的,导致不兼容。或者用户可能从源代码编译了lxml,但编译时使用的Python版本和运行时的不一致。 另外,用户可能是在升级Python后没有重新安装lxml,导致旧的编译版本与新Python不兼容。例如,用户可能之前用Python 3.9安装了lxml,现在升级到3.10,但lxml没有重新编译,所以出现符号错误。 还需要检查系统是否存在多个Python版本,导致安装路径混乱。可能用户安装了lxml到全局的Python环境中,但当前使用的是虚拟环境中的Python,版本不一致。 解决步骤可能包括:首先建议用户卸载现有的lxml,然后安装构建依赖项,如Python开发文件和libxml2、libxslt的开发库,再重新从源代码编译安装lxml,确保与当前Python版本一致。如果用户使用的是预编译的wheel,可能需要从PyPI下载对应版本的wheel,或者使用--no-binary选项强制从源码构建。 此外,还需要检查操作系统的更新情况,确保系统库是最新的,避免兼容性问题。最后,建议用户验证安装后的库是否正常工作,运行简单的导入测试。 总结可能的原因:Python版本不匹配、错误的安装方式、缺少构建依赖项。解决方案是重新安装lxml,确保与Python版本兼容,并安装必要的系统依赖。</think>--- ### **错误分析** `ImportError` 中提到的 `undefined symbol: _PyGen_Send` 表明 **Python 解释器与 `lxml` 库的 C 扩展模块存在版本不兼容**。`_PyGen_Send` 是 Python 内部 API 的一部分,若 `lxml` 编译时使用的 Python 版本与当前运行时版本不一致,会导致此符号无法解析--- ### **常见原因** 1. **Python 版本升级未重装 `lxml`** - 例如:从 Python 3.9 升级到 3.10 后未重新编译 `lxml`。 2. **混合使用不同环境的安装包** - 在虚拟环境中使用了全局 Python 的 `lxml`。 3. **预编译的二进制包不兼容** - 通过 `pip install lxml` 安装的预编译二进制包(wheel)与当前系统环境不匹配。 --- ### **解决方案** #### **1. 强制重装 `lxml` 并确保源码编译** 卸载现有包并强制从源码构建: ```bash pip uninstall lxml -y sudo apt-get install libxml2-dev libxslt-dev python3-dev # 安装编译依赖 pip install --no-binary lxml lxml --force-reinstall ``` #### **2. 验证 Python 版本一致性** 检查当前 Python 解释器版本是否与 `pip` 默认版本一致: ```bash python --version # 例如:Python 3.10.12 pip --version # 确保 pip 关联的 Python 版本相同 ``` #### **3. 修复动态库路径(Linux 专用)** 若错误持续,尝试更新动态链接库缓存: ```bash sudo ldconfig ``` --- ### **关键原理** | 步骤 | 作用 | |-------------------|----------------------------------------------------------------------| | `--no-binary lxml` | 禁止使用预编译的二进制包,强制从源码编译生成与当前 Python 兼容的 C 扩展 | | `libxml2-dev` | 提供 `lxml` 依赖的 XML 解析库头文件 | | `python3-dev` | 包含 Python C 扩展开发所需的头文件,确保编译时能链接正确的 Python 符号 | --- ### **高级排查** #### **检查符号表** 通过 `nm` 工具验证 `lxml` 动态库中是否存在 `_PyGen_Send` 引用: ```bash nm -D /usr/local/lib/python3.10/dist-packages/lxml/etree.cpython-310-x86_64-linux-gnu.so | grep _PyGen_Send ``` - 若输出 `U _PyGen_Send`,表示该符号未定义(预期结果,需由 Python 运行时提供)。 - 若符号解析失败,说明编译时链接的 Python 版本与当前运行时版本不一致。 #### **调试 Python 环境** 通过 `gdb` 查看 Python 解释器是否导出该符号: ```bash gdb -ex "info symbol _PyGen_Send" --args python -c "import lxml.etree" ``` - 正常应输出类似 `_PyGen_Send in section .text of /usr/bin/python3.10`。 --- ### **环境修复示例** 若在 Docker 中遇到此问题,需确保构建阶段与运行阶段的 Python 版本严格一致: ```Dockerfile # 明确指定 Python 基础镜像版本 FROM python:3.10-slim # 安装编译依赖 RUN apt-get update && apt-get install -y \ libxml2-dev \ libxslt-dev \ && rm -rf /var/lib/apt/lists/* # 安装 lxml(从源码构建) RUN pip install --no-cache-dir --no-binary lxml lxml ``` --- ### **总结** 此错误的核心是 **Python 运行时环境与 `lxml` 编译环境版本不匹配**。通过强制源码编译、验证依赖一致性,并确保开发头文件正确安装,可彻底解决问题。若在容器化环境中,需固化基础镜像版本以避免隐式升级导致的兼容性问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值