Scrapy蜘蛛,只能抓取一次网址

问题描述:

我正在写一个Scrapy蜘蛛,每天抓取一组网址。但是,这些网站中的一些非常大,所以我无法每天爬完整个网站,也不想生成必要的大量流量。Scrapy蜘蛛,只能抓取一次网址

一个老问题(here)问了类似的问题。然而,upvoted响应只是指向一个代码片段(here),它似乎需要某些请求实例,尽管这不在响应中解释,也不在包含代码片段的页面中解释。

我想弄明白这一点,但发现中间件有点混乱。无论是否使用链接的中间件,一个可以多次运行而无需重新创建URL的刮板的完整示例将非常有用。

我已经发布了下面的代码来实现滚动,但我不一定需要使用这个中间件。任何可以每天抓取并提取新网址的scrapy spider都可以。显然,一种解决方案是只写出一个刮掉的URL的字典,然后检查以确认每个新URL都不在字典中,但这似乎非常慢/效率低下。

蜘蛛

from scrapy.contrib.spiders import CrawlSpider, Rule 
from scrapy.contrib.linkextractors import LinkExtractor 
from cnn_scrapy.items import NewspaperItem 



class NewspaperSpider(CrawlSpider): 
    name = "newspaper" 
    allowed_domains = ["cnn.com"] 
    start_urls = [ 
     "http://www.cnn.com/" 
    ] 

    rules = (
     Rule(LinkExtractor(), callback="parse_item", follow=True), 
    ) 

    def parse_item(self, response): 
     self.log("Scraping: " + response.url) 
     item = NewspaperItem() 
     item["url"] = response.url 
     yield item 

项目

import scrapy 


class NewspaperItem(scrapy.Item): 
    url = scrapy.Field() 
    visit_id = scrapy.Field() 
    visit_status = scrapy.Field() 

中间件(ignore.py)

from scrapy import log 
from scrapy.http import Request 
from scrapy.item import BaseItem 
from scrapy.utils.request import request_fingerprint 

from cnn_scrapy.items import NewspaperItem 

class IgnoreVisitedItems(object): 
    """Middleware to ignore re-visiting item pages if they were already visited 
    before. The requests to be filtered by have a meta['filter_visited'] flag 
    enabled and optionally define an id to use for identifying them, which 
    defaults the request fingerprint, although you'd want to use the item id, 
    if you already have it beforehand to make it more robust. 
    """ 

    FILTER_VISITED = 'filter_visited' 
    VISITED_ID = 'visited_id' 
    CONTEXT_KEY = 'visited_ids' 

    def process_spider_output(self, response, result, spider): 
     context = getattr(spider, 'context', {}) 
     visited_ids = context.setdefault(self.CONTEXT_KEY, {}) 
     ret = [] 
     for x in result: 
      visited = False 
      if isinstance(x, Request): 
       if self.FILTER_VISITED in x.meta: 
        visit_id = self._visited_id(x) 
        if visit_id in visited_ids: 
         log.msg("Ignoring already visited: %s" % x.url, 
           level=log.INFO, spider=spider) 
         visited = True 
      elif isinstance(x, BaseItem): 
       visit_id = self._visited_id(response.request) 
       if visit_id: 
        visited_ids[visit_id] = True 
        x['visit_id'] = visit_id 
        x['visit_status'] = 'new' 
      if visited: 
       ret.append(NewspaperItem(visit_id=visit_id, visit_status='old')) 
      else: 
       ret.append(x) 
     return ret 

    def _visited_id(self, request): 
     return request.meta.get(self.VISITED_ID) or request_fingerprint(request) 
+0

以及在其他回复中需要找到的网址呢? – eLRuLL

+0

我假设我去过一个URL之后,在该页面上将找不到新的URL(除了start_urls)。或者我误解了你的问题? –

+1

没问题,那么我认为你的方法(或类似的方法)可以,想法是保存那些已经完成的方法,如果它们很多,我会推荐使用单独的数据库,Scrapy也会保存请求像指纹,这有助于他们自己的重复数据删除组件。 – eLRuLL

这里的东西,有什么ÿ你想要做的是能够有一个数据库,你的爬行调度​​/ croned。 dupflier.middleware或不是你仍然不得不刮起整个网站,尽管......我觉得尽管代码提供的不是显而易见的整个项目,那WAYY太多的代码。

我不完全确定你在搞什么,但是我现在要假设你有CNN作为你在刮文章的项目URL?

我会做什么是使用细胞神经网络的RSS源或给出甚至站点地图提供到期日与文章荟萃和使用OS模块...

定义的日期每个爬网实例 使用正则表达式限制与对日期的文章定义的日期爬虫明细表张贴 部署和安排抓取/在scrapinghub 使用scrapinghubs Python API中的客户端通过项目迭代

仍然会爬到整个网站的内容,但有xmlspider或rssspider类是完美的用于更快速地解析所有数据......现在,数据库是可用于“云”...我觉得人们可以更具模块化的项目的规模能力,以及更容易移植性/交叉兼容性

我确定描述流将受到一些修补,但这个想法很简单。