在网页节点中,可以定义id、class或其他属性。节点间有层次关系,网页中要通过XPath或CSS选择器定位一个或多个节点。在页面解析时,可利用XPath或CSS选择器提取某个节点,再调用相应方法获取它的正文内容或者属性,就可提取到想要的信息。在python中常用的解析库有lxml、Beautiful Soup、pyquery等。使用这些库可以很大程度上提高效率。

一     使用XPath解析库

XPath,全称XML Path Language,即XML路径语言,是一门在XML文档中查找信息的语言。适用于XML文档和HTML文档搜索。

XPath的选择功能十分强大,提供了非常简洁明了的路径选择表达式。另外,还提供了超过100个内建函数,用于字符串、数值、时间的匹配以及节点、序列的处理等。几乎所有想要定位的节点,都可以用XPath来选择。

XPath于1999年11月16日成为W3C标准,被设计为供XSLT、XPointer以及其他XML解析软件使用,更多的文档可以访问其官方网站:https://www.w3.org/TR/xpath/。

XPath对应的库是lxml库。

1、 XPath的常用规则
下表是XPath的几个常用规则
表4-1 XPath常用规则
表达式               描述
nodename        选取此节点的所有子节点
/                        从当前节点选取直接子节点
//                      从当前节点选取子孙节点
.                        选取当前节点
..                       选取当前节点的父节点
@                     选取属性

下面是XPath的匹配示例,如下所示:
//title[@lang='eng']
这个实例是XPath规则 ,代表选择所有名称为title,同时属性lang的值为eng的节点。

2、 第一个lxml库实例

下面用一个简单的代码了解下XPath对网页的解析过程,代码如下:

 1 from lxml import etree
 2 text = '''
 3 <div>
 4     <ul>
 5         <li class="item-0"><a href="link1.html">first item</a></li>
 6         <li class="item-1"><a href="link2.html">second item</a></li>
 7         <li class="item-inactive"><a href="link2.html">third item</a></li>
 8         <li class="item-1"><a href="link4.html">fourth item</a></li>
 9         <li class="item-0"><a href="link5.html">fifth item</a>
10     </ul>
11 </div>
12 '''
13 html = etree.HTML(text)         # 调用HTML类初始化,自动修正HTML文本
14 result = etree.tostring(html)   # 输出修正后的HTML代码,是bytes类型
15 print(result.decode("utf-8"))

在上面代码中,首先导人lxml库的etree模块,然后声明了一段HTML文本,调用HTML类进行初始化,这样就成功构造了一个XPath解析对象。注意HTML文本中的最后一个li节点是没有闭合的,但是etree模块可以自动修正HTML文本。

调用tostring()方法即可输出修正后的HTML代码,结果是bytes类型。利用decode()方法将其转成str类型,在输出结果中,经过处理后,li节点的标签被补全,并且还自动添加了body、html节点。输出结果如下:

 1 <html><body><div>
 2     <ul>
 3         <li class="item-0"><a href="link1.html">first item</a></li>
 4         <li class="item-1"><a href="link2.html">second item</a></li>
 5         <li class="item-inactive"><a href="link2.html">third item</a></li>
 6         <li class="item-1"><a href="link4.html">fourth item</a></li>
 7         <li class="item-0"><a href="link5.html">fifth item</a>
 8     </li></ul>
 9 </div>
10 </body></html>

还可以直接读取文本文件进行解析,示例如下:
from lxml import etree
html = etree.parse('./test.html', etree.HTMLParser())
result = etree.tostring(html)
print(result.decode('utf-8'))

上面代码中test.html的内容是前面例子中的HTML代码。这次的输出结果中多了DOCTYPE的声明,对解析没有任何影响。输出如下所示:

 1 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
 2 <html><body><div>&#13;
 3     <ul>&#13;
 4         <li class="item-0"><a href="link1.html">first item</a></li>&#13;
 5         <li class="item-1"><a href="link2.html">second item</a></li>&#13;
 6         <li class="item-inactive"><a href="link2.html">third item</a></li>&#13;
 7         <li class="item-1"><a href="link4.html">fourth item</a></li>&#13;
 8         <li class="item-0"><a href="link5.html">fifth item</a>&#13;
 9     </li></ul>&#13;
10 </div></body></html>

 

 

3、 所有节点
可用 // 开头的XPath规则来选取所有符合要求的节点。用前面的HTML文本,如果要选取所有节点,可以这样实现:

 1 from lxml import etree
 2 html = etree.parse('./test.html', etree.HTMLParser())
 3 result = html.xpath('//*')  # *表示选取所有节点
 4 print(result)   # 输出如下所示:
 5 [<Element html at 0x2555e650208>, <Element body at 0x2555e650308>,
 6 <Element div at 0x2555e650348>, <Element ul at 0x2555e650388>,
 7 <Element li at 0x2555e6503c8>, <Element a at 0x2555e650448>,
 8 <Element li at 0x2555e650488>, <Element a at 0x2555e6504c8>,
 9 <Element li at 0x2555e650508>, <Element a at 0x2555e650408>,
10 <Element li at 0x2555e650548>, <Element a at 0x2555e650588>,
11 <Element li at 0x2555e6505c8>, <Element a at 0x2555e650608>]
View Code

相关文章: