Scrapy 爬虫运行全流程深度剖析,让你轻松掌握高效爬取技巧!

   日期:2024-12-24     作者:caijiyuan       评论:0    移动:http://w.yusign.com/mobile/news/2626.html
核心提示:大家好,在我们使用 scrapy 进行网站数据采集的时,会遇到多个 spider 同时运行或者单个 spider 运行的情况,

大家好,在我们使用 scrapy 进行网站数据采集的时,会遇到多个 spider 同时运行或者单个 spider 运行的情况,一般采取的是 shell 命令去运行,在分析 scrapy 的源码实现时,发现可以定制化启动,本篇文章我将分享启动代码和依靠启动代码分析部分 scrapy 的启动流程,希望能给读者朋友们带来帮助。

特别声明本公众号文章只作为学术研究,不作为其他不法用途;如有侵权请联系作者删除。

立即加星标

每月看好文

 目录


一、前言介绍

二、启动代码实现

三、scrapy启动分析

四、crawl源码分析

五、ExecutionEngine分析

六、downloader源码分析


一、前言介绍

本篇文章阅读完后,读者可以知晓使用 scrapy 时优雅的启动 spider 和了解 scrapy 的启动流程,让采集者在工作中更加的游刃有余,接下来我们进入正文吧。


二、启动代码实现

编写启动代码如下

思路传参,可以传 all 或者传 spider 的名字,从而启动爬虫。

使用可以把这个代码放到对应的位置,名字可以自定义。

这个 name 对应 spider 中的 spider name。


三、scrapy 启动分析

上面的 class 作用:这个类用于在一个进程中运行多个爬虫。

从源码技术角度解读,主要做了如下功能

  • 启动 reactor 事件监听(start函数

  • 当接收到关闭信号时时停止 reactor(signal_shutdown 和 signal_kill)从父类 CrawlerRunner

  • 首先初始化方法主要创建了 self._crawlers ,是个 set,里面可以存放多个 Crawler,self._active 也是个 set,里面是正在运行的 crawler。

  • 立刻停止所有的在运行的 Crawler(stop 方法

  • 等待所有的 Crawler 运行完后再停止(join

  • 传入一个 spider 的实例类,然后使用 create_crawler 创建一个 crawler,然后调用 _crawl 方法并将加入 self.crawlers,然后调用创建的crawler的crawl进行爬取 (这里不会立即爬,会等到 reactor事件循环开始后(crawl

然后分析 crawl,等事件循环开启后,crawl 就开始爬取,那么爬取前做了什么?

总结Craler 其实算我们的主角了,因为像一些关于爬虫内部相关的的东西都要在这里初始化并创建,他的存在是如果有一个 spider 要被创建那么就会有一个 crawler 去对应。例如初始化时会初始化下方的一些东西


四、crawl 源码分析

首先会进行 spider 的创建;把自己设置的 setting 和 scrapy 本身的 setting 进行合并(合并的时候自己设置的为优先级高,如果同时拥有重复的,那么自己设置的会将scrapy 默认的进行覆盖;创建 engine,调用引擎的 open_spider 方法;并且调用了 engine的start 方法,这两个要重点观看,代码如下

总结:  这个类里面还有一些其他方法,获取spider中间件(get_spider_middleware,获得pipline(get_iteme_pipline),获 得扩展 (get_extension,停止 spider(stop),接下来重头戏跑到了引擎里面。


五、ExecutionEngine 分析

分析的过程会具体以爬虫的运行为导向,会牵扯其实一些初始化的代码或者辅助的代码为辅。初始化方法里面会重点的创建 调度器;下载器;Scraper; 源码分析如下

然后我们分析 open_spider: 

做了以下工作,主要对 itempipline 需要进行 open_spider 进行了处理(这里也说明了链接数据库啥的前置性,如果在 itempipline 写的情况下会被引擎主动调用,对 start_requests 进行了调度;统计状态;发送 spider_opened 的信号。源码解读如下

重点看如何实现的定时在事件循环中调度,通过这个方法可以每五秒主动调用一次,下面的四行代码形成了个逻辑去不间断的调用self._next_request以便达到处理请求的目的。源码解读如下

通过上面的代码,调用的函数是 _next_request:从 spider 一开始,那么调度器中的 request 肯定为空,那么会从 start_requests 进行取请求,如果调度器中存在 requests,那么会一直使用 _next_request_from_scheduler(),处理请求,如果说这 5s 的是主动去request,那么这 self._next_request_from_scheduler() 调用就是被动去 request。源码如下

接下来看下 _next_request_from_scheduler,从调度器中获取下一个请求,下载请求并处理下载结果,同时确保在不同阶段(处理下载结果、移除请求、调度下一个调用)记录任何错误,源码解读如下

总结拿到请求后,我们接下来分析请求是如何下载和解析的。


六、downloader源码分析

首先会将请求加入 slot 后,使用 downloader.fetch 进行处理 request,如果处理完成后返回的结果是 response,会发送 response_received 信号,然后调用 _on_complete 继续下一个调度,源码解读如下

接下来我们看download.fetch如何处理的:首先调用中间件处理请求self.middleware.download,然后无论是否成功,都要从activate中移除这个请求,源码如下

这个 download 函数,会首先调用所有请求中间件的 process_requests 方法,如果 process_requests 返回一个 request 或者返回为空那么接着会进行执行下一个中间件的 process_requests 方法, 如果 process_requests 方法返回一个 response,那么下载器直接就返回 response 了,不会进行请求;如果不返回 response 的情况下,调用 download_dunc 函数进行下载;源码解读如下

通过分析可以查看到下载函数如下

接下来分析图片中函数,代码解读如下

下载完成后,我们回到 _next_request_from_scheduler的d.addBoth(self._handle_downloader_output, request)  处理下载器的结果,我们在上方代码   def download(self, download_func: Callable, request: Request, spider: Spider) 的 process_request 里面已经知道,如果直接返回一个 requqest 或 response 对象,那么会直接返回到现在处理的结果上, 所以处理这个结果的时候,会有两种可能如果是 Request 类型的那么继续抓取,是 response 直接进行解析;代码解读如下

接下来我们看看 scrapy 是如何处理响应的,代码解读如下

上面就是其完整流程了,其实还有一个问题?spider 的解析方法 是哪调用的

:其实是 scrape2,通过调用 spider 中 spider 中间件,然后通过 call_spider,调用的回调方法,代码解读如下

本篇分享到这里就结束了,感谢大家的阅读和支持。如果你对爬虫逆向分析、验证码破解及其他技术话题感兴趣,记得关注我的公众号,不错过下一期的更新。我们将继续深入探讨各种技术细节和实用技巧,一起探索数字世界的奥秘。期待与你在下期文章中再见,一起学习,一起进步!☀️☀️

     本文地址:http://w.yusign.com/news/2626.html    述古往 http://w.yusign.com/static/ , 查看更多
 
特别提示:本信息由相关用户自行提供,真实性未证实,仅供参考。请谨慎采用,风险自负。

举报收藏 0打赏 0评论 0
 
更多>同类资讯
0相关评论

相关文章
最新文章
推荐文章
推荐图文
资讯
点击排行
{
网站首页  |  关于我们  |  联系方式  |  用户协议  |  隐私政策  |  版权声明  |  网站地图  |  排名推广  |  广告服务  |  积分换礼  |  网站留言  |  RSS订阅  |  违规举报  |  鄂ICP备2020018471号