一旦Spider的爬取的深度比较深时,数据的提取基本上是贯穿每一层的,为了将数据一层一层传递下去,我们需要将上一层提取的数据传递到下一层,供下一层使用,这时我们就需要使用的scrapy.Request的meta参数,其是一个字典。在传递不变数据时,不需要担心,但是我们传递的是一个Item类型或字典,这两者都属于可变类型,恰好又与scrapy的异步机制发生了碰撞,当我们将一个字典(或者Item)装进meta里面时,Item就会从Spider经过Engine最终到Pipeline,如果在这期间,Item被修改了,那么被Pipeline过滤、加工、存储的Item也会相应的改变,简而言之就是浅拷贝的问题,解决方法深拷贝。
所以最终建议使用copy.deepcopy函数进行深拷贝
def parse(self, response): province_list = response.xpath("//div[@class=‘city_province‘]") for province in province_list: province_name = province.xpath("./div/text()").get() city_list = province.xpath("./ul/li/a") for city in city_list: item = {} city_name = city.xpath("./text()").get() city_url = city.xpath("./@href").get() # 链接分为两类:没有二手房的链接和有二手房的链接 if "fang" in city_url: continue # print(province_name, city_name, city_url) # 将所有城市的链接转化为二手房的链接 city_esf_url = city_url + "ershoufang/co32/" item["province"] = province_name item["city"] = city_name yield scrapy.Request(url=city_esf_url, callback=self.parse_city, meta={"item": copy.deepcopy(item)})
另外建议,进行深拷贝的位置也是有讲究的,必须在meta里进行深拷贝,否则也会出现重复。