gcrawler:一个基于gevent的简单爬虫框架

引子

以前用scrapy写过一些简单的爬虫程序。但是我的需求实在太简单了,用scrapy有点大材小用,而且过于强大的缺点就是用起来太复杂,加上我也不太喜欢twisted——用各种回调实现的异步框架用起来还是不太自然。

前一阵接触了一下gevent(不知道为什么这样一个纯技术网站会在墙外),且不说据说它性能很好,关键是用patch的方式隐含提供异步支持的实现用起来真是太爽了。于是自己写了一个简单的爬虫框架,主要思路是模仿scrapy的。

关于Scrapy

首先来看Scrapy的架构(源于scrapy文档):

用户编写的爬虫主要是需要实现Spider和Item Pipeline两部分,Scheduler和Downloader部分是由Scrapy提供,并且整个程序由Scrapy Engine所驱动。

工作流程是:程序启动后Scrapy Engine从Scheduler取得网址,然后通过Downloader去下载页面交给Spider处理,Spider分析页面后根据情况决定是继续抓下一级锭接的页面(返回一个Scrapy Request)还是返回数据(返回一个Item List),Spider返回的数据(Item List)将被汇总交给Item Pipeline处理,比如存成文件或存入数据库什么的。

之所以要重复一下Scrapy的工作流程,是因为gcrawler也是模仿这个流程来做的。

Scrapy的局限及gcrawler的特点

不过在说gcrawler之前,还是先谈一下我的需求中用Scrapy实现不太方便的地方。最主要的是我的应用中虽然也是用HTTP协议去抓取内容,但是有很多额外的要求,比如有时需要POST,有时需要BasicAuth,有时还需要处理一些特定的HTTP Header字段,这些虽然有Download Middleware也可以实现,但很不自然——一个简单的HTTP请求操作被分割得支离破碎,对于代码的日后维护会造成很大的麻烦。

比如要用feedparser读RSS,因为feedparser是下载解析一体的实现,这时Scrapy就不太方便,虽然也可以拆开实现:用Scrapy下载再在Spider里用feedparser,但显然这种麻烦不是必要的。再比如说需要用OAuth进行REST API调用的话,用Scrapy的Download Middleware我还真不知道要怎么做才好。

因此,gcrawler与scrapy最大的不同就是Downloader的功能也将由用户实现(放在类似Scrapy的Spider中),用户可以自由控制下载操作的种种细节。乍一看似乎这样会增加用户的工作量,但实际上是简化了开发。比如前面说的feedparser或是OAuth调用,都可以直接实现,不用考虑分拆到不同的地方去做。那么由用户来实现下载工作会不会影响性能呢?Scrapy的一大优势就在于利用Twisted这个异步网络框架提供了网络访问的高性能。答案是不会,因为gevent提供了更为简单和高效的实现方式。二者的差异在于:

因为Scrapy是基于Twisted,而它是一个基于回调的异步框架,这就意味着用它来写Downloader固然可以得到高性能(托异步的福),但同时带来额外的复杂性(拜回调所赐)。所以Scrapy内部实现了这个高性能的Downloader,在提代高性能的同时屏蔽了这种复杂性,但代价就是前面所说的,用户自定义操作需要通过Middleware实现,结果还是增加了一些复杂性,并且使程序结构变得不太清晰。

而如前面所说,gevent通过patch的方式提供了隐含的异步支持,这样用户编写Downloader就成了简单的貌似“同步阻塞操作”,于是结构清晰与高性能得以兼得。个人根据gevent与twisted的性能比较猜测,能有与scrapy相当甚至可能更好的性能(纯猜测,待求证)。这是gevent相对twisted的一个巨大的优点。

gcrawler的使用

gcrawler的使用很简单:用户需要实现一个spider类,提供三个成员函数:scheduler, worker, pipeline。其中scheduler是一个生成器,用yield依次返回请求项(比如URL),worker相当于Scrapy里的Downloader+Spider,用于下载页面内容并解析,pipeline与Scrapy的item pipeline类似,都是用于存储最终结果用。

scheduler和pipeline没什么好说的,重点在worker里。因为gevent有隐含异步支持,所以这里不再需要像Scrapy里那样下载一个页面解析完后需要把请求重新发回Scheduler进行调度,而是可以直接 继续下载下一级链接的页面继续解析,整个流程会清晰很多,但又不会降低性能。当然要实现像Scrapy那样的方式也可以,只要在worker里把下一级页面链接再传递给scheduler即可。如果worker没有什么结果需要保存(比如上述把链接交给scheduler作下一步处理的情况),只需要简单返回一个None即可,pipeline会自动略过的。

一个简单的下载页面的例子如下:

当然,为了方便实现类似Scrapy的应用,gcrawler提供了一个默认的Downloader,所以上面的例子可以简化如下,只需要提供urls,并实现pipeline保存结果即可:
 另外还提供了一个retryOnURLError的decorator,用于自动重试,用法参见源码。

gcrawler的源码

