前面我们在写爬取豆瓣读书内容示例中提到了XPath,本文就详细介绍下在爬虫中如何使用XPath选择器,掌握本文中的内容,将解决98%在爬虫中利用XPath提取元素的需求。
一、XPath简介
XPath 是一门在 XML 或HTML文档中查找信息的语言。XPath 用于在 XML 和HTML文档中通过元素和属性进行导航。
什么是 XPath?
XPath 使用路径表达式在XML和HTML文档中进行导航。
XPath 包含一个标准函数库。
XPath 是一个 W3C 标准。
二、XPath的节点关系
节点(Node)是XPath 的术语。
1)父节点(Parent)
每个元素以及属性都有一个父。在“(图一)html”的例子中,book 元素是 title、author、year 以及 price 元素的父。
2)子节点(Children)
元素节点可有零个、一个或多个子。在“(图一)html”的例子中,title、author、year 以及 price 元素都是 book 元素的子。
3)同胞节点(Sibling)
拥有相同的父的节点。在“(图一)html”的例子中,title、author、year 以及 price 元素都是同胞。
4)先辈节点(Ancestor)
某节点的父、父的父,等等。在“(图一)html”的例子中,title 元素的先辈是 book 元素和 bookstore 元素,
5)后代节点(Descendant)
某个节点的子,子的子,等等。在“(图一)html”的例子中,bookstore 的后代是 book、title、author、year 以及 price 元素。
三、XPath的语法
XPath 使用路径表达式在 XML 和HTML文档中选取节点。节点是通过沿着路径或者 step 来选取的。
下面列出了最有用的路径表达式,掌握了这些表达式,可以完成89%的爬虫提取元素的需求。我们编写了将近一百个网站的各种各样的数据提取的XPath代码所涉及到的语法都包含在下面的表格中啦。
article 选取所有article元素的所有子节点
/article 选取根元素article
article/a 选取所有属于article的子元素的a元素
//div/ 选取所有div子元素(不论出现在文档任何地方)
article//div 选取所有属于article元素的后代的div元素,不管它出现在article下的任何位置
//@class 选取所有名为class的属性
/article/div[1] 选取属于article子元素的第一个div元素
/article/div[last()] 选取属于article子元素的最后一个div元素
/article/div[last()-1] 选取属于article子元素的倒数第二个div元素
//div[@class] 选取所有拥有class属性的div元素
//div[@class='article'] 选取所有class属性为article的div元素
//div[@class='article']/text() 选取所有class属性为article的div元素下的text值
/div/* 选取属于div元素的所有子节点
//* 选取所有元素
//div[@*] 选取所有带属性的div元素
//div/a|//div/p 选取所有div元素下的a和p元素
//span|//ul 选取文档中的span和ul元素
article/div/p|//span 选取所有属于article元素的div元素的p元素以及文档中所有的span元素
四、使用XPath提取豆瓣读书书籍标题的示例
我们还是以获取豆瓣读书的书籍信息为例来说明XPath的使用。
我们这里通过3种方法来提取这个书籍的标题值。
1)方法一:从html开始一层一层往下找,使用Firefox浏览器自带的复制XPath功能使用的就是这个方式。
re1_selector = sel.xpath('/html/body/div[3]/div[1]/div/div[2]/ul/li[1]/div/h2/a/text()').extract()[0]
2)方法二:找到特定的id元素,因为一个网页中id是唯一的,所以再基于这个id往下找也是可以提取到想要的值,使用Chrome浏览器自带的复制XPath功能使用的就是这个方式。
re2_selector = sel.xpath('//*[@id="content"]/div/div[2]/ul/li[1]/div/h2/a/text()').extract()[0]
3)方法三:找到特定的其他非id元素,保障这个非id元素在你获取的规则中是唯一的,再基于这个非id元素往下找。
re3_selector = sel.xpath('//ul[@class="cover-col-4 clearfix"]/li[1]/div/h2/a/text()').extract()[0]
最后我们执行,发现这3种方法都是可以正确获取到“百年法”这个书籍标题。