使用Scrapy串行抓取域名

时间:2016-11-02 10:43:15

标签: python scrapy web-crawler scrapy-spider

我在DB中有网站我想连续抓取,即:

  1. 将域添加到允许的域列表(应为空)。
  2. 将此域添加到请求中(将http://添加到其中可以正常运行)。
  3. 抓取请求,关于允许的域名。
  4. 前进到下一个域,仅将其添加到允许的域列表中。它将是唯一一个,所以不会发生纵横交错。注意:criss-cross question对我没有帮助,但也许我错过了一些东西......
  5. 抓取此请求。
  6. 完成我拥有的所有域名 - 连续。
  7. 到目前为止,我所取得的成就是抓取域名,它做得非常好,它可以完美地抓取请求。 我遇到的唯一问题是allowed_domains似乎没有更新,它会抓取各种网站。

    我设置DEPTH_LIMIT=1所以它不会是无限爬行,我也添加了DF抓取而不是BF抓取:

    DEPTH_LIMIT= 1
    SCHEDULER_DISK_QUEUE = 'scrapy.squeues.PickleFifoDiskQueue'
    SCHEDULER_MEMORY_QUEUE = 'scrapy.squeues.FifoMemoryQueue'
    

    这是我的蜘蛛的代码(只是开头;因为你真的不关心我的项目处理......):

    from __future__ import with_statement
    import scrapy
    from scrapy.spiders import CrawlSpider, Rule
    from scrapy.linkextractors import LinkExtractor
    from scrapy.http.request import Request
    from company.items import CompanyItem, UrlItem
    from urlparse import urlparse
    import MySQLdb
    import json
    
    
    class RecipeSpider(CrawlSpider):
        name = "company"
    
        allowed_domains = []
        start_urls = []
        rules = (Rule(LinkExtractor(allow=(), deny=(), tags=('a', 'link', 'li' 'area')), callback='extract_raw_recipe', follow=True),)
    
        def start_requests(self):
            # print "before sources"
            sources = self.get_allowed_domains()
            dummy_tuple = (long(len(sources) + 1), u'dummy', None, None, None, None, None, 0L, long(len(sources) + 1),)
            final_sources = sources + (dummy_tuple,)
    
            for source in final_sources:
                self.allowed_domains = [str(source[1])]
                url_string = str("http://" + source[1])
                self.start_urls = [url_string]
                self.update_running_source(source)
                yield Request(url_string, self.extract_raw_recipe)
        ### start_requests()
    
        def extract_raw_recipe(self, response):
            pass
    

    extract_raw_recipe的代码没有请求或解析下一个网址,它只是工作,所以不需要编辑它。但如果我需要在那里添加一些东西,请告诉我,因为这可能是缺失的链接。当前代码将字典添加到项目中,然后将此项目放入数据库中。

    总之:我需要添加什么才能在每次抓取请求时过滤域名?

    如果需要提供更多代码,请告诉我。

1 个答案:

答案 0 :(得分:3)

我的建议是采取完全不同的方法。在数据库中创建需要爬网的域的队列(基于您想要的任何条件),然后选择一个域进行爬网,并使用allowed_domains列表中的相关域初始化蜘蛛。蜘蛛完成后,重新开始下一个域的爬行。重复,直到队列中的所有域都完成。

这将使您对整个过程有更多的控制权(例如,重新排队失败的爬网,取消有问题的抓取和移动而不会丢失进度,一次抓取多个域而不会出现“串扰”等)如果您打算扩展它,它还允许您执行自定义设置(例如USER_AGENT,DUPEFILTER,DOWNLOAD_DELAY)或基于每个域的自定义规则,从而显着扩展蜘蛛的可用性。

如果这不是一个选项,您可以重置allowed_domains列表。这样做有一些问题,但首先是关于Scrapy异地过滤的一些背景知识。

OffSiteMiddleware负责根据allowed_domains编译允许的域列表。它使用了一个正则表达式,它只在蜘蛛启动时编译一次(使用spider_opened信号)。更新变量allowed_domains对蜘蛛没有影响,除非您还强制OffSideMiddleWare重新编译其正则表达式。

以下方法(放置在您的蜘蛛中)应该可用于将allowed_domains替换为新列表:

from scrapy.spidermiddlewares.offsite import OffsiteMiddleware

def change_allowed_domains(self, allowed_domains):
    self.allowed_domains = allowed_domains

    for middleware in self.crawler.engine.scraper.spidermw.middlewares:
        if isinstance(middleware, OffsiteMiddleware):
            middleware.spider_opened(self)

这会重置domains_seen使用的set() OffsiteMiddleware,因此如果您将其用于其他任何内容,请记住这一点。

所以,花一点时间来吸收所有这些问题,一个问题开始出现:当你在allowed_domains中对每个域进行排队时,当前更改start_requests()的方法将不起作用,因为{{ 1}}类仅跟踪一个Spider正则表达式(根本不与请求/响应对象关联)。如果在蜘蛛开始爬网之前将20个请求排队到不同的域(每次更改allowed_domains列表),它将使用最近编译的正则表达式(即最后排队的allowed_domains域)。

要解决此问题,您需要抓取一个域的所有请求,使用插槽编写自己的allowed_domains,并让它处理所有过滤。或者,只有在队列中的所有请求都完成后,才能创建一个不同的将下一个域添加到列表中,并且下载器中的所有插槽都是空的(可能通过检查OffsiteMiddleware和`self.crawler.engine.slot。调度器)。

祝你好运!