用Scrapy已经有一段时间了,觉得该是看一下源码的时候了。最开始用的时候还是0.16的版本,现在稳定版已经到了0.18。结合使用Scrapy的过程,先从Scrapy的命令行看起。
一、准备
下载源代码,scrapy托管在github上,可以直接去项目主页(https://github.com/scrapy/scrapy)通过各种方式(ssh、svn、git、下载压缩包等)下载源码。
IDE我用的是pyCharm,这个工具很强大,但并不是免费的(有免费的社区版),方便看代码和debug。
scrapy版本:0.18.2,为了方便,这里用scrapy_home带至scrapy源码所在目录路径。
二、从cmdline.py说起
scrapy通过自带的命令行方式可以实现快速构建、执行等。而这一切的功能都是从cmdline.py这个模块开始的。当我们敲下scrapy <command> [options] [args]的命令时,都是通过该模块来解析,然后执行具体的任务的。这个可以从scrapy_home/bin/scrapy这个文件下看到,这个文件的内容也很短,就几行而已:
显然,调用的是cmdline.py这个模块的execute()函数。接下来就简单看一夏cmdline.py这个模块的具体代码。
三、cmdline.py的实现
scrapy命令的执行方式如下:
scrapy <command> [options] [args]
通过代码可以看到cmdline.py中execute()主要做了一下几个工作:
- 处理参数信息为空的情况;
- 处理配置信息(包含向后兼容的代码),这样新的scrapy可以处理以前老版本下生成的项目;
- 判断目前执行scrapy命令的当前目录是否包含一个scrapy project,因为在scrapy project中可以执行更多的command选择;
- 判断传入的command是否正确,不正确的话给出提示信息;
- 如果命令正确,则根据传入的options和args用一个parser来解析成command可以用的方式,记录在cmd中;
- _run_print_help()函数调用cmd.process_options()来执行cmd的选项设置;
process_options()函数在command.py的ScrapyCommand类中定义,该类是其他所有scrapy command(如crawl命令)的父类。 - 有了5,6处理得到的信息,然后加上setting信息,创建抓取器;
- _run_print_help()调用_run_command()函数来执行cmd;
这里要看的是_run_command()这个函数,由此函数开始,不同的命令调用不同的run函数执行。
四、总结
scrapy的执行从scrapy_home/bin/scrapy这个脚本开始,调用cmdline这个模块。cmdline模块完成命令的解析,配置的读取和设置等等一系列工作,更具不同的命令将调用对应的模块来继续完成该命令的工作。每个具体的命令对应于一个scrapy_home/scrapy/commands包下具体的模块的一个模块。而这些命令都是ScrapyCommand这个类的子类,均override了run()这个函数,各命令的run()来完成自己不同的工作。