一旦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里進行深拷貝,否則也會出現重復。