Исходный код Scrapy (2) — где запускается сканер

Python рептилия
这是崔斯特的第三十三篇原创文章

начать учитьсяScrapyИсходный код (๑• . •๑)

Команда запуска Scrapy

В общем, способ запуска проекта Scrapy (запуск Scrapy из скрипта здесь не рассматривается)


                                                            
Usage examples:
$ scrapy crawl myspider
[ ... myspider starts crawling ... ]
$ scrapy runspider myspider.py
[ ... spider starts crawling ... ]

                                                        

Но лучший способ написать это — создать новый файл Python следующим образом (для легкой отладки):


                                                            
from scrapy import cmdline
cmdline.execute("scrapy crawl myspider".split())

                                                        

Легко обнаружить, что файл запуска Scrapycmdline.pyв файлеexecute()функция, давайте узнаем, что делает эта функция.

Анализировать исходный код


                                                            
def execute(argv=None, settings=None):
    if argv is None:
        argv = sys.argv
    # --- backwards compatibility for scrapy.conf.settings singleton ---
    if settings is None and 'scrapy.conf' in sys.modules:
        from scrapy import conf
        if hasattr(conf, 'settings'):
            settings = conf.settings
    # ------------------------------------------------------------------

                                                        

Поискscrapy.confФайл конфигурации, 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)
# --- backwards compatibility for scrapy.conf.settings singleton ---
import warnings
from scrapy.exceptions import ScrapyDeprecationWarning
with warnings.catch_warnings():
    warnings.simplefilter("ignore", ScrapyDeprecationWarning)
    from scrapy import conf
    conf.settings = settings
# ------------------------------------------------------------------

                                                        

set EDITOR from environment if available

читатьsettingsустановочный файл, импорт проекта, вызовget_project_settings()функция, здесьutilsв папкеproject.pyдокумент:


                                                            
def get_project_settings():
    if ENVVAR not in os.environ:
        project = os.environ.get('SCRAPY_PROJECT', 'default')
        init_env(project)

                                                        

project.py

init_env()Функция выглядит следующим образом:


                                                            
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)

                                                        

conf.py

Как сказано в комментарии, инициализируйте среду, рекурсивно найдите файл конфигурации в пользовательском проекте.settings.py, и установите его в переменную окруженияScrapy settings moduleсередина. Затем измените путь Python, чтобы модуль проекта можно было найти.


                                                            

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

                                                        

project.py

Слишком далеко,get_project_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)

                                                        

Импортируйте соответствующий модуль обходчика модуля (inside_project)

Независимо от того, находится ли среда выполнения в проекте, в основном проверьте, существует ли файл конфигурации scrapy.cfg, прочитайте папку команд и преобразуйте все классы команд в{cmd_name: cmd_instance}Словарь


                                                            
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)

                                                        

Найдите соответствующий экземпляр команды в соответствии с именем команды, установите конфигурацию и уровень проекта для команды, добавьте правила синтаксического анализа, проанализируйте параметры команды и передайте их экземпляру команды Scrapy для обработки.

Наконец, взгляните на код ниже.


                                                            
cmd.crawler_process = CrawlerProcess(settings)
_run_print_help(parser, _run_command, cmd, args, opts)
sys.exit(cmd.exitcode)

                                                        

инициализацияCrawlerProcessПример, выполните соответствующую команду, вотcrawl


                                                            
def _run_command(cmd, args, opts):
    if opts.profile:
        _run_command_profiled(cmd, args, opts)
    else:
        cmd.run(args, opts)

                                                        

Увидев это, я вспомнил введение в документеRun Scrapy from a script


                                                            
# Here’s an example showing how to run a single spider with it.
import scrapy
from scrapy.crawler import CrawlerProcess
class MySpider(scrapy.Spider):
    # Your spider definition
    ...
process = CrawlerProcess({
    'USER_AGENT': 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)'
})
process.crawl(MySpider)
process.start() # the script will block here until the crawling is finished

                                                        

Так что прогоны сканера Scrapy полезны для использованияCrawlerProcess, если вы хотите узнать больше, вы можете перейти к исходному кодуscrapy/scrapy/crawler.py


                                                            
"""
A class to run multiple scrapy crawlers in a process simultaneously.
This class extends :class:`~scrapy.crawler.CrawlerRunner` by adding support
for starting a Twisted `reactor`_ and handling shutdown signals, like the
keyboard interrupt command Ctrl-C. It also configures top-level logging.
This utility should be a better fit than
:class:`~scrapy.crawler.CrawlerRunner` if you aren't running another
Twisted `reactor`_ within your application.
The CrawlerProcess object must be instantiated with a
:class:`~scrapy.settings.Settings` object.
:param install_root_handler: whether to install root logging handler
    (default: True)
This class shouldn't be needed (since Scrapy is responsible of using it
accordingly) unless writing scripts that manually handle the crawling
process. See :ref:`run-from-script` for an example.
"""

                                                        

Наконец, прикрепите карту путей Scrapy.

Суммировать

Проще говоря, есть следующие шаги:

  1. Прочитайте файл конфигурации и примените его к сканеру.
  2. Преобразование всех классов команд в словарь имен и экземпляров
  3. инициализацияCrawlerProcessНапример, запустить сканер

(Это головная боль, я не могу вспомнить много имен функций)

рассмотрение:

  1. Исходный код Scrapy (1) — обзор процесса сканирования
  2. Исходный код Scrapy (2) — где запускается сканер