【Scrapy 框架】「版本2.4.0源码」选择器(Selectors)详解篇

全部源码解析文章索引目录传送门

【Scrapy 框架】版本 2.4.0 源码篇:全部配置目录索引

内容介绍

在抓取网页时,需要执行的最常见任务是从HTML源提取数据。

提取数据的方式有很多种根据自己的习惯就好。

BeautifulSoup是Python程序员中一个非常流行的Web抓取库,基于HTML代码的结构构造Python对象,并相当好地处理不好的标记,但它缺点是速度慢。

lxml是一个XML解析库(解析HTML),它使用基于ElementTree。(lxml不是Python标准库的一部分。)

Scrrapy有自己的提取数据的机制被称为Selectors,“选择”HTML文档的某些部分。

使用选择器

构建选择器

response 对象公开 Selector 实例上 .selector 属性

>>> response.selector.xpath('//span/text()').get()
'good'

使用XPath和CSS查询方式:response.xpath()和response.css()

>>> response.xpath('//span/text()').get()
'good'
>>> response.css('span::text').get()
'good'

文本构造方式

>>> from scrapy.selector import Selector
>>> body = '<html><body><span>good</span></body></html>'
>>> Selector(text=body).xpath('//span/text()').get()
'good'

构建response的HtmlResponse是TextResponse子类

>>> from scrapy.selector import Selector
>>> from scrapy.http import HtmlResponse
>>> response = HtmlResponse(url='http://example.com', body=body)
>>> Selector(response=response).xpath('//span/text()').get()
'good'

使用选择器

打开要解析的页面
在这里插入图片描述
构造一个XPath,用于选择title标记中的文本

>>> response.xpath('//title/text()')
[<Selector xpath='//title/text()' data='Example website'>]

提取文本数据调用选择器 .get() 或 .getall()

>>> response.xpath('//title/text()').getall()
['Example website']
>>> response.xpath('//title/text()').get()
'Example website'
>>> response.css('title::text').get()
'Example website'

.xpath()和.css()方法返回SelectorList实例,也可以快速嵌套数据

>>> response.css('img').xpath('@src').getall()
['image1_thumb.jpg',
 'image2_thumb.jpg',
 'image3_thumb.jpg',
 'image4_thumb.jpg',
 'image5_thumb.jpg']

提取第一个匹配的元素,使用 .get() 或者 .extract_first()

>>> response.xpath('//div[@id="images"]/a/text()').get()
'Name: My image 1 '

如果未抓取到对应数据元素

>>> response.xpath('//div[@id="not-exists"]/text()').get() is None
True

>>> response.xpath('//div[@id="not-exists"]/text()').get(default='not-found')
'not-found'

选择对应属性内容

>>> [img.attrib['src'] for img in response.css('img')]
['image1_thumb.jpg',
 'image2_thumb.jpg',
 'image3_thumb.jpg',
 'image4_thumb.jpg',
 'image5_thumb.jpg']
 
>>> response.css('img').attrib['src']
'image1_thumb.jpg'

对应选择的结果是唯一时

>>> response.css('base').attrib['href']
'http://example.com/'

构建图像url的几种方式

>>> response.xpath('//base/@href').get()
'http://example.com/'

>>> response.css('base::attr(href)').get()
'http://example.com/'

>>> response.css('base').attrib['href']
'http://example.com/'

>>> response.xpath('//a[contains(@href, "image")]/@href').getall()
['image1.html',
 'image2.html',
 'image3.html',
 'image4.html',
 'image5.html']

>>> response.css('a[href*=image]::attr(href)').getall()
['image1.html',
 'image2.html',
 'image3.html',
 'image4.html',
 'image5.html']

>>> response.xpath('//a[contains(@href, "image")]/img/@src').getall()
['image1_thumb.jpg',
 'image2_thumb.jpg',
 'image3_thumb.jpg',
 'image4_thumb.jpg',
 'image5_thumb.jpg']

>>> response.css('a[href*=image] img::attr(src)').getall()
['image1_thumb.jpg',
 'image2_thumb.jpg',
 'image3_thumb.jpg',
 'image4_thumb.jpg',
 'image5_thumb.jpg']

