本文主要参照scrapy最新官方文档编写。
官方文档直达链接:https://docs.scrapy.org/en/latest/topics/selectors.html
大部分人可能喜欢使用以下三个解析器对网页进行解析:
- BeautifulSoup:使用方便,支css选择器,但它有个不可忽视的缺点:慢。
- lxml解析库:采用xpath解析,速度快。
- pyquery:它提供了和jQuery类似的语法来解析HTML文档,支持CSS选择器
- re:正则表达式是万能通用的,不过使用它的头疼度我就不用过多解释了。。
但对于某些网页结构俩说,单一的解析方法也许并不是那么方便,如果想嵌套xpath与css选择器甚至正则表达式呢?
好的,你需要了解学习一下强大的Selector选择器,它不仅是能在scrapy框架内部使用,也可导入到其他脚本爬虫中。
而且这更适合经常使用scrapy框架的人的解析习惯。
这里着重介绍在外部使用Selector的方法,(scrapy内部使用无需先实例化,其余操作均相同):
1.导入scrapy,实例化对象
- 首先导入包,传入网页响应实例化Selector的对象,使用xpath或css解析器解析网页:
from scrapy import Selector
body = 'good'
selector = Selector(text=body)
>>> selector.xpath('//span/text()').get()
'good'
>>> selector.css('span::text').get()
'good'
2.提取文本数据,
- 必须调用选择器.get() 或.getall()方法,如下所示:
from scrapy import Selector
body ="""
Example website
"""
>>>selector = Selector(text=body)
>>>selector.xpath('//title/text()').getall()
['Example website']
>>>selector.xpath('//title/text()').get()
'Example website'
.get()总是返回一个结果; 如果有多个匹配,则返回第一个匹配的内容; 如果没有匹配项,则返回None。.getall()返回包含所有结果的列表。
请注意,CSS选择器可以使用CSS3伪元素选择文本或属性节点:
>>> selector.css('title::text').get()
'Example website'
3.选择器返回对象格式
- 正如你所看到的,
.xpath()
和.css()
方法返回一个SelectorList
实例,这是新的选择列表。此API可用于快速选择嵌套数据:
>>> selector.css('img').xpath('@src').getall()
['image1_thumb.jpg',
'image2_thumb.jpg',
'image3_thumb.jpg',
'image4_thumb.jpg',
'image5_thumb.jpg']
如果只想提取第一个匹配的元素,可以调用选择器.get()
(或.extract_first()
这是以前版本的方法):
>>> selector.xpath('//div[@id="images"]/a/text()').get()
'Name: My image 1 '
4.返回None
- 如果解析式没有找到元素,则返回:
None
:
>>> selector.xpath('//div[@id="not-exists"]/text()').get() is None
True
- 当你不希望返回的数据是None时,可以提供默认返回值作为参数,以代替None:
>>> selector.xpath('//div[@id="not-exists"]/text()').get(default='not-found')
'not-found'
5.css选择器的.attrib
- 可以使用css选择器的
.attrib
而非xpath的@src采取列表推导式来获取网页结构某属性值:
>>> [img.attrib['src'] for img in selector.css('img')]
['image1_thumb.jpg',
'image2_thumb.jpg',
'image3_thumb.jpg',
'image4_thumb.jpg',
'image5_thumb.jpg']
- 作为快捷方式,.attrib也可以直接在SelectorList上使用; 它返回第一个匹配元素的属性,当仅预期单个结果时,例如当通过id选择或在网页上选择唯一元素时,这是最有用的::
>>> selector.css('img').attrib['src']
'image1_thumb.jpg'
6.常用链接提取示例
- 现在我们将获得基本URL和一些图像链接:
>>> selector.xpath('//base/@href').get()
'http://example.com/'
>>> selector.css('base::attr(href)').get()
'http://example.com/'
>>> selector.css('base').attrib['href']
'http://example.com/'
>>> selector.xpath('//a[contains(@href, "image")]/@href').getall()
['image1.html',
'image2.html',
'image3.html',
'image4.html',
'image5.html']
>>> selector.css('a[href*=image]::attr(href)').getall()
['image1.html',
'image2.html',
'image3.html',
'image4.html',
'image5.html']
>>>selector.xpath('//a[contains(@href, "image")]/img/@src').getall()
['image1_thumb.jpg',
'image2_thumb.jpg',
'image3_thumb.jpg',
'image4_thumb.jpg',
'image5_thumb.jpg']
>>>selector.css('a[href*=image] img::attr(src)').getall()
['image1_thumb.jpg',
'image2_thumb.jpg',
'image3_thumb.jpg',
'image4_thumb.jpg',
'image5_thumb.jpg']
7.CSS选择器的扩展:Selector支持一些w3c标准的拓展
- 要选择文本节点,请使用 ::text
- 选择属性值,用::attr(name)那里的名字是你想要的价值属性的名称
8.嵌套选择器
- 当解析后不调用.get()或.getall()方法时,将会返回一个选择器列表,我们可在后续继续对该对象进行选择器的嵌套调用:
>>> links = selector.xpath('//a[contains(@href, "image")]')
>>> links.getall()
['Name: My image 1
',
'Name: My image 2
',
'Name: My image 3
',
'Name: My image 4
',
'Name: My image 5
']
>>> for index, link in enumerate(links):
... args = (index, link.xpath('@href').get(), link.xpath('img/@src').get())
... print('Link number %d points to url %r and image %r' % args)
Link number 0 points to url 'image1.html' and image 'image1_thumb.jpg'
Link number 1 points to url 'image2.html' and image 'image2_thumb.jpg'
Link number 2 points to url 'image3.html' and image 'image3_thumb.jpg'
Link number 3 points to url 'image4.html' and image 'image4_thumb.jpg'
Link number 4 points to url 'image5.html' and image 'image5_thumb.jpg'
9.使用正则表达式选择器
-
Selector
还有一种.re()
使用正则表达式提取数据的方法。但是,与使用.xpath()
或.css()
methods 不同,.re()
返回unicode字符串列表。所以你不能构造嵌套的.re()
调用。
以下是用于从上面的[HTML代码中提取图像名称的示例:
>>> selector.xpath('//a[contains(@href, "image")]/text()').re(r'Name:\s*(.*)')
['My image 1',
'My image 2',
'My image 3',
'My image 4',
'My image 5']
- 使用
.re_first()
提取第一个匹配的字符串:
>>> selector.xpath('//a[contains(@href, "image")]/text()').re_first(r'Name:\s*(.*)')
'My image 1'
10.关于extract()和extract_first()的使用
- Scrapy仍然支持这些方法,没有计划弃用它们。Scrapy使用文档现在使用.get()和 .getall()方法编写,你可以随自己喜好选用,但显然.get()和 .getall()更简洁。
11.本文未详细深入讲解css、xpath选择器本身语法,需要自己再去w3c学习。
完。