代码在这里下载:1.5KB(好吧,我的个人技术网站在春节前也可耻滴被墙外了,大家自己想办法去下载吧不要问我。要是连这都不会,还是不要在中国搞技术了,因为太多的先进技术被墙外)。License还没想好用什么,先标一个copyright,反正在中国标什么License结果都一样的。等稳定一段时间发google code上去再确定用什么License吧。

已发布在bitbucketgithub,采用BSD License。

附录:gevent的安装

在使用这个框架之前首先需要安装gevent,而gevent又依赖libevent和greenlet。本来这事不复杂,gevent的文档里都有说,但可耻滴如前面所说,它的官网在中国大陆是“被不存在的”,所以我还是在这里说一下具体安装方法,并向有关部门坚决竖中指,你们是中国技术创新进步的最大阻力!

Ubuntu 10.04:

apt-get install python-dev libevent-1.4-2 libevent-dev

easy_install greenlet

easy_install gevent

Debian 5:

#先在sources.list里增加一个sid源,比如:

#deb http://mirrors.163.com/debian/ sid main

apt-get install python-gevent

#如果还缺什么则参考ubuntu

FreeBSD 8:

cd /usr/ports/devel/py-gevent

make install clean

Mac OS X 10.6.x:

#当然需要安装XCode和HomeBrew(或其它方式安装libevent)

brew install libevent

easy_install greenlet

easy_install gevent

Windows……这个自己Google去吧,友情建议还是不要在windows下浪费生命为好。

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
### 回答1: "ModuleNotFoundError: No module named gevent"是一个常见的错误,通常表示系统中缺少了gevent模块。 gevent一个Python的并发库,它使用协程(coroutine)来实现非阻塞的网络编程,提供高效的异步IO操作。如果你在代码中引入了gevent模块,但系统中没有安装该模块,就会出现"ModuleNotFoundError: No module named gevent"的错误提示。 要解决这个问题,首先需要确保你的系统上已经安装了gevent模块。你可以使用pip(Python包管理器)来安装gevent,打开命令提示符或终端窗口,输入以下命令: ``` pip install gevent ``` 这将自动从Python软件包索引中下载并安装gevent模块。 如果你已经安装了gevent,但仍然报错,可能是因为你的Python环境没有正确配置。在某些情况下,你可能需要重新安装Python,并确保你的Python环境变量(PATH)正确设置。 另外,如果你在使用虚拟环境(Virtual Environment)中开发项目,你需要确保你的虚拟环境中已经安装了gevent模块。在虚拟环境中安装模块的方法与在全局环境中类似,可以使用pip进行安装。 总之,如果你遇到"ModuleNotFoundError: No module named gevent"的错误,首先检查系统中是否安装了gevent模块,然后确认Python环境配置正确,或者在虚拟环境中安装gevent模块。 ### 回答2: ModuleNotFoundError: 找不到名为"gevent"的模块。 这个错误通常发生在Python代码试图导入一个名为"gevent"的模块时,但是找不到它。这可能是因为你尚未安装此模块,或者安装不正确。 要解决这个问题,你可以尝试以下步骤: 1. 确保已正确安装了gevent模块。可以使用pip命令来安装它。在命令行中运行以下命令:pip install gevent 2. 如果你已经安装了gevent模块但仍然出现这个错误,请确保你的Python环境和代码正确设置。可能需要检查Python的环境变量以确保它能正确找到模块的位置。 3. 如果你无法成功安装或使用gevent模块,可以尝试使用其他替代模块或解决方案。在Python中有许多并发和异步处理的模块可供选择,例如asyncio、multiprocessing等。 总之,解决此错误可以通过正确安装gevent模块和正确配置Python环境来实现。如果问题仍然存在,可能需要进一步调查并尝试其他解决方案。 ### 回答3: "Modulenotfounderror: no module named gevent" 是一个Python错误消息,表示在当前环境中缺少名为 "gevent" 的模块。要解决这个错误,你可以按照以下步骤进行操作: 1. 首先,确认你已经正确安装了 "gevent" 模块。可以通过使用命令行终端或者命令提示符输入以下命令来安装它: ``` pip install gevent ``` 这将使用pip工具将 "gevent" 模块下载并安装到你的Python环境中。 2. 如果你已经安装了 "gevent" 模块,但仍然收到该错误消息,请确保你正在使用与安装过程相同的Python环境。在某些情况下,你可能有多个Python版本或虚拟环境,导致模块安装在不正确的环境中。应该检查你的Python路径和环境设置。 3. 如果你使用的是类似Anaconda之类的Python发行版,需要验证是否可以从你的发行版的软件仓库中安装 "gevent"(如果可用)。在某些情况下,发行版可能需要不同的命令或指令来安装Python模块。 4. 如果上述步骤都没有解决问题,并且你已经确认你需要使用 "gevent" 模块,那么可能是由于其他的依赖项或设置问题导致无法正常加载这个模块。在这种情况下,你可以尝试使用其他替代模块,或者在相关论坛或社区寻求帮助,看看是否有其他解决方案。 总之,"Modulenotfounderror: no module named gevent" 错误表示缺少了 "gevent" 模块,可以通过正确安装模块、验证Python环境、安装适用于特定发行版的模块等步骤来解决这个问题。
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值