CSS选择器扩展

按照W3C标准,CSS选择器不支持选择文本节点或属性值。但在web抓取上下文中选择这些内容是非常重要的,因此scrapy(Parsel)实现非标准伪元素:

  1. 若要选择文本节点,使用 ::text
  2. 若要选择属性值,使用 ::attr(name) 属性的名称

title::text 选择后代的子文本节点

>>> response.css('title::text').get()
'Example website'

*::text 选择当前选择器上下文的所有子代文本节点

>>> response.css('#images *::text').getall()
['\n   ',
 'Name: My image 1 ',
 '\n   ',
 'Name: My image 2 ',
 '\n   ',
 'Name: My image 3 ',
 '\n   ',
 'Name: My image 4 ',
 '\n   ',
 'Name: My image 5 ',
 '\n  ']

foo::text 如果foo元素,但不包含文本(即文本为空)

>>> response.css('img::text').getall()
[]

>>> response.css('img::text').get()
>>> response.css('img::text').get(default='none')
'none'

a::attr(href) 选择href子代链接的属性

>>> response.css('a::attr(href)').getall()
['image1.html',
 'image2.html',
 'image3.html',
 'image4.html',
 'image5.html']

嵌套选择器

选择方法 (.xpath()或.css()) 返回相同类型的选择器列表

>>> links = response.xpath('//a[contains(@href, "image")]')
>>> links.getall()
['<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>']
>>> for index, link in enumerate(links):
...     href_xpath = link.xpath('@href').get()
...     img_xpath = link.xpath('img/@src').get()
...     print(f'Link number {index} points to url {href_xpath!r} and image {img_xpath!r}')
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'

选择元素属性

XPath语法

>>> response.xpath("//a/@href").getall()
['image1.html', 'image2.html', 'image3.html', 'image4.html', 'image5.html']

CSS选择器的扩展 (::attr(…)) 语法

>>> response.css('a::attr(href)').getall()
['image1.html', 'image2.html', 'image3.html', 'image4.html', 'image5.html']

.attrib 语法

>>> [a.attrib['href'] for a in response.css('a')]
['image1.html', 'image2.html', 'image3.html', 'image4.html', 'image5.html']

# 字典方式
>>> response.css('base').attrib
{
    
    'href': 'http://example.com/'}
>>> response.css('base').attrib['href']
'http://example.com/'

# 空结果
>>> response.css('foo').attrib
{
    
    }

带有正则表达式的选择器

Selector也有一个.re()使用正则表达式提取数据的方法。但与使用.xpath()或.css()方法,.re()返回字符串列表。所以你不能构造嵌套的.re()。

>>> response.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']

.get() .extract_first()) .re(),命名.re_first()。使用它仅提取第一个匹配字符串:

>>> response.xpath('//a[contains(@href, "image")]/text()').re_first(r'Name:\s*(.*)')
'My image 1'

extract() and extract_first()

.extract()和.extract_first() 对标 .get()和.getall()

SelectorList.get()SelectorList.extract_first() 相同

>>> response.css('a::attr(href)').get()
'image1.html'
>>> response.css('a::attr(href)').extract_first()
'image1.html'

SelectorList.getall()SelectorList.extract() 相同

>>> response.css('a::attr(href)').getall()
['image1.html', 'image2.html', 'image3.html', 'image4.html', 'image5.html']
>>> response.css('a::attr(href)').extract()
['image1.html', 'image2.html', 'image3.html', 'image4.html', 'image5.html']

Selector.get()Selector.extract() 相同

>>> response.css('a::attr(href)')[0].get()
'image1.html'
>>> response.css('a::attr(href)')[0].extract()
'image1.html'

列表方式操作Selector.getall()

>>> response.css('a::attr(href)')[0].getall()
['image1.html']

由于官网给出的实际内容在日常工作中很少用到,因此在专栏中会有一个实际应用检索列表供大家有选择性阅读。

猜你喜欢

转载自blog.csdn.net/qq_20288327/article/details/113483971