本文介绍Scrapy中选择器的用法。
可以通过官方文档获取更为详细的内容。
简介
在抓取网页时,爬虫需要执行的最常见任务是从HTML源提取数据。
有几个库可用于实现此目的:
- BeautifulSoup是Python程序员中非常流行的Web抓取库,它根据HTML代码的结构构造一个Python对象,并且合理地处理坏标记,但它有一个缺点:它很慢。
- lxml是一个XML解析库(也可以解析HTML),它使用基于ElementTree的pythonic API。(lxml不是Python标准库的一部分。)
Scrapy带有自己的提取数据机制。它们被称为选择器,因为它们“选择”由XPath或CSS表达式指定的HTML文档的某些部分。
XPath是一种用于在XML文档中选择节点的语言,也可以与HTML一起使用。
CSS是一种将样式应用于HTML文档的语言。它定义选择器以将这些样式与特定HTML元素相关联。
Scrapy选择器是在lxml库上构建的,这意味着它们在速度和解析准确性方面非常相似。
选择器测试网址:https://doc.scrapy.org/en/latest/_static/selectors-sample1.html
下面使用这个网址来练习一下选择器的用法。
这个网址的html代码长这样:
<html>
<head>
<base href='http://example.com/' />
<title>Example website</title>
</head>
<body>
<div id='images'>
<a href='image1.html'>Name: My image 1 <br /><img src='image1_thumb.jpg' /></a>
<a href='image2.html'>Name: My image 2 <br /><img src='image2_thumb.jpg' /></a>
<a href='image3.html'>Name: My image 3 <br /><img src='image3_thumb.jpg' /></a>
<a href='image4.html'>Name: My image 4 <br /><img src='image4_thumb.jpg' /></a>
<a href='image5.html'>Name: My image 5 <br /><img src='image5_thumb.jpg' /></a>
</div>
</body>
</html>
网页长这样:
开始测试
首先在命令行中使用shell命令,并且传入该网址,进入命令行交互模式:
scrapy shell https://doc.scrapy.org/en/latest/_static/selectors-sample1.html
在控制台中显示了可用的scrapy变量。
使用选择器
接下来查看selector:
response.selector
selector是scrapy内置的一个选择器类。利用这个类,我们可以进行许多数据的提取。
由于我们正在处理HTML,因此选择器将自动使用HTML解析器。
因此,通过查看该页面的HTML代码,让我们构建一个XPath来选择title标签内的文本:
response.selector.xpath('//title/text()')
返回结果是一个list(其中只有一个元素:selector这个对象),内容就是selector。
如果用.extract_first()方法,就可以直接输出里面的data了。
上面介绍的是使用xpath进行选择,另一种方法是通过CSS:
response.selector.css('title::text').extract_first()
两种方法都是可以的。
注意到,上面每次都要加上“selector”。其实是可以把它省略掉的,因为scrapy中,提供了两个快捷方式response.xpath()和response.css()。也就是说,上面的命令可以这样写,效果是一样的:
response.xpath('//title/text()').extract_first()
response.css('title::text').extract_first()
获取图片
我们想拿到id=images这个div里面所有的图片信息——
可以先通过xpath,拿到这个div:
response.xpath('//div[@id="images"]')
或者可以直接调用CSS,选择里面所有的imgs标签:
response.xpath('//div[@id="images"]').css('img')
可以看到由selector组成的list,其中每个元素都是一个selector。
接下来如何提取里面的数据呢?
首先通过css中加入::attr(属性名)可以获得属性。(本例中,属性名应该是src)
response.xpath('//div[@id="images"]').css('img::attr(src)')
要获取内容,还要再后面加上extract()方法:
response.xpath('//div[@id="images"]').css('img::attr(src)').extract()
相当于从selector中拿出src这个属性(返回一个list),然后使用extract()提取出了实际的数据值。
当然,如果src有多个内容,我们可以通过extract_first()获取第一个内容:
response.xpath('//div[@id="images"]').css('img::attr(src)').extract_first()
extract()可以提供默认返回值作为参数,以代替None(未查找到的情况):
response.xpath('//div[@id="not-exists"]/text()').extract_first(default='not-found')
获取超链接
现在我们来选择一下超链接,从图中可以看到,超链接是在href这个属性里的:
使用命令:
response.xpath('//a/@href')
同样用extract提取:
当然也可以用CSS代替:
response.css('a::attr(href)')
两种方法都差不多,可以自行选择。
获取文本
两种方法:
response.xpath('//a/text()').extract()
response.css('a::text').extract()
更高级的选项
如果我们想要查找属性名称包含image的所有的超链接可以使用contains选项,第一个参数是属性名,第二个属性是要查找的值
response.xpath('//a[contains(@href,"image")]/@href').extract()
CSS的写法:
response.css('a[href*=image]::attr(href)').extract()
假如我们要选择所有a标签里的img里面的src属性,用上contains:
response.xpath('//a[contains(@href,"image")]/img/@src').extract()
CSS:
注意[]之后要有空格
response.css('a[href*=image] img::attr(src)').extract()
正则表达式
Selector还有一种使用正则表达式提取数据的方法——.re()
假如我们要提取文本中冒号后的内容:
直接使用text获取的是所有的文本,那么我们可以使用正则表达式:
response.css('a::text').re('Name\:(.*)')
注意,\用来对:进行转义。
如图,成功取得了冒号后的内容。
与extract()方法类似,re也提供了取得列表中第一个元素的方法:re_first()
response.css('a::text').re_first('Name\:(.*)')
进一步地,可以使用strip()方法,去掉返回结果中前后的空格:
response.css('a::text').re_first('Name\:(.*)').strip()
小结
response为我们提供了几个提取方法:
- xpath
- CSS
- re
返回的结果都是Selector类型,可以进行嵌套循环。
(a) 对css来说:
- 获取a标签中的文本内容:
response.css('a::text')
- 获取a标签中的某个属性:
response.css('a::attr(属性)')
(b)对xpath来说:
- 获取a标签中的文本内容:
response.xpath('//a/text()')
- 获取a标签中的某个属性:
response.xpath('//a/@href')
两种选择方法,写法不同,效果类似。
要从selector变为数据,则在后面加上.extract()
或 .extract()_first()
或.extract()[x](x为list中元素的下标)
如果要提取更具体的信息,可以用正则表达式的方法,在后面加上 .re() 或 .re()_first 进行嵌套选择。