scrapy的meta的作用就是在执行scrapy.Request()
函数时把一些回掉函数中需要的数据传进去,meta必须是一个字典,在下一个函数中可以使用response.meta
防问,这里需要注意的是,meta传递的数据是浅拷贝传递的,如果传递的数据是可变的数据类型,那么很容易造成数据不对应的错误,以下是本人在工作中的遇到此问题的代码片段:
def parse_jinyan(self, response):
'''评论页'''
doctorId = response.xpath('//script').re('doctorId:"(\d+)"')
if not doctorId:
return
base_url = 'https://m.haodf.com/ndoctor/ajaxshowlist?is2YearsAgo={params[is2YearsAgo]}&diseasename={params[diseasename]}&diseasekey={params[diseasekey]}&doctorPinyin={params[doctorPinyin]}&doctorId={params[doctorId]}&pinyinRef={params[pinyinRef]}&sn={params[sn]}&diseaseId={params[diseaseId]}&num={params[num]}&size={params[size]}&time={params[time]}&_t={params[_t]}'
# url参数
params = {
'is2YearsAgo': '1',
'diseasename': '全部',
'diseasekey': 'all',
'doctorPinyin': response.meta['doctorPinyin'],
'doctorId': doctorId[0],
'pinyinRef': response.meta['pinyinRef'],
'sn': response.meta['sn'],
'diseaseId': '',
'num': '1',
'size': '10',
'time': '',
'_t': str(int(time.time() * 1000))
}
# 两年前的评论
if self.scope == 'allComment':
yield scrapy.FormRequest(
url=base_url.format(params=params),
meta={'hid': response.meta['hid'], 'ddid': response.meta['ddid'], 'base_url': base_url,
'params': copy.deepcopy(params), 'num': 1},
callback=self.parse_comment,
errback=self.request_errback)
# 两年内的评论
is_twoyears = response.xpath('//ul[contains(@class,"vote-ul")]')
if is_twoyears:
params['is2YearsAgo'] = '0'
for li in is_twoyears.xpath('./li[@class="vote-li js-vote-li " and not(@data-disease="all")]'):
diseaseId = li.xpath('./@data-id').extract_first()
diseasename = li.xpath('./@data-name').extract_first()
diseasekey = li.xpath('./@data-disease').extract_first()
params['diseasename'] = diseasename
params['diseasekey'] = diseasekey
params['diseaseId'] = diseaseId
yield scrapy.FormRequest(
url=base_url.format(params=params),
meta={'hid': response.meta['hid'], 'ddid': response.meta['ddid'], 'base_url': base_url,
'params': copy.deepcopy(params), 'num': 1},
callback=self.parse_comment,
errback=self.request_errback)
else:
print '两年内没有获得评论'
以上要将params等信息传递到下一个解析方法,params是一个字典,字典是可变的数据类型,for循环中会对params字典进行修改,然后再进行传递,如果没有对params进行深拷贝的话,会造成params在下一个解析方法中出现数据不对应的情况,因为scrapy是将请求Request对象扔到队列中的,是一个异步采集框架,所以params如果是浅拷贝的话,只是拷贝了对象的引用而没有拷贝数据本身,当scrapy用请求对象发送请求并将返回结果给下一个解析方法后,接收到的meta里的数据是可以被操作修改的,所以params是会被for循环不断的修改,从而接收到的数据是被修改过后的数据。通过深拷贝可以解决该问题。
欢迎关注公众号:日常bug,每天写至少一篇技术文章,每天进步一点点。