前言

虽然爬虫的入门级编写并不难,但要让爬虫真正稳定可靠的运行起来,真不是一件容易的事。
首先,要用到scrapy,就必须要读懂scrapy这个爬虫框架,如果连这个框架的执行逻辑都搞不懂,那么爬虫也很难写好。

1.命令行启动

这里先不谈使用了各种框架的复杂情况,比如scrapyd服务、redis分布式队列等。只看最简单的情况,假设只写了几个简单爬虫spider(中间件和管道写不写无影响)。

输入命令

通过命令行运行其中的某一个spider:

  1. scrapy crawl myspider

首先,命令里的scrapy是一个可执行文件,后面的crawl myspider是scrapy的参数。
可执行文件scrapy在/usr/local/python/bin目录里,是一个python脚本,有效代码为:

  1. from scrapy.cmdline import execute
  2. if __name__ == '__main__':
  3. sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
  4. sys.exit(execute())

这个文件的作用就是从命令行里读取命令,然后传递给scrapy.cmdline包的execute()方法进行下一步操作。

execute()方法

从python的第三方库目录里找到scrapy/cmdline.py文件,可以看到代码中有execute()方法(为了压缩篇幅,这里删掉了无关紧要的代码):

  1. def execute(argv=None, settings=None):
  2. if argv is None:
  3. argv = sys.argv
  4.  
  5. if settings is None:
  6. settings = get_project_settings()
  7. # set EDITOR from environment if available
  8. try:
  9. editor = os.environ['EDITOR']
  10. except KeyError: pass
  11. else:
  12. settings['EDITOR'] = editor
  13. check_deprecated_settings(settings)
  14.  
  15. inproject = inside_project()
  16. cmds = _get_commands_dict(settings, inproject)
  17. cmdname = _pop_command_name(argv)
  18. parser = optparse.OptionParser(formatter=optparse.TitledHelpFormatter(), \
  19. conflict_handler='resolve')
  20. if not cmdname:
  21. _print_commands(settings, inproject)
  22. sys.exit(0)
  23. elif cmdname not in cmds:
  24. _print_unknown_command(settings, cmdname, inproject)
  25. sys.exit(2)
  26.  
  27. cmd = cmds[cmdname]
  28. parser.usage = "scrapy %s %s" % (cmdname, cmd.syntax())
  29. parser.description = cmd.long_desc()
  30. settings.setdict(cmd.default_settings, priority='command')
  31. cmd.settings = settings
  32. cmd.add_options(parser)
  33. opts, args = parser.parse_args(args=argv[1:])
  34. _run_print_help(parser, cmd.process_options, args, opts)
  35.  
  36. cmd.crawler_process = CrawlerProcess(settings)
  37. _run_print_help(parser, _run_command, cmd, args, opts)
  38. sys.exit(cmd.exitcode)
  39.  
  40. def _run_command(cmd, args, opts):
  41. if opts.profile:
  42. _run_command_profiled(cmd, args, opts)
  43. else:
  44. 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:

  1. def run(self, args, opts):
  2. if len(args) < 1:
  3. raise UsageError()
  4. elif len(args) > 1:
  5. raise UsageError("running 'scrapy crawl' with more than one spider is no longer supported")
  6. spname = args[0]
  7.  
  8. self.crawler_process.crawl(spname, **opts.spargs)
  9. self.crawler_process.start()

这里有2个重要操作:
1.调用CrawlerProcess的crawl方法,执行初始化(创建新爬虫对象)。
2.调用CrawlerProcess的start方法,正式运行。
CrawlerProcess便是scrapy运行过程中最根本的进程,是所有爬虫运行的基础。

附:get_project_settings()导入配置文件的过程

