我使用的是最新的scrapy版本,v1.3
我通过按照分页中的网址逐页抓取网页。在某些页面中,网站检测到我使用机器人并在 html 中显示错误。由于它是一个成功的请求,它缓存了页面,当我再次运行它时,我得到了同样的错误。
我需要的是如何防止该页面进入缓存?或者,如果我不能这样做,我需要在意识到 parse 方法中的错误后将其从缓存中删除。然后我可以重试并得到正确的。
我有一个部分解决方案,我在元中使用“dont_cache”:False 参数生成所有请求,因此我确保它们使用缓存。在我检测到错误并重试请求的地方,我将 dont_filter=True 和 "dont_cache":True 放在一起,以确保我获得了错误 url 的新副本。
def parse(self, response):
page = response.meta["page"] + 1
html = Selector(response)
counttext = html.css('h2#s-result-count::text').extract_first()
if counttext is None:
page = page - 1
yield Request(url=response.url, callback=self.parse, meta={"page":page, "dont_cache":True}, dont_filter=True)
Run Code Online (Sandbox Code Playgroud)
我还尝试了一个自定义重试中间件,在缓存之前我设法让它工作,但我无法成功读取 response.body。我怀疑它以某种方式被压缩,因为它是二进制数据。
class CustomRetryMiddleware(RetryMiddleware):
def process_response(self, request, response, spider):
with open('debug.txt', 'wb') as outfile:
outfile.write(response.body)
html = Selector(text=response.body)
url = response.url
counttext = html.css('h2#s-result-count::text').extract_first()
if counttext is None:
log.msg("Automated process error: %s" %url, level=log.INFO)
reason = 'Automated process error %d' %response.status
return self._retry(request, reason, spider) or response
return response
Run Code Online (Sandbox Code Playgroud)
任何建议表示赞赏。
谢谢
穆罕默德
负责请求/响应缓存的中间件是HttpCacheMiddleware. 在幕后,它是由缓存策略驱动的 - 特殊类,用于调度应该或不应该缓存哪些请求和响应。您可以实现自己的缓存策略类并将其与设置一起使用
HTTPCACHE_POLICY = 'my.custom.cache.Class'
文档中的更多信息:https : //doc.scrapy.org/en/latest/topics/downloader-middleware.html#httpcache-middleware-settings
内置策略源码:https : //github.com/scrapy/scrapy/blob/master/scrapy/extensions/httpcache.py#L18
感谢 mizhgun,我设法使用自定义策略开发了一个解决方案。
这是我所做的,
from scrapy.utils.httpobj import urlparse_cached
class CustomPolicy(object):
def __init__(self, settings):
self.ignore_schemes = settings.getlist('HTTPCACHE_IGNORE_SCHEMES')
self.ignore_http_codes = [int(x) for x in settings.getlist('HTTPCACHE_IGNORE_HTTP_CODES')]
def should_cache_request(self, request):
return urlparse_cached(request).scheme not in self.ignore_schemes
def should_cache_response(self, response, request):
return response.status not in self.ignore_http_codes
def is_cached_response_fresh(self, response, request):
if "refresh_cache" in request.meta:
return False
return True
def is_cached_response_valid(self, cachedresponse, response, request):
if "refresh_cache" in request.meta:
return False
return True
Run Code Online (Sandbox Code Playgroud)
当我发现错误时,(当然发生缓存之后)
def parse(self, response):
html = Selector(response)
counttext = html.css('selector').extract_first()
if counttext is None:
yield Request(url=response.url, callback=self.parse, meta={"refresh_cache":True}, dont_filter=True)
Run Code Online (Sandbox Code Playgroud)
当您将 refresh_cache 添加到元中时,可以在自定义策略类中捕获。
不要忘记添加 dont_filter 否则第二个请求将被过滤为重复。
| 归档时间: |
|
| 查看次数: |
2512 次 |
| 最近记录: |