【问题标题】:scrapy passing custom_settings to spider from script using CrawlerProcess.crawl()使用 CrawlerProcess.crawl() 从脚本将 custom_settings 传递给蜘蛛
【发布时间】:2017-07-19 14:30:59
【问题描述】:

我正在尝试通过脚本以编程方式调用蜘蛛。我无法使用 CrawlerProcess 通过构造函数覆盖设置。让我用从官方scrapy网站上抓取引号的默认蜘蛛来说明这一点(最后一个代码sn-p在official scrapy quotes example spider)。

class QuotesSpider(Spider):

    name = "quotes"

    def __init__(self, somestring, *args, **kwargs):
        super(QuotesSpider, self).__init__(*args, **kwargs)
        self.somestring = somestring
        self.custom_settings = kwargs


    def start_requests(self):
        urls = [
            'http://quotes.toscrape.com/page/1/',
            'http://quotes.toscrape.com/page/2/',
        ]
        for url in urls:
            yield Request(url=url, callback=self.parse)

    def parse(self, response):
        for quote in response.css('div.quote'):
            yield {
                'text': quote.css('span.text::text').extract_first(),
                'author': quote.css('small.author::text').extract_first(),
                'tags': quote.css('div.tags a.tag::text').extract(),
            }

这是我尝试运行引号蜘蛛的脚本

from scrapy.crawler import CrawlerProcess
from scrapy.utils.project import get_project_settings
from scrapy.settings import Settings

    def main():

    proc = CrawlerProcess(get_project_settings())

    custom_settings_spider = \
    {
        'FEED_URI': 'quotes.csv',
        'LOG_FILE': 'quotes.log'
    }
    proc.crawl('quotes', 'dummyinput', **custom_settings_spider)
    proc.start()

【问题讨论】:

    标签: python-3.x web-scraping scrapy scrapy-spider scrapinghub


    【解决方案1】:

    Scrapy 设置有点像 Python 字典。 所以你可以在传递给CrawlerProcess之前更新设置对象:

    from scrapy.crawler import CrawlerProcess
    from scrapy.utils.project import get_project_settings
    from scrapy.settings import Settings
    
    def main():
    
        s = get_project_settings()
        s.update({
            'FEED_URI': 'quotes.csv',
            'LOG_FILE': 'quotes.log'
        })
        proc = CrawlerProcess(s)
    
        proc.crawl('quotes', 'dummyinput', **custom_settings_spider)
        proc.start()
    

    编辑以下 OP 的 cmets:

    这是一个使用 CrawlerRunner 的变体,每次爬网都有一个新的 CrawlerRunner,并在每次迭代时重新配置日志记录以每次写入不同的文件:

    import logging
    from twisted.internet import reactor, defer
    
    import scrapy
    from scrapy.crawler import CrawlerRunner
    from scrapy.utils.log import configure_logging, _get_handler
    from scrapy.utils.project import get_project_settings
    
    
    class QuotesSpider(scrapy.Spider):
        name = "quotes"
    
        def start_requests(self):
            page = getattr(self, 'page', 1)
            yield scrapy.Request('http://quotes.toscrape.com/page/{}/'.format(page),
                                 self.parse)
    
        def parse(self, response):
            for quote in response.css('div.quote'):
                yield {
                    'text': quote.css('span.text::text').extract_first(),
                    'author': quote.css('small.author::text').extract_first(),
                    'tags': quote.css('div.tags a.tag::text').extract(),
                }
    
    
    @defer.inlineCallbacks
    def crawl():
        s = get_project_settings()
        for i in range(1, 4):
            s.update({
                'FEED_URI': 'quotes%03d.csv' % i,
                'LOG_FILE': 'quotes%03d.log' % i
            })
    
            # manually configure logging for LOG_FILE
            configure_logging(settings=s, install_root_handler=False)
            logging.root.setLevel(logging.NOTSET)
            handler = _get_handler(s)
            logging.root.addHandler(handler)
    
            runner = CrawlerRunner(s)
            yield runner.crawl(QuotesSpider, page=i)
    
            # reset root handler
            logging.root.removeHandler(handler)
        reactor.stop()
    
    crawl()
    reactor.run() # the script will block here until the last crawl call is finished
    

    【讨论】:

    • 对于我的用例,我需要使用 proc.crawl() 为蜘蛛的每次运行传递一个 .csv 文件。我想要有 1 个爬虫进程(使用通用设置),但是使用不同的名称连续调用 crawl 以用于日志和 csv 提要输出。我可以使用 scrapy 实现这一点吗?
    • @hAcKnRoCk 你可以在调用CrawlerProcess 时使用for 循环,并在那里更新设置,而不是覆盖custom_settings
    • @hAcKnRoCk,你看过Running multiple spiders in the same process中的最后一个例子吗,即用CrawlerRunner顺序运行蜘蛛?
    • @eLRuLL:是的,我已经尝试过使用 for 循环。代码位于pastebin.com/RTnUWntQ。我在第二次迭代期间收到“twisted.internet.error.ReactorNotRestartable”错误。
    • @paultrmbrth 是的,我确实看到了那个例子。但我不确定它是否适合我的用例。问题中的问题仍然存在。每次运行都会给我一个 .csv 和一个 .log 文件,我将无法运行我的蜘蛛。
    【解决方案2】:

    我认为您不能在将 Spider 类作为脚本调用时覆盖其 custom_settings 变量,主要是因为设置是在蜘蛛实例化之前加载的。

    现在,我没有真正看到具体更改 custom_settings 变量的意义,因为它只是一种覆盖默认设置的方法,而这正是 CrawlerProcess 提供的,这可以按预期工作:

    import scrapy
    from scrapy.crawler import CrawlerProcess
    
    
    class MySpider(scrapy.Spider):
        name = 'simple'
        start_urls = ['http://httpbin.org/headers']
    
        def parse(self, response):
            for k, v in self.settings.items():
                print('{}: {}'.format(k, v))
            yield {
                'headers': response.body
            }
    
    process = CrawlerProcess({
        'USER_AGENT': 'my custom user anget',
        'ANYKEY': 'any value',
    })
    
    process.crawl(MySpider)
    process.start()
    

    【讨论】:

    • 能够覆盖 custom_settings 的关键是这个。我希望能够执行 'crawl('myspider', list1_urlstoscrape, 'list1output.csv', 'list1.log' )',然后再次执行 'crawl('myspider', list2_urlstoscrape, 'list2output.csv', 'list2.log')。因此,为了实现这一点,我必须创建多个 CrawlerProcess 实例,由于捻线反应器问题,这是不可能的。
    • 你可以改变你的蜘蛛代码来一次接收多个列表,然后处理每个
    • 是的,但问题仍然存在。问题不在于传递要抓取的输入列表,而是说明您希望每个列表的输出如何(即,对于同一蜘蛛的每次爬网)。
    【解决方案3】:

    您似乎希望为每个蜘蛛拥有自定义日志。您需要像这样激活日志记录:

    from scrapy.utils.log import configure_logging
    
    class MySpider(scrapy.Spider):
        #ommited
        def __init__(self):
            configure_logging({'LOG_FILE' : "logs/mylog.log"})
    

    【讨论】:

    • 这实际上在一个非常独特的情况下帮助了我,我有一个调用 api 的蜘蛛和多个可以与蜘蛛一起使用的“帐户”。谢谢!
    【解决方案4】:

    您可以从命令行覆盖设置

    https://doc.scrapy.org/en/latest/topics/settings.html#command-line-options

    例如:scrapy crawl myspider -s LOG_FILE=scrapy.log

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-03-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-08
      • 1970-01-01
      相关资源
      最近更新 更多