一 CrawlSpider:URL规则过滤
CrawSpider类可以定义过滤url的规则,当spCrawSpiderder碰到满足条件的url都自动进行爬取,不用像基本爬虫类spider需手动yield Request。
4.1 创建CrawSpider
scrapy genspider -t crawl [爬虫类名] [域名]
与创建基本爬虫相比,这里用 -t 指明了使用的模板为’crawl’,即继承自CrawlSpider。
4.2 URL过滤规则
Rule类:
- link_extractor:LinkExtractor对象,用于定义爬取规则
- callback:满足规则的url,执行的回调函数
- follow:指定根据该规则从response中提取的链接是否需要跟进(指在提取出的url页面中是否还继续执行按规则提取提取url)
- process_links:从link_extractor中获取到链接后传递给该函数,用于过滤不需要爬取的链接
LinkExtractors类:链接提取器
- allow:允许的url,为一个正则表达式,符合则提取;
- deny:禁止的url,为一个正则表达式,符合则不提取;
- allow_domain:允许的域名;
- deny_domain:禁止的域名;
- restrict_xpaths:严格的xpath,和allow共同过滤;
4.3 举例
4.3.1 创建CrawlSpider
scrapy genspider -t crawl wxapp_spider 'wxapp-union.com'
4.3.2 CrawlSpider类
(1) 创建规则列表:可包含多条规则
rules=(
Rule(LinkExtractor(...)),
Rule(...)
)
规则列表rules创建后由scrapy框架自动执行,流程如下:
- scrapy将下载器返回的Response对象转发给crawlspider;
- scrapy自动解析Response对象,提取其中所有url,根据规则列表过滤;
- 根据符合规则的url创建Request对象,并将Request对象的callback参数设置为Rule中制定的callback函数;如果Rule中没有指定,则设置为默认解析函数parse;
- scrapy将Request对象转发给调度器;
注意:
包含目标数据的页面对应的Rule才需要
指定回调函数(解析函数),如果该页面中只是单纯为了提取其他URL,不需要
指定回调函数,LinkExtractor已经可以提取URL了;而且,scrapy自带URL去重的功能。
(2)创建解析函数
解析函数作为Rule中的回调函数,作用同基本爬虫类。
二 FormRequest:post请求模拟登录
Post请求要使用Request的子类FormRequest。如果要爬虫一开始就发送POST请求,需要在爬虫类中重写start_request(self)方法,并且不再调用start_urls里的url。因为爬虫类启动时,默认使用start_request方法通过get方式请求start_urls中的URL。
注意:
- 登录一个网页往往并不第一个请求就是POST,而是先GET到登录页面,再POST数据登录;
- Request对象若不指定回调函数,则默认调用parse函数,为避免,可以定义一个空的回调函数,专门用于这种情况;
- 登录后cookie就保存到本地了;
验证码识别: 使用第三方验证码平台,付费识别。对第三方平台发送图片进行请求,以json方式返回识别的验证码。
三 FilesPipeline、ImagesPipeline:文件下载
spider只创建Request对象,下载器也只获取Response对象,下载和存储图片由pipelines进行
3.1 传统下载方式:ulrlib.urlretrieve()
缺陷: 以获取一批图像URL为例,下载图片是按顺序遍历URL,一张一张图片下载,只有前一张下载完才会下载后面的,太慢;且需手动去重;
3.2 Scrapy为下载方法
scrapy框架由pipeline负责文件下载,且提供了FilesPipeline、ImagesPipeline,两个已定义好的pipeline。
FilesPipeline类:用于下载文件,包括视频、图片等;
ImagesPipeline类:专门用于下载图片,继承自FilesPipeline但功能更丰富,包括转格式、生成缩略图等。
优势:
- 调度器自动避免下载重复的文件;
- 异步下载,效率高;
- 可以方便地指定文件存储路径;
- 图片可以生成缩略图、转格式、检测图片宽高(可以设置太小的不下载);
FilesPipeline、ImagesPipeline为scrapy内置类,不需要手动创建和调用。通过在setting.py中配置即可创建和实现功能。
3.2.1FilesPipeline类
引擎会将spider解析后的数据转发给pipeline,若数据封装为item且具有file_urls、files属性,scrapy会调用FilesPipeline遍历file_urls中的URL并自动下载。下载完成后,将下载信息存入files属性。
- 定义item,包含file_urls属性(为待下载URL的list)、files属性;
- setting.py中配置FILES_STORE,作为文件存放路径;
- setting.py中配置ITEM_PIPELINE,启动pipeline;
scrapy.pipeline.files.FilesPipeline:1
3.2.2 ImagesPipeline类
与FilesPipeline类似,ImagesPipeline遍历iamge_urls中的URL,自动下载图片。下载完成后,信息存放在iamges中。
- 定义item,包含iamge_urls属性(为待下载URL的list)、iamges属性;
- setting.py中配置IMAGES_STORE,作为图片存放路径;
- setting.py中配置ITEM_PIPELINE,启动pipeline;
scrapy.pipeline.images.ImagesPipeline:1
3.3 自定义FilesPipeline、ImagesPipeline
ImagesPipeline的缺陷:settings.py中只能为ImagesPipeline设置一个统一的存储路径,无法实现图片分类存储。
get_media_requests(item,info)
ImagesPipeline通过调用get_media_requests()方法遍历item的iamge_urls属性生成request对象列表,返回给引擎。在请求前调用。
file_path(request, response, infp)
ImagesPipeline通过调用file_path()方法获得已下载图片的目标存储路径。在请求后调用。file_path返回的路径为"/full/图片名",之后scrapy再获取settings.py中的IMAGES_STORE路径值,最终路径为"(IMAGES_STORE)/full/图片名"。
自定义pipeline类,继承ImagesPipeline类,并对上述两个方法重写。
以图片分类存储为例,请求前的item中包含图片的详细信息,但是请求后无法获取item对象了,导致无法获取分类信息。通过上面两个方法发可以看到:Request对象是从请求前传到请求后的。如果将请求前的信息保存到Request对象中,则可实现 信息传递 了。而python的动态绑定使这一需求很简单满足:直接为Request对象创建一个属性,并将item对象赋为值即可。
重写get_media_requests方法:
先调用原方法获取request列表,再遍历列表为每个request对象增加item属性,并用参数item赋值,这样request对象中就保存了item的信息
重写fiel_path方法:
先根据request.item得到分类信息,从setting.py获取IMAGES_STORE的值。IMAGES_STORE+分类得到分类目录路径,检查是否存在并创建分类目录。然后调用原方法得到"/full/图片名",最后用分类目录路径replace默认存储路径中的full,得到图片路径。
四 下载器中间件:调用selenium
在middlewares.py文件中自定义下载器中间件类,直接继承object,必须至少实现process_request()、process_response()中的一个。在setting.py中配置后,由scrapy自动调用。可为中间件设置优先级。
下载器中间件位于引擎和下载器之间,可以通过 process_request() 方法操作引擎发给下载器的Request对象,也可以通过 process_response() 方法操作下载器发给引擎的Response对象。
4.1 process_request(self,request,spider)
scrapy自动调用,用于对引擎发给下载器的Request对象进行处理。多个下载器可以串联,依次调用各下载器的process_request方法。
参数:
- request:Request对象;
- spider:创建Request对象的spider对象;
返回值: 依据下载器中间件不同的返回值,scrapy进行不同的后续操作
- None:继续调用其他下载器中间件处理该request,直到合适的下载器处理函数被调用;
- Response对象:不会再将Request对象发送给下载器,而是直接将Response对象返回给引擎;
- Request对象:继续交给下一个下载器中间件处理;
- 产生异常:调用process_exception方法;
4.2 process_response(self,request,response,spider)
参数:
- request:被下载的request对象;
- resposne:处理后resposne对象;
- spier:发出request的spider对象;
返回值:
- Response对象:继续传给下一个中间件;
- Request对象:直接将Request对象重新传给下载器;
- 产生异常:调用request的errback方法,如果没有指定该方法则抛出异常;
4.3 应用
4.3.1 设置随机请求头
1.创建下载器中间件
class MyDownloaderMiddleware(object):
USER_AGENTS={
...
}
def process_request(self,request,spider):
user_agent=random.choice(self.USER_AGENT)
request.headers['User-Agent']=user_agent
注意:www.useragentstring.com中有各种请求头信息
2.在setting.py中启用下载器中间件
DOWNLOADER_MIDDLEWARES={
#下载器优先级,数字越小越优先,建议以543,544...
'scrapyTest.middlewares.MyDownloaderMiddleware':543,
}
4.3.2 启动selenium
在这里插入代码片
五 Scrapy Shell
想测试xpath、beautifulsoup、正则表达式、css选择器写法是否正确,而直接运行scrapy太慢,可用Scrapy Shell快速测试。
Scrapy Shell 使用流程:
- cmd启动Scrapy框架环境;
- cmd进入项目目录;
- cmd执行scrapy shell ‘www…’,获取访问URL的response;
- cmd执行xpath、beautifulsoup、正则表达式解析response,并输出;
- 查看解析结果是否正确