小白学 Python 爬虫(35):爬虫框架 Scrapy 入门基础(三) Selector 选择器

人生苦短,我用 Python
前文传送门:
小白学 Python 爬虫(2):前置准备(一)基本类库的安装
小白学 Python 爬虫(3):前置准备(二)Linux基础入门
小白学 Python 爬虫(4):前置准备(三)Docker基础入门
小白学 Python 爬虫(6):前置准备(五)爬虫框架的安装
小白学 Python 爬虫(10):Session 和 Cookies
小白学 Python 爬虫(11):urllib 基础使用(一)
小白学 Python 爬虫(12):urllib 基础使用(二)
小白学 Python 爬虫(13):urllib 基础使用(三)
小白学 Python 爬虫(14):urllib 基础使用(四)
小白学 Python 爬虫(15):urllib 基础使用(五)
小白学 Python 爬虫(16):urllib 实战之爬取妹子图
小白学 Python 爬虫(17):Requests 基础使用
小白学 Python 爬虫(18):Requests 进阶操作
小白学 Python 爬虫(21):解析库 Beautiful Soup(上)
小白学 Python 爬虫(22):解析库 Beautiful Soup(下)
小白学 Python 爬虫(23):解析库 pyquery 入门
小白学 Python 爬虫(26):为啥买不起上海二手房你都买不起
小白学 Python 爬虫(27):自动化测试框架 Selenium 从入门到放弃(上)
小白学 Python 爬虫(28):自动化测试框架 Selenium 从入门到放弃(下)
小白学 Python 爬虫(29):Selenium 获取某大型电商网站商品信息
小白学 Python 爬虫(31):自己构建一个简单的代理池
小白学 Python 爬虫(32):异步请求库 AIOHTTP 基础入门
小白学 Python 爬虫(33):爬虫框架 Scrapy 入门基础(一)
小白学 Python 爬虫(34):爬虫框架 Scrapy 入门基础(二)
引言
我们之前有介绍过通过 pyquery 、 Beautiful Soup 、 lxml 来提取网页数据。
但是在 Scrapy 中,同样也提供了自己独有的数据提取方式,即 Selector(选择器)。Selector 是基于 lxml 来构建的,支持 XPath 选择器、CSS 选择器以及正则表达式,功能全面,解析速度和准确度非常高。
独立使用
Scrapy Selectors 是 Parsel 库的包装。包装的目的是提供与 Scrapy Response 对象的更好的集成。
Parsel 是一个独立的 Web 抓取库,无需 Scrapy 即可使用。它在后台使用 lxml 库,并在 lxml API 之上实现了一个简单的 API 。这意味着 Scrapy 选择器的速度和解析精度与 lxml 非常相似。
我们可以写一个简单的示例代码来测试一下 Selectors 的单独使用。
from scrapy import Selector
body = '<html><head><title>Hello Python</title></head></html>'
selector = Selector(text=body)
title = selector.xpath('//title/text()').extract_first()
print(title)
执行结果如下:
Hello Python
这个简单的示例我们并没有在 Scrapy 框架中执行,而是把 Scrapy 中的 Selector 单独拿出来使用了。
Selector 的使用同其他解析库类似,如果方便的话,我们也可以在其他项目中直接使用 Selector 来提取数据。
Scrapy Shell
由于 Selector 主要是与 Scrapy 结合使用,如 Scrapy 的回调函数中的参数 response 直接调用 xpath() 或者 css() 方法来提取数据,所以在这里我们借助 Scrapy shell 来模拟 Scrapy 请求的过程,来讲解相关的提取方法。
这里我们借助官方文档的示例进行演示。
https://docs.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>
首先,让我们开启 Scrapy shell,在命令行输入如下命令:
scrapy shell https://docs.scrapy.org/en/latest/_static/selectors-sample1.html
这时,我们进入了 Scrapy Shell 模式,其实就是 Scrapy 发起了一次请求,然后把一些可操作的变量传递给我们:

