运行Scrapy的Django自定义管理命令:如何包含Scrapy的选项?

时间:2012-05-12 13:59:26

标签: python django scrapy

我希望能够从Django中运行Scrapy web crawling framework。 Scrapy本身仅提供命令行工具scrapy来执行其命令,即该工具不是故意编写的,而是从外部程序调用。

用户Mikhail Korobov提出nice solution,即从Django自定义管理命令调用Scrapy。为方便起见,我在此重复他的解决方案:

# -*- coding: utf-8 -*-
# myapp/management/commands/scrapy.py 

from __future__ import absolute_import
from django.core.management.base import BaseCommand

class Command(BaseCommand):

    def run_from_argv(self, argv):
        self._argv = argv
        return super(Command, self).run_from_argv(argv)

    def handle(self, *args, **options):
        from scrapy.cmdline import execute
        execute(self._argv[1:])

而不是呼叫,例如scrapy crawl domain.com我现在可以在Django项目中执行python manage.py scrapy crawl domain.com。但是,Scrapy命令的选项根本不会被解析。如果我python manage.py scrapy crawl domain.com -o scraped_data.json -t json,我只会收到以下回复:

Usage: manage.py scrapy [options] 

manage.py: error: no such option: -o

所以我的问题是,如何扩展自定义管理命令以采用Scrapy的命令行选项?

不幸的是,Django的documentation of this part并不是很广泛。我还阅读了Python optparse module的文档,但事后对我来说并不清楚。谁能在这方面帮助我?非常感谢提前!

2 个答案:

答案 0 :(得分:5)

好的,我找到了解决问题的方法。这有点难看,但它确实有效。由于Django项目的manage.py命令不接受Scrapy的命令行选项,因此我将选项字符串拆分为manage.py接受的两个参数。解析成功后,我重新加入这两个参数并将它们传递给Scrapy。

也就是说,而不是写

python manage.py scrapy crawl domain.com -o scraped_data.json -t json

我在这些选项之间添加了空格

python manage.py scrapy crawl domain.com - o scraped_data.json - t json

我的句柄功能如下所示:

def handle(self, *args, **options):
    arguments = self._argv[1:]
    for arg in arguments:
        if arg in ('-', '--'):
            i = arguments.index(arg)
            new_arg = ''.join((arguments[i], arguments[i+1]))
            del arguments[i:i+2]
            arguments.insert(i, new_arg)

    from scrapy.cmdline import execute
    execute(arguments)

与此同时,Mikhail Korobov提供了最佳解决方案。见这里:

# -*- coding: utf-8 -*- 
# myapp/management/commands/scrapy.py 

from __future__ import absolute_import
from django.core.management.base import BaseCommand

class Command(BaseCommand):

    def run_from_argv(self, argv):
        self._argv = argv
        self.execute()

    def handle(self, *args, **options):
        from scrapy.cmdline import execute
        execute(self._argv[1:])

答案 1 :(得分:3)

我认为你真的在寻找POSIX argument syntax conventions准则10

  

参数 - 应该被接受为表示选项结束的分隔符。   以下任何参数都应被视为操作数,即使它们开头也是如此   人物。 - 参数不应该用作选项或操作数。

Python的optparse模块就是这样,即使在windows下也是如此。

我将scrapy项目设置模块放在参数列表中,因此我可以在独立的应用程序中创建单独的scrapy项目:

# <app>/management/commands/scrapy.py
from __future__ import absolute_import
import os

from django.core.management.base import BaseCommand

class Command(BaseCommand):
    def handle(self, *args, **options):
        os.environ['SCRAPY_SETTINGS_MODULE'] = args[0]
        from scrapy.cmdline import execute
        # scrapy ignores args[0], requires a mutable seq
        execute(list(args))

调用如下:

python manage.py scrapy myapp.scrapyproj.settings crawl domain.com -- -o scraped_data.json -t json

使用scrapy 0.12和django 1.3.1进行测试