@[TOC]Python爬虫利器-XPath
Python爬虫利器-XPath
在新手使用正则表达式提取源代码中指定信息的时候,如果正则表达式编写不适宜,往往会匹配到网页中我们不需要的内容,这实际大大增加了信息筛选、清洗的成本。尺有所短,寸有所长,小编今天要介绍的是一个能和正则表达式媲美的页面文本信息提取利器——XPath。接下来,小编从实用的角度带大家学习XPath的相关知识。
1. 什么是XPath
XPath是XML Path的简称,它是一种用来确定XML(可扩展标记语言)文档中某部分位置的语言。XPath也是一种表达式语言,它基于XML的树状结构,可以用来在整个树中来寻找指定的节点。为方便理解,我们可以将它看成路径表达式:一个“文件夹”(标签)下有若干“子文件”(标签或字符串)。由于HTML文档本身就是一个标准的XML页面,因此我们可以使用XPath的语法来定位页面元素。
2. XPath元素定位方法
以下是我在网上找到的一个HTML:
<bookstore>
<a href="http://blog.csdn.net/qq_36148847">链接</a>
<title>Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</bookstore>
仔细观察该HTML,可将其视为bookstore“文件夹”(标签对)下面有几个“文件夹”(标签对),分别为a、title、author、year、price,而他们分别装着一个“文件”(字符串):“链接”、“Harry Potter”、“J K. Rowling”、“2005”和“29.99”。
下面我们介绍几个术语:在上面的例子中,bookstore元素是a、title、author、year 、price 元素的父,a、title、author、year 、price 元素是bookstore元素的子,a、title、author、year、 price 元素之间彼此是同胞,title元素的先辈是bookstore元素,bookstore元素的后代包含a元素和title元素等。
XPath是使用路径表达式的方法定位所需要的信息,下面是一些常用的表达式:
表达式 描述
/bookstore 从当前节点选取元素bookstore
//bookstore 从任意位置选取bookstore 元素
//div[@class=“header”] 从任意位置选取class属性是header的div 元素
/bookstore/a[1] 从当前节点选取bookstore元素下的第一个a元素
//* 从任意位置选取任意元素,即选取文档中的所有元素
/title/text() 从当前节点选取title元素的文本内容
. 选取当前节点
… 选取当前节点的父节点
运用这些表达式及组合,我们可以写出目标信息的路径表达式,如上面例子中我们想提取这本书的书名,已知它在bookstore元素下的title元素中,我们可以写成一种类似绝对路径的表达式:“/bookstore/title/text()”,当然写法很多,我们在下面的实操中具体讲解。
在使用XPath时,定位到的元素会以列表的形式返回,比如“/bookstore/*”会返回bookstore元素下的所有元素组成列表,每个元素的类型依然是lxml库中特有的“元素”类型,它有标签值(tag)、属性或者文本(text),可以通过调用相应的方法得到。
3.程序详解
3.1 简单入门
我们导入指定模块,并输入该HTML:
In[1]: from lxml import etree
In[2]: html ='''
<bookstore><a href="http://blog.csdn.net/qq_36148847">链接</a><title>Harry Potter</title><author>J K. Rowling</author><year>2005</year><price>29.99</price></bookstore>
'''
In[3]: sel= etree.HTML(html) #将网页源代码转换成XPath可以解析的格式
In[4]: bookstore=sel.xpath('//bookstore') #从任意位置提取bookstore元素
In[5]: print(type(bookstore))
Out[5]: <class 'list'>
In[6]: print(bookstore)
Out[6]: [<Element bookstore at 0x1a0ed3c0048>]
可以看出我们使用XPath方式提取后得到的数据类型为列表。
In[7]: for i in bookstore:
In[8]: print(i)
Out[8]: <Element bookstore at 0x1a0ed3c0048>
即使输出列表中的每个元素,依然只是返回“element XX at XXX”,它表示这是一个“元素”类型的变量。
3.2使用XPath定位元素
(1)不同方式得到title的信息
我们采用三种方式获得title的内容。Tag可以返回XPath解析后的对象的节点。Text方法是一种字符串方法,可以返回对应的文本内容。
**① 方法一:**从任意位置选取bookstore下的子节点title,得到title列表中的第一个元素的节点,输出其文本内容:
In[9]: title=sel.xpath('//bookstore/title')
In[10]: print(title[0].text)
Out[10]: Harry Potter
**② 方法二:**对全文xpath对象,在任意位置选取bookstore节点下的title节点的文本内容
In[11]: title1=sel.xpath('//bookstore/title/text()')
In[12]: print(title1)
Out[12]: ['Harry Potter']
**③ 方法三(相对路径法):**对bookstore的第一个xpath对象,在当前节点下选取title子节点的文本内容
In[13]: title2=bookstore[0].xpath('./title/text()')
In[14]: print(title2)
Out[14]: ['Harry Potter']
可以看出,以上三种方法都可以得到title元素下的文本内容。第一种方法获得的是str对象,后面两种方法返回的是列表。
同理,我们也可以采用三种方式得到author的文本内容,程序如下:
author1=sel.xpath('//*/author/text()') #对全文xpath对象,在任意位置选取第一层节点下的author子节点,提取出文本内容
author2=title[0].xpath('../author/text()') #对title的第一个xpath对象,在父节点下选取author子节点,提取出文本内容
author3=sel.xpath('//a[@href="http://blog.csdn.net/qq_36148847"]/../author/text()') #在任意位置寻找到href属性是http://blog.csdn.net/qq_36148847的a节点,在它的父节点下选取author子节点,提取出文本内容
(2)使用通配符,获取所有文本信息
我们使用*代表任意节点,提取所有节点的文本内容。
In[15]: all_text=sel.xpath('//bookstore/*/text()')
In[16]: for unittext in all_text:
In[17]: print(unittext)
Out[17]: 链接
Harry Potter
J K. Rowling
2005
29.99
4.结语
以上就是XPath的基本用法,只要找到合适的规律方法,就能帮你在重重迷雾中拨云见日。是不是很简单呢?以后如果遇到正则表达式不能解决的问题,可以试试XPath哦。