即使我们了解了HTML的树结构,要设法解析这棵树以获取文本内容,也将是一个十分艰巨的任务。好消息是,已经有人替我们实现了这些功能,通过一种被称为XPath的语言,就可以轻松地定位并提取元素、属性和文本。Scrapy爬虫框架中,也引入了XPath语言来定位和提取数据。
XPath(XML Path Language,XML路径语言),是一门在XML文档中查找信息的语言。HTML与XML结构类似,也可以在HTML中查找信息。
XPath使用路径表达式来选取HTML文档中的节点或者节点集。这些路径表达式和我们在常规的计算机文件系统中看到的表达式非常相似。
例如,在Windows系统中,要指明桌面上的文件hello.py的路径,通常可以写成C:\Users\tao\Desktop\hello.py,从C盘开始,使用反斜杠(\)逐级向下查找,直到找到最终的目标。如表2-2中列举了常用的XPath路径表达式。
表2-2 XPath常用路径表达式
有计算机基础的读者对诸如:斜杠(/)、点(.)、两点(..)的用法一定不会陌生。即使不熟悉也没关系,因为XPath的语法实在太简单了。下面通过一些实例来加深对XPath用法的理解。
还是以电影排行的HTML文档为例,使用XPath提取页面信息。HTML代码和显示页面,如图2-10所示。
图2-10 电影排行代码和显示页面
1.安装lxml库
使用XPath之前,要先安装Python的lxml库。lxml库是一个HTML/XML的解析器。安装方法非常简单,在命令行中输入以下命令即可。
>pip install lxml
2.导入lxml库
提取数据之前,要先导入lxml库的etree模块,再使用etree读取movies.html文件,生成一个节点树的对象,代码如下:
#导入lxml库的etree模块 from lxml import etree #解析movies.html文件,返回一个节点树的对象 html_selector = etree.parse("movies.xhtml",etree.HTMLParser())
节点树的对象生成后,就可以使用XPath抽取数据了。
3.获取html元素
使用斜杠(/)从根节点开始获取html元素。
#获取根节点html的元素 root = html_selector.xpath("/html") print(root)
运行结果如下:
[<Element html at 0x1a1a9395948>]
可以看出,返回的root是一个列表,列表中存储了一个Element(元素)类型的对象,对象中节点的名称为html。
4.获取title元素
可以使用斜杠(/)从根节点开始逐层查找元素的子节点。
#斜杠(/)获取节点title title = html_selector.xpath("/html/head/title") print(title)
运行结果如下:
[<Element title at 0x1a1a9395a48>]
需要注意的是,斜杠(/)在起始位置时,代表的是从根节点开始查找,其他位置代表查找子节点。
5.获取title的文本
可以使用text()获取节点title中的文本。
#text()获取节点title的文本 title_name = html_selector.xpath("/html/head/title/text()") print(title_name)
运行结果如下:
['电影排行']
6.获取所有电影名称
电影名称所在的p节点相对根节点很远,如果从根节点逐层往下查找,XPath的表达式就会很长,如/html/body/div/div/p/text()。使用双斜杠(//)可以不考虑位置,获取页面中所有符合规则的子孙节点。
movie_name = html_selector.xpath("//p/text()") print(movie_name)
运行结果如下:
['1.肖申克的救赎', '2.霸王别姬']
代码使用了双斜杠(//)抽取出页面中所有节点p的文本。注意抽取出来的所有数据,均是保存于列表中的。
当然,双斜杠(//)也可以放在路径表达式的中间,代码如下:
name = html_selector.xpath("/html//div[@id='content']/h1/text()")
运行结果如下:
['1.肖申克的救赎', '2.霸王别姬']
7.获取网页的编码格式
有时要获取的信息保存在属性中。例如,页面的编码格式就是在meta标签的charset属性中。可以使用“@属性名”的方式获取属性值。
#使用@获取属性的值 meta = html_selector.xpath("//meta/@charset") print(meta)
运行结果如下:
['UTF-8']
在爬虫中,经常使用@href获取超链接。
8.获取div的id属性值
通过斜杠(/)或双斜杠(//)可以查找子节点或子孙节点。那么如何通过子节点,查找父节点呢?可以用两点(..)来实现。
attr = html_selector.xpath("//h1/../@id") print(attr)
运行结果如下:
['content']
h1的后面是两点(..),即定位到h1的父节点<div id="content">,再使用@id获取属性id的值。
有时需要查找某个特定的节点或者包含某个指定值的节点,如获取属性id为content的div元素,或者获取第一个p节点的文本等,如果使用XPath路径表达式,实现起来就比较困难,这时就需要用到谓语了。谓语被嵌在方括号([ ])中,用于查找特定节点或指定值的节点。如表2-3中列举了一些常用的带谓语的路径表达式(还是以电影排行的HTML文档为例)。
表2-3 常用的带谓语的路径表达式
XPath的功能非常强大,内置函数也很丰富,熟练使用,能大大提高HTML信息的提取效率。在Scrapy爬虫中,也是主要使用XPath定位和提取数据。更多XPath的用法,可以参考w3cschool( http://www.w3school.com.cn/xpath/index.asp )。