在做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信息丢失的更多相关文章

  1. HBase2.0 meta信息丢失的修复方法

    在HBase入库日志中发现有一个表入库失败,检查HBase服务端后发现该表的meta信息丢失了: 而HDFS上的region还在: 而HBCK工具不支持HBase2.0版本,只好自己写一个修复工具.网 ...

  2. 【Discuz】云平台服务:出了点小错,由于站点ID/通信KEY等关键信息丢失导致Discuz!云平台服务出现异常

    提示信息 出了点小错,由于站点ID/通信KEY等关键信息丢失导致Discuz!云平台服务出现异常 版本X3.2.20160601 解决方案 Step1.修改云平台开通状态为未开通状态 Step2.访问 ...

  3. 使用JDBC获取各数据库的Meta信息——表以及对应的列

    先贴代码,作为草稿: 第一个是工具类, MapUtil.java [java] view plain copy import java.util.ArrayList; import java.util ...

  4. IE=edge,chrome=1的META信息详解

    这几天在玩 HTML5 ★ Boilerplate,注意到meta信息中有这么一句: 复制代码 代码如下: <meta http-equiv="X-UA-Compatible" ...

  5. FFmpeg开发实战(三):FFmpeg 打印音视频Meta信息

    在之前使用FFmpeg命令行的时候,我们经常看到FFmpeg命令行在输出音视频文件的会打印一下文件的Meta信息,类似如图: 那么我们如何通过代码的方式输出这些Meta信息呢? FFmpeg提供了一个 ...

  6. Web前端开发最佳实践(4):在页面中添加必要的meta信息

    meta标签放置在HTML页面的head中,主要用于标识网站.其中基本上包含了网站的一些描述信息,例如,简介.作者等.这些信息有助于搜索引擎更准确地识别网页的内容,也有助于第三方工具抓取网站基本信息. ...

  7. Raid信息丢失数据恢复及oracle数据库恢复验证方案

    早些时候,有个客户14块盘的磁盘阵列出现故障,需要恢复的数据是oracle数据库,客户在寻求数据恢复技术支持,要求我提供详细的数据恢复方案,以下是提供给客户的详细数据恢复解决方案,本方案包含Raid数 ...

  8. 安居客scrapy房产信息爬取到数据可视化(下)-可视化代码

    接上篇:安居客scrapy房产信息爬取到数据可视化(下)-可视化代码,可视化的实现~ 先看看保存的数据吧~ 本人之前都是习惯把爬到的数据保存到本地json文件, 这次保存到数据库后发现使用mongod ...

  9. 采集网站特殊文件Meta信息

    采集网站特殊文件Meta信息   元(Meta)信息是描述文件的属性的特殊信息,如文件的所有者.联系方式.机构名.邮件地址等信息.而网站中常常会有共享的文档文件,如PDF.Excel.Word.这些文 ...

随机推荐

  1. html_学习地址

    源码地址: 玩安卓:https://www.wanandroid.com/project: 博客/博主地址:

  2. analyse idoc by creation date

    t-code ZMM0127 infoset: ZMM_IDOC_READ_01 go to code: AUTHORITY-CHECK OBJECT 'S_IDOCMONI'ID 'ACTVT' F ...

  3. [VS]VS2013中在一对大括号之间添加垂直虚线

  4. bat批量修改图片的名字实现(两种方法)

    问题描述: 业务中遇到需要批量修改大量图片的名字. 如下图,需要修改为图片名字“u=”之后和“,”之前的那一串 解决思路1: bat批处理,网上查找相关代码如下: @echo off SetLocal ...

  5. jquery datatable测试部分代码(仅自用)

    创建一个四列的datatable表,第四列为表格里的按钮设置,respond为JSON对象数组. $('#example').DataTable({        //每页显示十条数据        ...

  6. mybatis入门篇:代码生成器(MyBatis Generator)

    这篇文章只是按照自己的需要去配置代码生成器,未对所有配置进行讲解,需要了解具体详情的,请到官网查阅文档.传送门:http://www.mybatis.org/generator/ 1.首先引入相关的依 ...

  7. RestTemplate invoke JSON and convert to Object

    @Test public void webTest() throws JsonProcessingException { Map<String, String> a = new HashM ...

  8. Linux基础(学习过程记录)

    常用快捷键:Tab:使用Tab键来进行命令补全,补全目录.补全命令参数Ctrl+c键来强行终止当前程序Ctrl+d 键盘输入结束或退出终端Ctrl+s 暂停当前程序,暂停后按下任意键恢复运行Ctrl+ ...

  9. selenium常用的模块

    from selenium import webdriver #select模块处理下拉框from selenium.webdriver.support.ui import Select # Keys ...

  10. supersocket 遇到的Failed to initialize 和 log4net用法

    使用Bootstrap来通过配置启动SuperSocket的时候总是显示Failed to initialize!  , 官网配置中 <superSocket> <servers&g ...