只抓取URL一次的Scrapy spider



我正在编写一个Scrapy spider,它每天抓取一组URL一次。然而,其中一些网站非常大,所以我不能每天爬满整个网站,也不想产生这样做所需的大量流量。

一个老问题(这里)提出了类似的问题。然而,投票支持的响应只是指向一个代码片段(此处),该代码片段似乎需要请求实例的某些内容,尽管响应中没有对此进行解释,也没有在包含代码片段的页面上进行解释。

我试图理解这一点,但发现中间件有点令人困惑。无论是否使用链接中间件,一个可以多次运行而无需重新编译URL的scraper的完整示例都非常有用。

我在下面发布了一些代码来开始工作,但我不一定需要使用这个中间件。任何能每天爬行并提取新URL的抓取蜘蛛都可以。显然,一种解决方案是只写一本抓取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)

事情是这样的,您想要做的是能够拥有一个数据库,对其进行爬网。dupfiler.middleware或不你仍然必须刮整个网站不管。。。我觉得,尽管很明显,所提供的代码不可能是整个项目,但WAYY的代码太多了。

我不太确定你在抓取什么,但我假设现在你有CNN作为你抓取文章的项目URL?

我会做的是使用CNNs的RSS提要,甚至网站地图,提供文章元的截止日期,并使用操作系统模块。。。

定义每个爬网实例的日期使用regex将爬网程序定义的日期与文章发布的日期进行逐项限制部署并计划爬网到scratchhub使用scratchinghubs python api客户端迭代项目

仍然会抓取整个网站的内容,但使用xmlspider或rsspader类非常适合更快地解析所有数据。。。现在数据库在"云中"可用。。。我觉得一个可以更模块化,具有项目的扩展能力,也更容易移植/交叉兼容性

我确信我描述的流程会受到一些修改,但这个想法是直截了当的。

最新更新