崔庆才python3爬虫-13章 Scrapy框架的使用-Selector的使用


崔庆才python3爬虫-13章 Scrapy框架的使用-Selector的使用

1
我们之前介绍了利用Beautiful Soup, pyquery以及正则表达式来提取网页数据,这确实非常方便,而 Scrapy还提供了自己的数据提取方法,即 Selector ( 选择器)。 Selector是基于lxml来构建的,支持XPath选择器、CSS选择器以及正则表达式,功能全面,解析速度和准确度非常高

直接使用

1
2
3
4
5
6
7
Selector个可以独立使用的模块。我们可以直接利用S elector这个类来构建一个选择器对象,然后调用它的相关方法如xpath()、css()等来提取数据。
例如,针对一段HTML代码,我们可以用如下方式构建S elector对象来提取数据:
from scrapy import Selector
body = '<htm lxheacl><title>Hello World</title></head><body></bodyx/html>'
selector = Selector(text=body)
title = selector.xpath('//title/text()).extract_first()
print(title )
1
2
3
4
5
6
运行结果如下所示:
Hello World
我们在这里没有在Scrapy框架中运行,而是把 Scrapy中的 Selector单独拿出来使用了,构建的时候传入t e x t 参数,就生成了一个S electo r选择器对象,然后就可以像前面我们所用的Scrapy中的解析方式一样,调用xpath()、css()等方法来提取了。
在这里我们查找的是源代码中的title中的文本,在XPath选择器最后加text() 方法就可以实现文本的提取了。
以上内容就是Selector的直接使用方式。同 Beautiful Soup等库类似, Selector其实也是强大的网页解析库。如果方便的话,我们也可以在其他项目中直接使用Selector来提取数据。
接下来,我们用实例来详细讲解Selector的用法。

scrapy shell

官方文档

1
由于Selector主要是与Scrapy结合使用,如 Scrapy的回调函数中的参数response直接调用xpath()或者css()方法来提取数据,所以在这里我们借助Scrapy shell来模拟Scrapy请求的过程,来讲解相关的提取方法
1
2
3
4
5
6
7
我们用官方文档的一个样例页面来做演不:http://doc.scrapy.org/en/latest/_static/selectors-sample1.html0

开启Scrapy shell, 在命令行输入如下命令:
scrapy shell http://doc.scrapy.org/en/latest/_static/selectors-samplel.html

我们就进入到Scrapy shell模式。这个过程其实是, Scmpy发起了一次请求,请求的URL就是刚才
命令行下输入的U R L ,然后把一些可操作的变量传递给我们,如 request. response等
1
2
3
我们可以在命令行模式下输入命令调用对象的一些操作方法,回车之后实时显示结果。这与
Python的命令行交互模式是类似的。
接下来,演示的实例都将页面的源码作为分析目标,页面源码如下所示:

总结

1
(因为很多网站都有反爬机制,其实使用 scrapy shell 的时候就是以 scrapy 爬虫的标志进行访问的,所以网站回拒绝爬虫的服务,返回 403
1
2
3
1.(只治标,不治本)在使用scrapy 的时候在最后加上 -s USER-AGENT="Mozills/5.0"

scrapy shell "https://movie.douban.com" -s USER_AGENT='Mozills/5.0’
1
2
3
4
5
6
7
8
9
10
11
12
2.(半治标半治本)
修改scrapy 中 setting.py 文件的 USER-AGENT
    修改前:
#USER_AGENT = 'yi (+http://www.yourdomain.com)'
   修改后:
USER_AGENT = 'Mozilla/5.0 (Windows NT 5.1; rv:5.0) Gecko/20100101 Firefox/5.0'
  
注意:
  这里的 scrapy 只能在 scrapy 中使用,直接在cmd 中使用不生效,这就是作者说的半指标半治本
scrapy shell https://movie.douban.com/top250
我们可以看见返回成功的信息:
response <200 https://movie.douban.com/top250>
1
2
3
4
5
6
7
8
9
3.(治愈)
 直接修改 python 的defult_setting.py 文件里默认的 USER-AGENT值
(那么之后不管实在项目中还是再cmd中使用 scrapy shell ,都是以浏览器的标识阱行访问网站的)、
 那么 找到 defult_setting.py 文件的位置;
 一般在你安装 python 的目录下的 /lib/site-package/scrapy/deting.py中 找到 user-agent进行修改:
    修改前:
USER_AGENT = 'Scrapy/%s (+http://scrapy.org)' % import_module('scrapy').__version__
    修改后:
USER_AGENT = 'Mozilla/5.0 (Windows NT 5.1; rv:5.0) Gecko/20100101 Firefox/5.0'

XPath选择器

1
2
3
进入Scrapy shell之后,我们将主要操作response这个变量来进行解析。因为我们解析的是HTML代码,Selector将自动使用HTML语法来分析。
response有一个属性selector ,我们调用response.selector返回的内容就相当于用response的body构造了一个Selector对象。通过这个Selector对象我们可以调用解析方法如xpath()、css()等,通过向方法传入XPath或 CSS选择器参数就可以实现信息的提取。
我们用一个实例感受一下,如下所示:
1
2
3
4
5
6
7
8
9
10
我们用一个实例感受一下,如下所示:
>>> result = response.selector.xpath('//a')
>>> result
[<Selector xpath='//a' data='<a href="imagel.html">Name: My image 1 <'>,
<Selector xpath='//a' data='<a href="image2.html">Name: My image 2 <*>,
<Selector xpath='//a' data='<a href="image3.html">Name: My image 3 <*>,
<Selector xpath='//a' data='<a href="image4.html">Name: My image 4 <'>,
<Selector xpath='//a' data='<a href="images.html">Name: My image 5 <*>]
>>> type(result)
scrapy.selector.unified.SelectorList
1
2
3
4
5
6
7
8
打印结果的形式是Selector组成的列表,其实它是Selector List类型, SelectorList和Selector都可以继续调用xpath()和css()等方法来进一步提取数据。
在上面的例子中,我们提取了a节点。接下来,我们尝试继续调用xpath()方法来提取a节点内包含的img节点,如下所示:
>>> result.xpath('./img')
[<Selector xpath='./img' dmta='<img src="imagel_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">'>]
1
2
我们获得了a节点里面的所有img节点,结果为5
值得注意的是,选择器的最前方加.(点),这代表提取元素内部的数据,如果没有加点,则代表从根节点开始提取。此处我们用了./img的提取方式,则代表从a节点里进行提取。如果此处我们用//img ,则还是从html节点里进行提取。
1
2
3
4
5
6
7
我们刚才使用了response.selector.xpath()方法对数据进行了提取。 Scrapy提供了两个实用的快捷方法,response.xpath()和 response.css(), 它们二者的功能完全等同于 response. selector.xpath()和 response.selector.css()o 方便起见,后面我们统一直接调用response的 xpath()和 css()方法进行选择。

现在我们得到的是SelectorList类型的变量,该变量是由Selector对象组成的列表。我们可以用索引单独取出其中某个Selector元素,如下所示:
» > result[0]
<Selector xpath = '//a' data='<a href="imagel.html">Name: My image 1 <'>

我们可以像操作列表一样操作这个SelectorList
1
2
3
4
5
6
7
8
9
但是现在获取的内容是Selector或者SelectorList类型,并不是真正的文本内容。那么具体的内容怎么提取呢?
比如我们现在想提取出a节点元素,就可以利用extract ()方法,如下所示:
» > result.extract()
[ '<a href=" imagel.html">Name:My image1<brximg src= "im a g e l_ th u m b .jp g "x/a > ', '<a href="im age2. html">Name:
My image 2 < brxim g src="im age2_thum b.jpg"x/a>', ' <a h re f ="image3. html">Name: My image 3 < brxim g
src="image3_thumb.jpg"x/a>', '<a href ="image4.html">Name: My image 4 <brximg src="image4_thumb.jpg"x/a>',
' <a h re f=" images. htm l" >Name: My image 5 < b rxim g src="im age5_thum b.jpg"x/a>, ]

这里使用了extract()方法,我们就可以把真实需要的内容获取下来。
1
2
3
4
5
6
7
我们还可以改写XPath表达式,来选取节点的内部文本和属性,如下所示:
>>> response.xpath('//a/text()').extract()
[ ' Name: My image 1 ', 'Name: My image 2 ' , 'Name: My image 3 ', ' Name: My image 4 ' , 'Name: My image 5 ']
>>> re sponse .xpath('//a/@href' ).extract()
[ 'im a g e l.h tm l', 'im ag e2.h tm l', ' image3. h tm l', 'im ag e4.h tm l', 'im ag e5.h tm l']

我们只需要再加一层/text()就可以获取节点的内部文本,或者加一层/@href就可以获取节点的href属性。其中,@符号后面内容就是要获取的属性名称。
1
2
3
4
5
6
7
8
但是这里有一个问题:如果符合要求的节点只有一个,那么返回的结果会是什么呢?我们再用一个实例来感受一下,如下所示:
>>> response.xpath('//a[@href= "imagel.html"]/text()' ) .extract()
['Name: My image1']

我们用属性限制了匹配的范围,使 XPath只可以匹配到一个元素。然后用 extract()方法提取结果,其结果还是一个列表形式,其文本是列表的第一个元素。但很多情况下,我们其实想要的数据就是第一个元素内容,这里我们通过加一个索引来获取,如下所示:
>>> response.xpath('//a [@href="imagel.html"]/text ()') .extract()[0]

' Name: My image 1 '
1
2
3
4
5
6
7
8
9
10
11
12
13
14
但是,这个写法很明显是有风险的。一旦XPath有问题,那么extract()后的结果可能是一个空列表。如果我们再用索引来获取,那不就会可能导致数组越界吗?
所以,另外一个方法可以专门提取单个元素,它叫作extract_first() 我们可以改写上面的例子
如下所示:
>>> response.xpath ('//a [@href="imagel.html"]/text()').ex tract_first()
' Name: My image 1 '
这样,我们直接利用e x tra c t_ first()方法将匹配的第一个结果提取出来,同时我们也不用担心数组越界的问题。
另外我们也可以为extract_first()方法设置一个默认值参数,这样当XPath规则提取不到内容时会直接使用默认值。例 如 将 XPath改成一个不存在的规则,重新执行代码,如下所示:
> » response.xpath ('//a[@href="imagel"]/text()').extract_ first()
>>> response.xpath('//a[@href="im ag el"]/text()').extract_ first('DefaultImage')
'DefaultImage'
这里 如果XPath匹配不到任何元素,调用extract_first()会返回空,也不会报错。

在第二行代码中,我们还传递了一个参数当作默认值,如 Default Image0 这样如果XPath匹配不到结果的话,返回值会使用这个参数来代替,可以看到输出正是如此。
现在为止,我们了解了 Scrapy中 的 XPath的相关用法,包括嵌套查询、提取内容、提取单个内容、获取文本和属性等。

XPath用法总结

1
2
3
4
1.找标签
./xxx
//xxx
/xxx
1
2
2.获取内容
response.xpath(...../xxxx/text())
1
2
3.获取真实标签
response.xpath(.../xxxx).extract()
1
2
4.获取属性
response.xpath(.../xxxx/@herf) # @符号后面内容就是要获取的属性名
1
2
5.属性限制
response.xpath('//a[@href="imagel.html"]/text()' )

CSS选择器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
接下来,我们看看CSS选择器的用法
Scrapy的选择器同时还对接了CSS选择器,使用response.css()方法可以使用CSS选择器来选择对应的元素。
例如在上文我们选取了所有的a节点,那么CSS选择器同样可以做到,如下所示:
>>> response.css('a')
[< S elector xp a th = 'd e sce n d a n t-o r-se lf: :a ' data='<a h re f= "imagel.html">Name: My image 1 < '> ,
<S elector xp a th = 'd e sce n d a n t-o r-se lf: :a ' data='<a h re f= "image2. h tm l" >Name: My image 2 < '> ,
<S elector xp a th = 'd e sce n d a n t-o r-se lf: :a ' data='<a h re f= "image3. html">Name: My image 3 < >
<S elector xp a th = 'd e sce n d a n t-o r-se lf: :a ' data='<a h re f= "image4. html">Name: My image 4 < '> ,
<S elector xp a th = 'd e sce n d a n t-o r-se lf: :a ' data='<a h re f= "images. h tm l" >Name: My image 5 < '> ]
同样,调 用 ex tract()方法就可以提取出节点,如下所示:
» > re s p o n s e .c s s ('a ').e x tra c t。
[ '<a h re f=" im age l. h tm l" >Name: My image 1 < brx im g src = "im a g e l_ th u m b .jp g "x/a > ', '<a h re f=" image2. htm l" >Name:
My image 2 < brx im g src="im age2 _thu m b.jp g"x/a > ', '<a href="image3.html">Name: My image 3 < brx im g
src="image3_thumb.jpg"></a>*, '<a hre f=" image4.html">Name: My image 4 <brxim g src="image4_thumb.jp g " x /a > ',
' <a h re f ="image5.html">Name: My image 5 < brx im g src="image5_thumb. jp g " x / a > ']
用法和 XPath选择是完全一样的。
1
2
3
4
5
6
7
另外,我们也可以进行属性选择和嵌套选择,如下所示:
> » response.css('a [h re f="im a g e l. html"]').extract()
[ '<a href="imagel.htm l">Name: My image 1 < brx im g src = "im a g e l_ th u m b .jp g "x/a > ']
> » response.css('a[href="imagel.html"] img').extract()
[ '<img src=" imagel_thumb. jp g " > ']

这里用[href="image.html"]限定了href属性,可以看到匹配结果就只有一个了。另外如果想找a节点内的 img节点,只需要再加一个空格和img即可。选择器的写法和标准CSS选择器写法如出一辙
1
2
3
我们也可以使用extract_first()方法提取列表的第一个元素,如下所示:
>>> response.css(,a[href="imagel.html"] img').extract_fi:rst()
'<img src="imagel_thumb•jpg">'
1
2
3
4
5
接下来的两个用法不太一样。节点的内部文本和属性的获取是这样实现的,如下所示:
>>> response.css('a[href="imagel.html"]::text').extract_first()
'Name: My image 1 '
>>> response.css('a[href="imagel.html"] img::attr(src)').extract_first()
'imagel_thumb.jpg
1
2
3
4
5
6
7
8
9
获取文本和属性需要用::te x t和 ::a ttr ()的写法。而其他库如Beautiful Soup或 pyquery都有单独
的方法。
另外, CSS选择器和XPath选择器一样可以嵌套选择。我们可以先用XPath选择器选中所有a 节
点 ,再利用CSS选择器选中img节点,再 用 XPath选择器获取属性。我们用一个实例来感受一下,如
下所示:
>>> response.xpath('//a').css('img').xpath('@src').extract()
['imagel_thumb.jpg', 'image2_thumb.jpg', 'image3_thumb.jpg', 'image4_thumb.jpg', 'image5_thumb.jpg']
我们成功获取了所有img节点的 sr c 属性。
因此,我们可以随意使用xpath()和 css()方法二者自由组合实现嵌套查询,二者是完全兼容的。

css用法总结

1
2
3
4
5
6
7
8
1.获取文本
response.css('xxxx::text').extract_first()
2.获取属性
response.css('xxxx::attr(xxx)').extract_first()
3.获取标签
response.css('a')
4.限制属性
response.css('a[href="xxxx"]')

正则匹配

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Scrapy的选择器还支持正则匹配。比如,在示例的a 节点中的文本类似于Name: My image1 , 现在我们只想把Name:后面的内容提取出来,这时就可以借助re()方法,实现如下:
>>>response.xpath('//a/text()').re('Name:\s(.*)')
['My image 1 ', 'My image 2 ', 'My image 3 1, 'My image 4 ', 'My image 5 ']

我们给re()方法传了一个正则表达式,其中(.*)就是要匹配的内容,输出的结果就是正则表达式
匹配的分组,结果会依次输出。
如果同时存在两个分组,那么结果依然会被按序输出,如下所示:
>>> response.xpath('//a/text()').re('(.*?):\s(.*)')
['Name', 'My image 1 ', 'Name', 'My image 2 ', 'Name', 'My image 3 'Name', 'My image 4 ', 'Name', 'My image
5 ']



似 extract_first()方法,re_first()方法可以选取列表的第一个元素,用法如下:
>>> response.xpath('//a/text()').re_first('(.*?):\s(.*)')
1Name1
>>> response.xpath('//a/text()').re_first('Name:\s(.*)')
'My image 1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
不论正则匹配了几个分组,结果都会等于列表的第一个元素。
值得注意的是, response对象不能直接调用:re()和 re _ first()方法。如果想要对全文进行正则匹
配,可以先调用xpath()方法再正则匹配,如下所示:
>>> response.re('Name:\s(.*)')
Traceback (most recent call last):
File "<console>", line 1, in <module>
1348613章 Scrapy框架的使用
AttributeError: 'HtmlResponse' object has no attribute 're'
>>> response.xpath('.,).re('Name:\s(.*)<br>,)
['My image 1 ', 'My image 2 'My image 3 ', 'My image 4 ', 'My image 5 ']
>>> response.xpath('.,).re_first('Name:\s(.*)<br>,)
'My image 1 '

通过上面的例子,我们可以看到,直接调用re()方法会提示没有re属性。但是这里首先调用了xpath ('.')选中全文,然后调用re()和 re_first()方法,就可以进行正则匹配了。

没有伞的孩子,必须努力奔跑!

Typewriter Mode** 已开启。

可以在视图菜单中关闭

不再显示关闭

本文标题:崔庆才python3爬虫-13章 Scrapy框架的使用-Selector的使用

文章作者:TTYONG

发布时间:2020年03月22日 - 17:03

最后更新:2022年03月28日 - 19:03

原始链接:http://tianyong.fun/%E5%B4%94%E5%BA%86%E6%89%8Dpython3%E7%88%AC%E8%99%AB-13%E7%AB%A0%20Scrapy%E6%A1%86%E6%9E%B6%E7%9A%84%E4%BD%BF%E7%94%A8(13.3)-%20Selector%E7%9A%84%E4%BD%BF%E7%94%A8.html

许可协议: 转载请保留原文链接及作者。

多少都是爱
0%