scrapy/utils/project.py:

  1. ...
  2. ENVVAR = 'SCRAPY_SETTINGS_MODULE'
  3. ...
  4. def get_project_settings():
  5. if ENVVAR not in os.environ:
  6. project = os.environ.get('SCRAPY_PROJECT', 'default')
  7. init_env(project)
  8.  
  9. settings = Settings()
  10. settings_module_path = os.environ.get(ENVVAR)
  11. if settings_module_path:
  12. settings.setmodule(settings_module_path, priority='project')
  13.  
  14. # XXX: remove this hack
  15. pickled_settings = os.environ.get("SCRAPY_PICKLED_SETTINGS_TO_OVERRIDE")
  16. if pickled_settings:
  17. settings.setdict(pickle.loads(pickled_settings), priority='project')
  18.  
  19. # XXX: deprecate and remove this functionality
  20. env_overrides = {k[7:]: v for k, v in os.environ.items() if
  21. k.startswith('SCRAPY_')}
  22. if env_overrides:
  23. settings.setdict(env_overrides, priority='project')
  24.  
  25. return settings

get_project_settings会首先判断是否设置了SCRAPY_SETTINGS_MODULE环境变量,这个环境变量用来指定工程的配置模块。如果没有这个环境变量,则会调用init_env来初始化环境变量,由于我们没有设置SCRAPY_PROJECT,所以会用default默认值来执行init_env(在scrapy/utils/conf.py)。

scrapy/utils/conf.py:

  1. def init_env(project='default', set_syspath=True):
  2. """Initialize environment to use command-line tool from inside a project
  3. dir. This sets the Scrapy settings module and modifies the Python path to
  4. be able to locate the project module.
  5. """
  6. cfg = get_config()
  7. if cfg.has_option('settings', project):
  8. os.environ['SCRAPY_SETTINGS_MODULE'] = cfg.get('settings', project)
  9. closest = closest_scrapy_cfg()
  10. if closest:
  11. projdir = os.path.dirname(closest)
  12. if set_syspath and projdir not in sys.path:
  13. sys.path.append(projdir)
  14.  
  15. def get_config(use_closest=True):
  16. """Get Scrapy config file as a SafeConfigParser"""
  17. sources = get_sources(use_closest)
  18. cfg = SafeConfigParser()
  19. cfg.read(sources)
  20. return cfg
  21.  
  22. def get_sources(use_closest=True):
  23. xdg_config_home = os.environ.get('XDG_CONFIG_HOME') or \
  24. os.path.expanduser('~/.config')
  25. sources = ['/etc/scrapy.cfg', r'c:\scrapy\scrapy.cfg',
  26. xdg_config_home + '/scrapy.cfg',
  27. os.path.expanduser('~/.scrapy.cfg')]
  28. if use_closest:
  29. sources.append(closest_scrapy_cfg())
  30. 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。这个文件的内容很简单:

  1. [settings]
  2. default = myspider.settings
  3. [deploy]
  4. #url = http://localhost:6800/
  5. 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 源码解析 (一):启动流程源码分析(一)命令行启动的更多相关文章

  1. Android Activity启动流程源码全解析(1)

    前言 Activity是Android四大组件的老大,我们对它的生命周期方法调用顺序都烂熟于心了,可是这些生命周期方法到底是怎么调用的呢?在启动它的时候会用到startActivty这个方法,但是这个 ...

  2. Android Activity启动流程源码全解析(2)

    接上之前的分析 ++Android Activity启动流程源码全解析(1)++ 1.正在运行的Activity调用startPausingLocked 一个一个分析,先来看看startPausing ...

  3. Spring IOC容器启动流程源码解析(四)——初始化单实例bean阶段

    目录 1. 引言 2. 初始化bean的入口 3 尝试从当前容器及其父容器的缓存中获取bean 3.1 获取真正的beanName 3.2 尝试从当前容器的缓存中获取bean 3.3 从父容器中查找b ...

  4. 【图解源码】Zookeeper3.7源码分析,包含服务启动流程源码、网络通信源码、RequestProcessor处理请求源码

    Zookeeper3.7源码剖析 能力目标 能基于Maven导入最新版Zookeeper源码 能说出Zookeeper单机启动流程 理解Zookeeper默认通信中4个线程的作用 掌握Zookeepe ...

  5. Spark(四十九):Spark On YARN启动流程源码分析(一)

    引导: 该篇章主要讲解执行spark-submit.sh提交到将任务提交给Yarn阶段代码分析. spark-submit的入口函数 一般提交一个spark作业的方式采用spark-submit来提交 ...

  6. Spring IOC 容器预启动流程源码探析

    Spring IOC 容器预启动流程源码探析 在应用程序中,一般是通过创建ClassPathXmlApplicationContext或AnnotationConfigApplicationConte ...

  7. Spark(五十一):Spark On YARN(Yarn-Cluster模式)启动流程源码分析(二)

    上篇<Spark(四十九):Spark On YARN启动流程源码分析(一)>我们讲到启动SparkContext初始化,ApplicationMaster启动资源中,讲解的内容明显不完整 ...

  8. scrapy 源码解析 (二):启动流程源码分析(二) CrawlerProcess主进程

    CrawlerProcess主进程 它控制了twisted的reactor,也就是整个事件循环.它负责配置reactor并启动事件循环,最后在所有爬取结束后停止reactor.另外还控制了一些信号操作 ...

  9. ZooKeeper单机客户端的启动流程源码阅读

    客户端的启动流程 看上面的客户端启动的脚本图,可以看到,zookeeper客户端脚本运行的入口ZookeeperMain.java的main()方法, 关于这个类可以理解成它是程序启动的辅助类,由它提 ...

