开发环境为 Python3.6,Scrapy 版本 2.4.x ,爬虫项目全部内容索引目录
看懂Python爬虫框架,所见即所得一切皆有可能
本章带你学习基于 Python3 的 Scrapy 爬虫框架 中数据爬取过程中从HTML源中如何提取数据。
提取数据的方式有很多种根据自己的习惯就好。
代码内容基于「Scrapy 爬虫框架」源码版本 2.4.0 ,更新内容会进行标记说明对应版本。
# 在处理response对象可以直接使用selector定位属性获取数据
>>> response.selector.xpath('//span/text()').get()
'good'
# response.xpath()方式
>>> response.xpath('//span/text()').get()
'good'
# response.css()方式
>>> response.css('span::text').get()
'good'
# 文本构造方式
>>> from scrapy.selector import Selector
>>> body = 'good'
>>> Selector(text=body).xpath('//span/text()').get()
'good'
# 基于TextResponse类的HtmlResponse处理response
>>> 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']
按照W3C标准,CSS选择器不支持选择文本节点或属性值。但在web抓取上下文中选择这些内容是非常重要的,因此scrapy(Parsel)实现非标准伪元素:
# 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()
['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):
... 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'
# 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']