scrapy 源码解析 (一):启动流程源码分析(一)命令行启动
前言
虽然爬虫的入门级编写并不难,但要让爬虫真正稳定可靠的运行起来,真不是一件容易的事。
首先,要用到scrapy,就必须要读懂scrapy这个爬虫框架,如果连这个框架的执行逻辑都搞不懂,那么爬虫也很难写好。
1.命令行启动
这里先不谈使用了各种框架的复杂情况,比如scrapyd服务、redis分布式队列等。只看最简单的情况,假设只写了几个简单爬虫spider(中间件和管道写不写无影响)。
输入命令
通过命令行运行其中的某一个spider:
- scrapy crawl myspider
首先,命令里的scrapy是一个可执行文件,后面的crawl myspider是scrapy的参数。
可执行文件scrapy在/usr/local/python/bin目录里,是一个python脚本,有效代码为:
- from scrapy.cmdline import execute
- if __name__ == '__main__':
- sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
- sys.exit(execute())
这个文件的作用就是从命令行里读取命令,然后传递给scrapy.cmdline包的execute()方法进行下一步操作。
execute()方法
从python的第三方库目录里找到scrapy/cmdline.py文件,可以看到代码中有execute()方法(为了压缩篇幅,这里删掉了无关紧要的代码):
- def execute(argv=None, settings=None):
- if argv is None:
- argv = sys.argv
- if settings is None:
- settings = get_project_settings()
- # set EDITOR from environment if available
- try:
- editor = os.environ['EDITOR']
- except KeyError: pass
- else:
- settings['EDITOR'] = editor
- check_deprecated_settings(settings)
- inproject = inside_project()
- cmds = _get_commands_dict(settings, inproject)
- cmdname = _pop_command_name(argv)
- parser = optparse.OptionParser(formatter=optparse.TitledHelpFormatter(), \
- conflict_handler='resolve')
- if not cmdname:
- _print_commands(settings, inproject)
- sys.exit(0)
- elif cmdname not in cmds:
- _print_unknown_command(settings, cmdname, inproject)
- sys.exit(2)
- cmd = cmds[cmdname]
- parser.usage = "scrapy %s %s" % (cmdname, cmd.syntax())
- parser.description = cmd.long_desc()
- settings.setdict(cmd.default_settings, priority='command')
- cmd.settings = settings
- cmd.add_options(parser)
- opts, args = parser.parse_args(args=argv[1:])
- _run_print_help(parser, cmd.process_options, args, opts)
- cmd.crawler_process = CrawlerProcess(settings)
- _run_print_help(parser, _run_command, cmd, args, opts)
- sys.exit(cmd.exitcode)
- def _run_command(cmd, args, opts):
- if opts.profile:
- _run_command_profiled(cmd, args, opts)
- else:
- cmd.run(args, opts)
此方法中的重要操作有:
1.执行get_project_settings()方法,导入全局配置文件scrapy.cfg,进而导入项目的settings .py。这里用到了scrapy/utils/project.py中的get_project_settings()方法,这里先不展开。
2.解析命令行scrapy之后的命令,并把命令中的配置项导入到settings中,中间的一大段代码就是执行此功能,每个有效的命令均对应scrapy/commands中以命令命名的文件中的Command类。
3.cmd.crawler_process = CrawlerProcess(settings)这句代码建立CrawlerProcess对象,并把所有的设置settings传递给此对象。
4._run_print_help(parser, _run_command, cmd, args, opts)调用_run_command执行命令。如果指定了profile命令行参数,则用cProfile运行命令,cProfile是一个标准模块,这里不必考虑。无论如何,最后都会执行命令的run()方法,也就是scrapy/commands/crawl.py中Command类的run()方法。
执行crawl命令
scrapy/commands/crawl.py#Command:
- def run(self, args, opts):
- if len(args) < 1:
- raise UsageError()
- elif len(args) > 1:
- raise UsageError("running 'scrapy crawl' with more than one spider is no longer supported")
- spname = args[0]
- self.crawler_process.crawl(spname, **opts.spargs)
- self.crawler_process.start()
这里有2个重要操作:
1.调用CrawlerProcess的crawl方法,执行初始化(创建新爬虫对象)。
2.调用CrawlerProcess的start方法,正式运行。
CrawlerProcess便是scrapy运行过程中最根本的进程,是所有爬虫运行的基础。
附:get_project_settings()导入配置文件的过程
scrapy/utils/project.py:
- ...
- ENVVAR = 'SCRAPY_SETTINGS_MODULE'
- ...
- def get_project_settings():
- if ENVVAR not in os.environ:
- project = os.environ.get('SCRAPY_PROJECT', 'default')
- init_env(project)
- settings = Settings()
- settings_module_path = os.environ.get(ENVVAR)
- if settings_module_path:
- settings.setmodule(settings_module_path, priority='project')
- # XXX: remove this hack
- pickled_settings = os.environ.get("SCRAPY_PICKLED_SETTINGS_TO_OVERRIDE")
- if pickled_settings:
- settings.setdict(pickle.loads(pickled_settings), priority='project')
- # XXX: deprecate and remove this functionality
- env_overrides = {k[7:]: v for k, v in os.environ.items() if
- k.startswith('SCRAPY_')}
- if env_overrides:
- settings.setdict(env_overrides, priority='project')
- return settings
get_project_settings会首先判断是否设置了SCRAPY_SETTINGS_MODULE环境变量,这个环境变量用来指定工程的配置模块。如果没有这个环境变量,则会调用init_env来初始化环境变量,由于我们没有设置SCRAPY_PROJECT,所以会用default默认值来执行init_env(在scrapy/utils/conf.py)。
scrapy/utils/conf.py:
- def init_env(project='default', set_syspath=True):
- """Initialize environment to use command-line tool from inside a project
- dir. This sets the Scrapy settings module and modifies the Python path to
- be able to locate the project module.
- """
- cfg = get_config()
- if cfg.has_option('settings', project):
- os.environ['SCRAPY_SETTINGS_MODULE'] = cfg.get('settings', project)
- closest = closest_scrapy_cfg()
- if closest:
- projdir = os.path.dirname(closest)
- if set_syspath and projdir not in sys.path:
- sys.path.append(projdir)
- def get_config(use_closest=True):
- """Get Scrapy config file as a SafeConfigParser"""
- sources = get_sources(use_closest)
- cfg = SafeConfigParser()
- cfg.read(sources)
- return cfg
- def get_sources(use_closest=True):
- xdg_config_home = os.environ.get('XDG_CONFIG_HOME') or \
- os.path.expanduser('~/.config')
- sources = ['/etc/scrapy.cfg', r'c:\scrapy\scrapy.cfg',
- xdg_config_home + '/scrapy.cfg',
- os.path.expanduser('~/.scrapy.cfg')]
- if use_closest:
- sources.append(closest_scrapy_cfg())
- return sources
init_env首先调用get_config()获取cfg配置文件,这个配置文件获取的优先级是:
1./etc/scrapy.cfg,c:\scrapy\scrapy.cfg
2.XDG_CONFIG_HOME环境变量指定的目录下的scrapy.cfg
3.~/.scrapy.cfg
4.当前执行目录下的scrapy.cfg或者父目录中的scrapy.cfg
由于1,2,3默认都不设置,所以就使用当前执行命令下的scrapy.cfg,也就是工程目录下的scrapy.cfg。这个文件的内容很简单:
- [settings]
- default = myspider.settings
- [deploy]
- #url = http://localhost:6800/
- project = myspider
根据default = myspider.settings找到对应的配置模块,后面会执行一系列导入settings.py配置项的操作,过程其实很复杂,这里不再详细说了。
————————————————
版权声明:本文为CSDN博主「csdn_yym」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/csdn_yym/java/article/details/85420528
scrapy 源码解析 (一):启动流程源码分析(一)命令行启动的更多相关文章
- Android Activity启动流程源码全解析(1)
前言 Activity是Android四大组件的老大,我们对它的生命周期方法调用顺序都烂熟于心了,可是这些生命周期方法到底是怎么调用的呢?在启动它的时候会用到startActivty这个方法,但是这个 ...
- Android Activity启动流程源码全解析(2)
接上之前的分析 ++Android Activity启动流程源码全解析(1)++ 1.正在运行的Activity调用startPausingLocked 一个一个分析,先来看看startPausing ...
- Spring IOC容器启动流程源码解析(四)——初始化单实例bean阶段
目录 1. 引言 2. 初始化bean的入口 3 尝试从当前容器及其父容器的缓存中获取bean 3.1 获取真正的beanName 3.2 尝试从当前容器的缓存中获取bean 3.3 从父容器中查找b ...
- 【图解源码】Zookeeper3.7源码分析,包含服务启动流程源码、网络通信源码、RequestProcessor处理请求源码
Zookeeper3.7源码剖析 能力目标 能基于Maven导入最新版Zookeeper源码 能说出Zookeeper单机启动流程 理解Zookeeper默认通信中4个线程的作用 掌握Zookeepe ...
- Spark(四十九):Spark On YARN启动流程源码分析(一)
引导: 该篇章主要讲解执行spark-submit.sh提交到将任务提交给Yarn阶段代码分析. spark-submit的入口函数 一般提交一个spark作业的方式采用spark-submit来提交 ...
- Spring IOC 容器预启动流程源码探析
Spring IOC 容器预启动流程源码探析 在应用程序中,一般是通过创建ClassPathXmlApplicationContext或AnnotationConfigApplicationConte ...
- Spark(五十一):Spark On YARN(Yarn-Cluster模式)启动流程源码分析(二)
上篇<Spark(四十九):Spark On YARN启动流程源码分析(一)>我们讲到启动SparkContext初始化,ApplicationMaster启动资源中,讲解的内容明显不完整 ...
- scrapy 源码解析 (二):启动流程源码分析(二) CrawlerProcess主进程
CrawlerProcess主进程 它控制了twisted的reactor,也就是整个事件循环.它负责配置reactor并启动事件循环,最后在所有爬取结束后停止reactor.另外还控制了一些信号操作 ...
- ZooKeeper单机客户端的启动流程源码阅读
客户端的启动流程 看上面的客户端启动的脚本图,可以看到,zookeeper客户端脚本运行的入口ZookeeperMain.java的main()方法, 关于这个类可以理解成它是程序启动的辅助类,由它提 ...
随机推荐
- <VCC笔记> Assumption
接下来是第二种注释语句类型Assumption.语法_(Assume E), 这个表达式是让VCC在接下来的额推理中,无视表达式E, 直接认可表达式E. 例: int x, y; _(assume x ...
- C#构造函数 -0028
默认构造函数 声明基本构造函数的语法就是声明一个与类同名的方法,但该方法没有返回类型: public class MyClass { public MyClass() { } // rest of c ...
- 008.OpenShift Metric应用
一 METRICS子系统组件 1.1 metric架构介绍 OpenShift metric子系统支持捕获和长期存储OpenShift集群的性能度量,收集节点以及节点中运行的所有容器的指标. metr ...
- JavaWeb网上图书商城完整项目--day02-7.提交注册表单功能之流程分析
1.点击注册之后将提交的信息传递到UserServlet的public String regist方法进行处理,然后将东西通过service进行处理 业务流程:
- springboot项目打war包发布到外置tomcat
第一步:修改pom.xml 1. <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> ...
- xeus-clickhouse: Jupyter 的 ClickHouse 内核
在科学计算领域,Jupyter 是一个使用非常广泛的集成开发环境,它支持多种主流的编程语言比如 Python, C++, R 或者 Julia.同时,数据科学最重要的还是数据,而 SQL 是操作数据最 ...
- git和github入门指南(5)
5.github上的标签 5.1.标签的作用 给当前版本打一个标签,在github上就会形成一个releases版本 点击进去后,用户就可以下载对应版本的源代码 5.2.在本地git工具上创建标签,同 ...
- git和github入门指南(3.1)
3.远程管理 3.1.远程仓库相关命令 1.查看远程仓库名字,这里以github为例 git remote 上面命令执行后会得到:origin,这样一个名字,这个名字是我们克隆的时候默认设置好的 如果 ...
- 《UNIX环境高级编程》(APUE) 笔记第四章 - 文件和目录
4 - 文件和目录 1. 函数 stat.fstat.fstatat 和 lstat #inlcude <sys/stat.h> int stat(const char *restrict ...
- Windows使用VNC远程连接Linux桌面系统
sudo yum -y install tigervnc-server #安装 su - your_user #切换用户 vncpasswd #设置密码 sudo cp /lib/systemd/s ...