随机推荐

  1. <VCC笔记> Assumption

    接下来是第二种注释语句类型Assumption.语法_(Assume E), 这个表达式是让VCC在接下来的额推理中,无视表达式E, 直接认可表达式E. 例: int x, y; _(assume x ...

  2. C#构造函数 -0028

    默认构造函数 声明基本构造函数的语法就是声明一个与类同名的方法,但该方法没有返回类型: public class MyClass { public MyClass() { } // rest of c ...

  3. 008.OpenShift Metric应用

    一 METRICS子系统组件 1.1 metric架构介绍 OpenShift metric子系统支持捕获和长期存储OpenShift集群的性能度量,收集节点以及节点中运行的所有容器的指标. metr ...

  4. JavaWeb网上图书商城完整项目--day02-7.提交注册表单功能之流程分析

    1.点击注册之后将提交的信息传递到UserServlet的public String regist方法进行处理,然后将东西通过service进行处理 业务流程:

  5. springboot项目打war包发布到外置tomcat

    第一步:修改pom.xml 1. <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> ...

  6. xeus-clickhouse: Jupyter 的 ClickHouse 内核

    在科学计算领域,Jupyter 是一个使用非常广泛的集成开发环境,它支持多种主流的编程语言比如 Python, C++, R 或者 Julia.同时,数据科学最重要的还是数据,而 SQL 是操作数据最 ...

  7. git和github入门指南(5)

    5.github上的标签 5.1.标签的作用 给当前版本打一个标签,在github上就会形成一个releases版本 点击进去后,用户就可以下载对应版本的源代码 5.2.在本地git工具上创建标签,同 ...

  8. git和github入门指南(3.1)

    3.远程管理 3.1.远程仓库相关命令 1.查看远程仓库名字,这里以github为例 git remote 上面命令执行后会得到:origin,这样一个名字,这个名字是我们克隆的时候默认设置好的 如果 ...

  9. 《UNIX环境高级编程》(APUE) 笔记第四章 - 文件和目录

    4 - 文件和目录 1. 函数 stat.fstat.fstatat 和 lstat #inlcude <sys/stat.h> int stat(const char *restrict ...

  10. Windows使用VNC远程连接Linux桌面系统

    sudo yum -y install tigervnc-server  #安装 su - your_user #切换用户 vncpasswd #设置密码 sudo cp /lib/systemd/s ...