Xpath 选择器
目前我们在 Scrapy shell 之中,这里我们主要操作的对象是 response 。
response 有一个属性是 selector ,我们可以通过调用 response.selector.xpath 对数据进行获取,同时, Scrapy 为我们提供了两个更加简洁的方法, response.xpath() 和 response.css() ,这两个方法完全等同于 response.selector.xpath() 和 response.selector.css() 。
出于写法上的简便考虑,小编后续的代码将全部使用 response.xpath() 和 response.css() 。
首先,我们简单的获取一下 a 标签:
>>> result = response.xpath('//a')
>>> result
[<Selector xpath='//a' data='<a href="image1.html">Name: My image ...'>,
<Selector xpath='//a' data='<a href="image2.html">Name: My image ...'>,
<Selector xpath='//a' data='<a href="image3.html">Name: My image ...'>,
<Selector xpath='//a' data='<a href="image4.html">Name: My image ...'>,
<Selector xpath='//a' data='<a href="image5.html">Name: My image ...'>]
>>> type(result)
<class 'scrapy.selector.unified.SelectorList'>
这里我们获取到的结果是由 Selector 组成的列表: SelectorList 。
它的类型是 scrapy.selector.unified.SelectorList 。
SelectorList 和 Selector 都可以继续调用 xpath() 和 css() 等方法来进一步提取数据。
接着上面的例子,我们继续尝试获取 a 标签中的 img 标签:
>>> result.xpath('./img')
[<Selector xpath='./img' data='<img src="image1_thumb.jpg">'>,
<Selector xpath='./img' data='<img src="image2_thumb.jpg">'>,
<Selector xpath='./img' data='<img src="image3_thumb.jpg">'>,
<Selector xpath='./img' data='<img src="image4_thumb.jpg">'>,
<Selector xpath='./img' data='<img src="image5_thumb.jpg">'>]
这里我们获取到了所有的 a 标签中的 img 标签。
注意: 选择器的最前方加 .,这代表提取元素内部的数据,如果没有加点,则代表从根节点开始提取。
此处我们用了./img 的提取方式,则代表从 a 节点里进行提取。如果此处我们用 //img ,则还是从 html 节点里进行提取。
现在我们已经获得了 Selector 类型的节点 a ,如果我们想要将 a 节点元素提取出来,可以使用 extract() 方法,如下:
>>> result.extract()
['<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>']
这里我们如果想要获得内容的文本内容,可以使用 /text() ,如果想要获取 href 属性的内容可以使用 /@href 。
我们来看一个完整的示例:
>>> response.xpath('//a[@href="image1.html"]/text()').extract()
['Name: My image 1 ']
这里我们限制的结果,只查到的一条数据,很多情况下我们都会获得多条数据,这时如果想获取第一个元素的内容,可以使用索引的方式,如下:
>>> response.xpath('//a/text()').extract()[0]
'Name: My image 1 '
这样其实有一点点的小问题,如果当前我们需要的列表为空,这里直接会产生数组越界的异常。
Scrapy 为我们提供了另一个方法 extract_first() ,专门用来解决这个问题,上面的示例可以改写成下面的样子:
>>> response.xpath('//a/text()').extract_first()
'Name: My image 1 '
同时我们也可以为 extract_first() 方法设置一个默认值参数,这样当 XPath 规则提取不到内容时会直接使用默认值。
>>> response.xpath('//a[@href="image1"]/text()').extract_first('Default')
'Default'
CSS 选择器
我们接着看 CSS 选择器,还是上面的示例,小编这里就不多 BB 了,直接上示例:
>>> response.css('a')
[<Selector xpath='descendant-or-self::a' data='<a href="image1.html">Name: My image ...'>,
<Selector xpath='descendant-or-self::a' data='<a href="image2.html">Name: My image ...'>,
<Selector xpath='descendant-or-self::a' data='<a href="image3.html">Name: My image ...'>,
<Selector xpath='descendant-or-self::a' data='<a href="image4.html">Name: My image ...'>,
<Selector xpath='descendant-or-self::a' data='<a href="image5.html">Name: My image ...'>]
我们同样可以进行属性选择和嵌套选择:
>>> response.css('a[href="image1.html"]').extract()
['<a href="image1.html">Name: My image 1 <br><img src="image1_thumb.jpg"></a>']
>>> response.css('a[href="image1.html"] img').extract()
['<img src="image1_thumb.jpg">']
接下来获取文本值和属性值的方法稍有区别:
>>> response.css('a[href="image1.html"]::text').extract()
['Name: My image 1 ']
>>> response.css('a[href="image1.html"] img::attr(src)').extract()
['image1_thumb.jpg']
获取文本和属性需要用 ::text 和 ::attr() 的写法。
当然,我们的 CSS 选择器和 Xpath 选择器一样可以嵌套选择,一个简单的小示例感受下:
>>> response.xpath('//a').css('img').xpath('@src').extract()
['image1_thumb.jpg', 'image2_thumb.jpg', 'image3_thumb.jpg', 'image4_thumb.jpg', 'image5_thumb.jpg']
Selector 选择器就先介绍到这里了,更多的内容和用法可以参考官方文档:https://docs.scrapy.org/en/latest/topics/selectors.html
本文没什么代码,所以示例代码就不放了。

