scrapy meta信息丢失
在做58同城爬二手房时,由于房产详情页内对价格进行了转码处理,所以只能从获取详情页url时同时获取该url对应房产的价格,并通过meta传递给下回调函数
现在问题是,在回调函数中找不到原函数meta信息:
Traceback (most recent call last):
File "c:\users\chen\python36\lib\site-packages\scrapy\utils\defer.py", line 102, in iter_errback
yield next(it)
File "c:\users\chen\python36\lib\site-packages\scrapy\spidermiddlewares\offsite.py", line 30, in process_spider_output
for x in result:
File "c:\users\chen\python36\lib\site-packages\scrapy\spidermiddlewares\referer.py", line 339, in <genexpr>
return (_set_referer(r) for r in result or ())
File "c:\users\chen\python36\lib\site-packages\scrapy\spidermiddlewares\urllength.py", line 37, in <genexpr>
return (r for r in result or () if _filter(r))
File "c:\users\chen\python36\lib\site-packages\scrapy\spidermiddlewares\depth.py", line 58, in <genexpr>
return (r for r in result or () if _filter(r))
File "D:\oldHouse\oldHouse\spiders\old58House.py", line 69, in parse_detail
item = response.meta['item']
KeyError: 'item'
我第一猜想是由于请求经过各种retry重试,和rediret到jump_url、firewall上面,在这个过程中retry和redirect中间件是不是只拿到相应的url而没有保存原来的meta信息,这两个中间件对请求是怎么处理的
1.先看redirect中间件:scrapy.downloadermiddlewares.redirect.BaseRedirectMiddleware,重点代码位于_redirect方法
def _redirect(self, redirected, request, spider, reason):
ttl = request.meta.setdefault('redirect_ttl', self.max_redirect_times)
redirects = request.meta.get('redirect_times', 0) + 1 if ttl and redirects <= self.max_redirect_times:
redirected.meta['redirect_times'] = redirects
redirected.meta['redirect_ttl'] = ttl - 1
redirected.meta['redirect_urls'] = request.meta.get('redirect_urls', []) + \
[request.url]
redirected.dont_filter = request.dont_filter
redirected.priority = request.priority + self.priority_adjust
logger.debug("Redirecting (%(reason)s) to %(redirected)s from %(request)s",
{'reason': reason, 'redirected': redirected, 'request': request},
extra={'spider': spider})
return redirected
else:
logger.debug("Discarding %(request)s: max redirections reached",
{'request': request}, extra={'spider': spider})
raise IgnoreRequest("max redirections reached")
可以看到_redirect方法涉及到meta操作主要是刷新最大重试次数和已经重试次数,并没有丢失原有的meta信息
2.再看retry中间件:scrapy.downloadermiddlewares.retry.BaseRetryMiddleware,重点代码位于_redirect方法
def _retry(self, request, reason, spider):
retries = request.meta.get('retry_times', 0) + 1 retry_times = self.max_retry_times if 'max_retry_times' in request.meta:
retry_times = request.meta['max_retry_times'] stats = spider.crawler.stats
if retries <= retry_times:
logger.debug("Retrying %(request)s (failed %(retries)d times): %(reason)s",
{'request': request, 'retries': retries, 'reason': reason},
extra={'spider': spider})
retryreq = request.copy()
retryreq.meta['retry_times'] = retries
retryreq.dont_filter = True
retryreq.priority = request.priority + self.priority_adjust if isinstance(reason, Exception):
reason = global_object_name(reason.__class__) stats.inc_value('retry/count')
stats.inc_value('retry/reason_count/%s' % reason)
return retryreq
可以看到_retry方法涉及到meta操作主要是刷新重试次数,并未丢失原有meta信息
事实上,框架没有错,我开始的猜想也没错,错在我定制的edirect中间件修改了meta信息:
return Request(request.url, callback=spider.parse_detail, dont_filter=True)
我在real_url重定向到firewall上时,不允许它重定向,而是继续请求到real_url,重要的是没有携带real_url的meta信息,所以meta就是在这里丢失的!
第一次修改:
return Request(request.url, callback=spider.parse_detail, meta=response.meta, dont_filter=True)
由于我debug到redirect中间件中,response.url和request.url是一样的,所以我认为meta=response.meta和request.meta都是一样的效果,这是错误的,这样会报如下错误:
"Response.meta not available, this response is not tied to any request"
意思是这个response响应没有绑定给任何request,通过源码发现,response绑定给request是在引擎中发生的:
source:scrapy.core.engine.py line230~line241 in scrapy version 1.5.0
def _download(self, request, spider):
slot = self.slot
slot.add_request(request)
def _on_success(response):
assert isinstance(response, (Response, Request))
if isinstance(response, Response):
response.request = request # tie request to response received
logkws = self.logformatter.crawled(request, response, spider)
logger.log(*logformatter_adapter(logkws), extra={'spider': spider})
self.signals.send_catch_log(signal=signals.response_received, \
response=response, request=request, spider=spider)
return response
从请求到spider过程是这样的:
1)request --> 2)downloadmiddleware --> 3)downloader --> 4)downloadmiddleware --> 5)engine --> 6)spidermiddleware --> 7)spider
而当前在4)处,将response绑定给request的操作还未发生,自然就会报错了(ps:spider中使用response.meta是因为在位置7,所以可以拿到)
第二次修改:
return Request(request.url, callback=spider.parse_detail, meta=request.meta, dont_filter=True)
结果很顺利拿到meta信息。
这次也带给我一个教训,程序出现问题,首先从自己身上找问题,而不是找项目问题,scrapy还是很强大的
scrapy meta信息丢失的更多相关文章
- HBase2.0 meta信息丢失的修复方法
在HBase入库日志中发现有一个表入库失败,检查HBase服务端后发现该表的meta信息丢失了: 而HDFS上的region还在: 而HBCK工具不支持HBase2.0版本,只好自己写一个修复工具.网 ...
- 【Discuz】云平台服务:出了点小错,由于站点ID/通信KEY等关键信息丢失导致Discuz!云平台服务出现异常
提示信息 出了点小错,由于站点ID/通信KEY等关键信息丢失导致Discuz!云平台服务出现异常 版本X3.2.20160601 解决方案 Step1.修改云平台开通状态为未开通状态 Step2.访问 ...
- 使用JDBC获取各数据库的Meta信息——表以及对应的列
先贴代码,作为草稿: 第一个是工具类, MapUtil.java [java] view plain copy import java.util.ArrayList; import java.util ...
- IE=edge,chrome=1的META信息详解
这几天在玩 HTML5 ★ Boilerplate,注意到meta信息中有这么一句: 复制代码 代码如下: <meta http-equiv="X-UA-Compatible" ...
- FFmpeg开发实战(三):FFmpeg 打印音视频Meta信息
在之前使用FFmpeg命令行的时候,我们经常看到FFmpeg命令行在输出音视频文件的会打印一下文件的Meta信息,类似如图: 那么我们如何通过代码的方式输出这些Meta信息呢? FFmpeg提供了一个 ...
- Web前端开发最佳实践(4):在页面中添加必要的meta信息
meta标签放置在HTML页面的head中,主要用于标识网站.其中基本上包含了网站的一些描述信息,例如,简介.作者等.这些信息有助于搜索引擎更准确地识别网页的内容,也有助于第三方工具抓取网站基本信息. ...
- Raid信息丢失数据恢复及oracle数据库恢复验证方案
早些时候,有个客户14块盘的磁盘阵列出现故障,需要恢复的数据是oracle数据库,客户在寻求数据恢复技术支持,要求我提供详细的数据恢复方案,以下是提供给客户的详细数据恢复解决方案,本方案包含Raid数 ...
- 安居客scrapy房产信息爬取到数据可视化(下)-可视化代码
接上篇:安居客scrapy房产信息爬取到数据可视化(下)-可视化代码,可视化的实现~ 先看看保存的数据吧~ 本人之前都是习惯把爬到的数据保存到本地json文件, 这次保存到数据库后发现使用mongod ...
- 采集网站特殊文件Meta信息
采集网站特殊文件Meta信息 元(Meta)信息是描述文件的属性的特殊信息,如文件的所有者.联系方式.机构名.邮件地址等信息.而网站中常常会有共享的文档文件,如PDF.Excel.Word.这些文 ...
随机推荐
- JS代码简单一段即可破解QQ空间删除说说
代码如下: 简单的一段代码即可搞定啦!!是不是很简单! var delay = 1000; function del() { document.querySelector('.app_canvas_f ...
- git学习手记(也许仅对本人有用)
首先明白git的三种状态 commited已提交 =====>git仓库(存着各种版本)modified已修改(此时就是我们的编辑器中的未保存状态)====>工作目录staged暂存状态= ...
- asp微信支付代码证书文件post_url.aspx和post_url.aspx.cs源码下载
很多朋友在网上找的asp支付代码中都没有这两个证书文件,只能是用别人的,但是如果别人把他的网站这个文件删了,你的支付也就不能用了,今天我就把大家需要的这两个asp微信支付代码证书文件post_url. ...
- On-die termination for DDR
本文转载自: https://blog.csdn.net/weixin_38233274/article/details/81016870 ODT是什么鬼?为什么要用ODT?在很多关于DDR3的博文和 ...
- Mock及Mockito使用
mockito http://www.vogella.com/tutorials/Mockito/article.html 原文地址: http://www.open-open.com/lib/vie ...
- python 日期换算星期 蔡勒公式
#!/usr/bin/env python # encoding: utf-8 #coding=utf-8 date_star={ ':'星期一', ':'星期二', ':'星期三', ':'星期四' ...
- Tmux 常用快捷键
Ctrl-b : Send the prefix key through to the application. " : Split the current pane into two, t ...
- QMap迭代器
QMap<int, QString> intToStr; intToStr[] = "test" for (auto iter = intToStr.begin(); ...
- LeetCode 145. Binary Tree Postorder Traversal 二叉树的后序遍历 C++
Given a binary tree, return the postorder traversal of its nodes' values. Example: Input: [,,] \ / O ...
- QPixmap 在非QtCreator环境下无法显示jpg图片
这几天需要实现在Qt界面中显示jpg图片,于是直接将路径传给QPixmap对象,发现显示不出来. 然而在Qt SDK自带的Demo中却可以正确显示jpg图片,经搜索引擎查找发现,是自己的exe文件缺少 ...