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.这些文 ...
随机推荐
- centos7安装nginx,以及使用node测试反向代理
1.添加nginx的安装源 vi /etc/yum.repos.d/nginx.repo 2.输入下面内容,并保存退出 [nginx] name=nginx repo baseurl=http://n ...
- Python【每日一问】09
问:请分别写一段Python代码实现一下功能: (1)计算一个文件中的大写字母数量 (2)输入中文,返回相应的拼音,并写入文件中 答: (1)计算一个文件中的大写字母数量 file_name = &q ...
- python32模拟鼠标和键盘操作
前言Windows pywin32允许你像vc一样的形式来使用python开发win32应用.代码风格可以类似win32 sdk,也可以类似MFC,由你选择.如果你仍不放弃vc一样的代码过程在pyth ...
- Java tomcat Several ports (8005, 8080, 8009) required by Tomcat v9.0 Server at localhost
关于 下面问题是因为(8005, 8080, 8009) 被原tomcat占用了. Several ports (8005, 8080, 8009) required by Tomcat v9.0 S ...
- 8、Zookeeper分布式锁
基础知识:http://www.cnblogs.com/LiZhiW/p/4931577.html 1 可重入读写锁示例代码如下(lock.acquire加几个,就必须使用几个lock.release ...
- Three failed attempts of handling non-sequential data
The Progress of Products Classification Cause now we are considering to classify the product by two ...
- IDEA overwrite报错、languagelevel设置不生效问题
发现idea 倒入项目后,发现@override报错,发现是idea的jdk版本不对,需要设置大于1.5的jdk版本 解决办法: IDEA:File >> Project Structur ...
- azkaban使用--邮件发送配置
前置条件:你的服务器是可以连外网. 当任务是异步定时的,我们对于结果的感知往往没有手动跑脚本那么及时,但是如果任何一个任务运行失败可能都会引起一些列问题,在这个情况下消息通知就很重要了,azkaban ...
- node环境
下载教程:http://www.runoob.com/nodejs/nodejs-install-setup.html 选择版本下载:https://nodejs.org/en/download/ 输 ...
- element-ui:el-table时间格式化
如果想对表格某一列的内容格式化,可用 formatter 属性.属性绑定格式化的方法即可 <el-table-column prop="update_time" label= ...