小白学 Python 爬虫(35):爬虫框架 Scrapy 入门基础(三) Selector 选择器的更多相关文章
- 小白学 Python 爬虫(36):爬虫框架 Scrapy 入门基础(四) Downloader Middleware
人生苦短,我用 Python 前文传送门: 小白学 Python 爬虫(1):开篇 小白学 Python 爬虫(2):前置准备(一)基本类库的安装 小白学 Python 爬虫(3):前置准备(二)Li ...
- 小白学 Python 爬虫(37):爬虫框架 Scrapy 入门基础(五) Spider Middleware
人生苦短,我用 Python 前文传送门: 小白学 Python 爬虫(1):开篇 小白学 Python 爬虫(2):前置准备(一)基本类库的安装 小白学 Python 爬虫(3):前置准备(二)Li ...
- 小白学 Python 爬虫(38):爬虫框架 Scrapy 入门基础(六) Item Pipeline
人生苦短,我用 Python 前文传送门: 小白学 Python 爬虫(1):开篇 小白学 Python 爬虫(2):前置准备(一)基本类库的安装 小白学 Python 爬虫(3):前置准备(二)Li ...
- 小白学 Python 爬虫(40):爬虫框架 Scrapy 入门基础(七)对接 Selenium 实战
人生苦短,我用 Python 前文传送门: 小白学 Python 爬虫(1):开篇 小白学 Python 爬虫(2):前置准备(一)基本类库的安装 小白学 Python 爬虫(3):前置准备(二)Li ...
- 小白学 Python 爬虫(41):爬虫框架 Scrapy 入门基础(八)对接 Splash 实战
人生苦短,我用 Python 前文传送门: 小白学 Python 爬虫(1):开篇 小白学 Python 爬虫(2):前置准备(一)基本类库的安装 小白学 Python 爬虫(3):前置准备(二)Li ...
- 小白学 Python 爬虫(34):爬虫框架 Scrapy 入门基础(二)
人生苦短,我用 Python 前文传送门: 小白学 Python 爬虫(1):开篇 小白学 Python 爬虫(2):前置准备(一)基本类库的安装 小白学 Python 爬虫(3):前置准备(二)Li ...
- 小白学 Python 数据分析(4):Pandas (三)数据结构 DataFrame
在家为国家做贡献太无聊,不如跟我一起学点 Python 人生苦短,我用 Python 前文传送门: 小白学 Python 数据分析(1):数据分析基础 小白学 Python 数据分析(2):Panda ...
- 小白学 Python 数据分析(18):Matplotlib(三)常用图表(上)
人生苦短,我用 Python 前文传送门: 小白学 Python 数据分析(1):数据分析基础 小白学 Python 数据分析(2):Pandas (一)概述 小白学 Python 数据分析(3):P ...
- 小白学 Python 爬虫(33):爬虫框架 Scrapy 入门基础(一)
人生苦短,我用 Python 前文传送门: 小白学 Python 爬虫(1):开篇 小白学 Python 爬虫(2):前置准备(一)基本类库的安装 小白学 Python 爬虫(3):前置准备(二)Li ...
随机推荐
- 使用Laravel的队列实现系统通知、
使用Laravel的队列实现系统通知. 第一步:创建 jobs表的migrate php artisan queue:table 第二步:创建jobs 表 php artisan migrate 第三 ...
- poj 1279 Art Gallery (Half Plane Intersection)
1279 -- Art Gallery 还是半平面交的问题,要求求出多边形中可以观察到多边形所有边的位置区域的面积.其实就是把每一条边看作有向直线然后套用半平面交.这题在输入的时候应该用多边形的有向面 ...
- PyTorch之前向传播函数自动调用forward
参考:1. pytorch学习笔记(九):PyTorch结构介绍 2.pytorch学习笔记(七):pytorch hook 和 关于pytorch backward过程的理解 3.Pytorch入门 ...
- 从规则引擎到复杂事件处理(CEP)
Drools Fusion既是规则引擎,又可以作为CEP.除了事件定义和时间推理之外,对于引擎本身也会有一些不同的使用.主要体现在会话时钟.流模式.滑动窗口和对事件的内存管理. 会话时钟 由于事件的时 ...
- 21个项目玩转深度学习:基于TensorFlow的实践详解06—人脸检测和识别——项目集锦
摘自:https://github.com/azuredsky/mtcnn-2 mtcnn - Multi-task CNN library language dependencies comment ...
- records
2019年数据地址备份: three.js 实例在NextWebProject/static/canvas下边! qlgj 在NextWebProject下边!
- CF1045G AI robots
CF1045G AI robots 题目大意就不说了 这道题可以用CDQ分治做 但是,如何选择CDQ分治的维度一直是CDQ分治的难点所在 这道题我们有三种选择 1.让智商高的数智商低的 2.让看的近的 ...
- jq 技巧汇总
1,jQuery方法$()实际上是拥有两个参数的 $('li','.firstEl').onclick(function(){.......}) 这里,第二个参数用来限制第一个参数给定的查找结果 ...
- Centos6.5_x64-GitLab搭建私有GitHub
GitLab,是一个利用 Ruby on Rails 开发的开源应用程序,实现一个自托管的Git项目仓库,可通过Web界面进行访问公开的或者私人项目. 它拥有与GitHub类似的功 ...
- Linux中找不到ifconfig命令的解决方法
1.ifconfig命令是设置或显示网络接口的程序,可以显示出我们机器的网卡信息,可是有些时候最小化安装CentOS等Linux发行版的时候会默认不安装ifconfig等命令,这时候你进入终端,运行i ...