Python中利用xpath解析HTML
<html>
<body>
<form>
<div id='leftmenu'>
<h3>text</h3>
<ul id=’china’><!-- first location -->
<li>...</li>
<li>...</li>
......
</ul>
<ul id=’england’><!-- second location-->
<li>...</li>
<li>...</li>
......
</ul>
</div>
</form>
</body>
</html>
直接使用lxml处理:
import codecs
from lxml import etree
f=codecs.open("ceshi.html","r","utf-8")
content=f.read()
f.close()
tree=etree.HTML(content)
etree提供了HTML这个解析函数,现在我们可以直接对HTML使用xpath了,是不是有点小激动,现在就尝试下吧。
在使用xpath之前我们先来看看作为对照的jQuery和RE。
在jQuery里要处理这种东西就很简单,特别是假如那个ul节点有id的话(比如是<ul id=’china’>):
$("#china").each(function(){...});
具体到此处是:
$("#leftmenu").children("h3:contains('text')").next("ul").each(function(){...});
找到id为leftmenu的节点,在其下找到一个内容包含为”text”的h3节点,再取其接下来的一个ul节点。
在python里要是用RE来处理就略麻烦一些:
block_pattern=re.compile(u"<h3>档案</h3>(.*?)<h3>", re.I | re.S)
m=block_pattern.findall(content)
item_pattern=re.compile(u"<li>(.*?)</li>", re.I | re.S)
items=item_pattern.findall(m[0])
for i in items:
print i
那么用xpath要怎么做呢?其实跟jQuery是差不多的:
nodes=tree.xpath("/descendant::ul[@id='china']")
当然,现在没有id的话也就只能用类似于jQuery的方法了。完整的xpath应该是这样写的(注意,原文件中的TAG有大小写的情况,但是在XPATH里只能用小写):
nodes=tree.xpath(u"/html/body/form/div[@id='leftmenu']/h3[text()='text']/following-sibling::ul[1]")
更简单的方法就是像jQuery那样直接根据id定位:
nodes=tree.xpath(u"//div[@id='leftmenu']/h3[text()='text']/following-sibling::ul[1]")
这两种方法返回的结果中,nodes[0]就是那个“text”的h3节点后面紧跟的第一个ul节点,这样就可以列出后面所有的ul节点内容了。
如果ul节点下面还有其他的节点,我们要找到更深节点的内容,如下的循环就是把这些节点的文本内容列出:
nodes=nodes[0].xpath("li/a")
for n in nodes:
print n.text
对比三种方法应该可以看出xpath和jQuery对于页面的解析都是基于XML的语义进行,而RE则纯粹是基于plain text。RE对付简单的页面是没有问题,如果页面结构复杂度较高的时候(比如一堆的DIV来回嵌套之类),设计一个恰当的RE pattern可能会远比写一个xpath要复杂。特别是目前主流的基于CSS的页面设计方式,其中大部分关键节点都会有id――对于使用jQuery的页面来说则更是如此,这时xpath相比RE就有了决定性的优势。
附录:基本XPATH语法介绍,详细请参考XPath的官方文档
XPATH基本上是用一种类似目录树的方法来描述在XML文档中的路径。比如用“/”来作为上下层级间的分隔。第一个“/”表示文档的根节点(注意,不是指文档最外层的tag节点,而是指文档本身)。比如对于一个HTML文件来说,最外层的节点应该是”/html”。
同样的,“..”和“.”分别被用来表示父节点和本节点。
XPATH返回的不一定就是唯一的节点,而是符合条件的所有节点。比如在HTML文档里使用“/html/head/scrpt”就会把head里的所有script节点都取出来。
为了缩小定位范围,往往还需要增加过滤条件。过滤的方法就是用“[”“]”把过滤条件加上。比如在HTML文档里使用“/html/body/div[@id='main']”,即可取出body里id为main的div节点。
其中@id表示属性id,类似的还可以使用如@name, @value, @href, @src, @class….
而 函数text()的意思则是取得节点包含的文本。比如:<div>hello<p>world</p>< /div>中,用”div[text()='hello']“即可取得这个div,而world则是p的text()。
函数position()的意思是取得节点的位置。比如“li[position()=2]”表示取得第二个li节点,它也可以被省略为“li[2]”。
不过要注意的是数字定位和过滤 条件的顺序。比如“ul/li[5][@name='hello']”表示取ul下第五项li,并且其name必须是hello,否则返回空。而如果用 “ul/li[@name='hello'][5]”的意思就不同,它表示寻找ul下第五个name为”hello“的li节点。
此外,“*”可以代替所有的节点名,比如用”/html/body/*/span”可以取出body下第二级的所有span,而不管它上一级是div还是p或是其它什么东东。
而 “descendant::”前缀可以指代任意多层的中间节点,它也可以被省略成一个“/”。比如在整个HTML文档中查找id为“leftmenu”的 div,可以用“/descendant::div[@id='leftmenu']”,也可以简单地使用“ //div[@id='leftmenu']”。
至于“following-sibling::”前缀就如其名所说,表示同一层的下一个节点。”following-sibling::*”就是任意下一个节点,而“following-sibling::ul”就是下一个ul节点。
Python中利用xpath解析HTML的更多相关文章
- 利用XPath解析带有xmlns的XML文件
在.net中,编写读取xml 的程序中提示"未将对象引用设置到对象的实例",当时一看觉得有点奇怪.为什么在读取xml数据的时候也要实例化一个对象.google了才知道,xml文件中 ...
- (数据科学学习手札145)在Python中利用yarl轻松操作url
本文示例代码已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 大家好我是费老师,在诸如网络爬虫.web应用开发 ...
- julia与python中的列表解析.jl
julia与python中的列表解析.jl #=julia与python中的列表解析.jl 2016年3月16日 07:30:47 codegay julia是一门很年轻的科学计算语言 julia文档 ...
- Python中利用函数装饰器实现备忘功能
Python中利用函数装饰器实现备忘功能 这篇文章主要介绍了Python中利用函数装饰器实现备忘功能,同时还降到了利用装饰器来检查函数的递归.确保参数传递的正确,需要的朋友可以参考下 " ...
- python中利用matplotlib绘图可视化知识归纳
python中利用matplotlib绘图可视化知识归纳: (1)matplotlib图标正常显示中文 import matplotlib.pyplot as plt plt.rcParams['fo ...
- Python中的列表解析和生成器表达式
Python中的列表解析和生成器表达式 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.列表解析案例 #!/usr/bin/env python #_*_coding:utf-8 ...
- Python中利用原始套接字进行网络编程的示例
Python中利用原始套接字进行网络编程的示例 在实验中需要自己构造单独的HTTP数据报文,而使用SOCK_STREAM进行发送数据包,需要进行完整的TCP交互. 因此想使用原始套接字进行编程,直接构 ...
- python中利用队列asyncio.Queue进行通讯详解
python中利用队列asyncio.Queue进行通讯详解 本文主要给大家介绍了关于python用队列asyncio.Queue通讯的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细 ...
- 第14.12节 Python中使用BeautifulSoup解析http报文:使用select方法快速定位内容
一. 引言 在<第14.10节 Python中使用BeautifulSoup解析http报文:html标签相关属性的访问>和<第14.11节 Python中使用BeautifulSo ...
随机推荐
- Android(java)学习笔记243:多媒体之视频播放器
1.这里我们还是利用案例演示视频播放器的使用: (1)首先,我们看看布局文件activity_main.xml,如下: <RelativeLayout xmlns:android="h ...
- JPA事务回滚配置
<!-- 配置事务管理器 --> <bean id="transactionManager" class="org.springframework.or ...
- 解决zabbix图中出现中文乱码问题
我这周部署了zabbix监控服务器,但是配置过程中发现当有中文时,图中的中文会变成方块 如下图所示: 这个问题是由于zabbix的web端没有中文字库,我们最需要把中文字库加上即可 解决办法如下 1. ...
- Android MediaCodec 使用例子
Android MediaCodec 使用例子 下面的例子是使用MediaCodec 录制到文件的例子. 1 public class AvcEncoder { private MediaCodec ...
- C#中的占位符
当我们需要在屏幕上输出一句话的时候,如果不断的使用+来连接各个字符串,一是容易出错,二是代码显示的非常乱.这时候,占位符就能够发挥作用! 占位符: string name="张三" ...
- HTML5 Canvas Text文本居中实例
1.代码: <canvas width="700" height="300" id="canvasOne" class="c ...
- 黑马程序员-hashtable
散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构.也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度.这个映射函数叫做散列 ...
- CTE的使用
CTE在SQL2005后的版本提供,丰富了查询的表现形式,下面我们慢慢来看下CTE都能干什么 1.自我递归 ;WITH myaa AS ( SELECT num=1 UNION ALL SELECT ...
- PHP MySQL 预处理语句
PHP MySQL 预处理语句 预处理语句对于防止 MySQL 注入是非常有用的. 预处理语句及绑定参数 预处理语句用于执行多个相同的 SQL 语句,并且执行效率更高. 预处理语句的工作原理如下: 预 ...
- eclipse/myeclipse 变量名自动补全问题
原理是:在输入变量名后,去掉按下空格或=后,代码上屏 以前只知道alt+/调出assist,后来发现可以所有字母都激活content assist(8.1里有写).用起来果然很爽,但是eclipse ...