scrapy里面item传递数据后数据不正确的问题

欢迎到我的个人博客阅读这篇文章,体验更好哦~

在上篇文章《python3 + scrapy 爬取妹子图 (meizitu.com)》中,我爬取了妹子图网站的图片,爬取是按照如下思路的:

  1. 通过首页(http://www.meizitu.com/),爬取标签名称tag_name和标签链接tag_href
  1. 通过标签链接,爬取当前标签下全部页面page_list
  1. 通过页面,爬取当前页面的图片专辑名称album_name和图片专辑链接album_href
  1. 通过专辑链接,爬取该专辑里面所有图片名称img_title、图片链接img_src及图片链接列表img_urls
  1. 通过图片链接列表,使用scrapy自带的图片下载器ImagesPipeline下载图片到设定的文件夹

然后我们的爬虫代码里面有4层,层与层之间通过meta参数传递数据,例如parseparse_page时,数据传递是yield scrapy.Request(url=item['tag_href'], meta={'item': item}, callback=self.parse_page),其他各层传递与这个一样,到最后一层的时候就yield item,供pipeline使用。

爬虫代码整个代码如下:

# -*- coding: utf-8 -*-

import scrapy

from meizitu.items import MeizituItem


class MztSpider(scrapy.Spider):
    name = 'mzt'
    allowed_domains = ['meizitu.com']
    start_urls = ['http://www.meizitu.com/']
    
    def parse(self, response):
        """
        提取标签名称和链接
        :param response:
        :return:
        """
        
        tags = response.xpath(".//*[@class='tags']/span/a")
        for i in tags:
            item = MeizituItem()
            tag_href = i.xpath(".//@href").extract()[0]
            tag_name = i.xpath(".//@title").extract()[0]
            item['tag_name'] = tag_name
            item['tag_href'] = tag_href
            yield scrapy.Request(url=item['tag_href'], meta={'item': item}, callback=self.parse_page)
    
    def parse_page(self, response):
        """
        提取标签下链接
        :param response:
        :return:
        """
        
        # 进入某个标签后,爬取底部分页按钮
        page_lists = response.xpath(".//*[@id='wp_page_numbers']/ul/li")
        # 获取底部分页按钮上的文字,根据文字来判断当前标签页下总共有多少分页
        page_list = page_lists.xpath('.//text()')
        # 如果当前标签页下有多个页面,则再根据第一个按钮是否为“首页”来进行再次提取,因为这里有的页面第一个按钮是“首页”,有的第一个按钮是“1”
        if len(page_lists) > 0:
            if page_list[0].extract() == '首页':
                page_num = len(page_lists) - 3
            
            else:
                page_num = len(page_lists) - 2
        else:
            page_num = 1
        
        # 根据当前标签页的链接,来拼成带页码的链接
        if '_' in response.url:
            index = response.url[::-1].index('_')
            href_pre = response.url[:-index]
        else:
            if page_num == 1:
                href_pre = response.url.split('.html')[0]
            else:
                href_pre = response.url.split('.html')[0] + '_'
        for i in range(1, page_num + 1):
            if page_num == 1:
                href = href_pre + '.html'
            else:
                href = href_pre + str(i) + '.html'
            item = response.meta['item']
            item['page_list'] = href
            
            yield scrapy.Request(url=item['page_list'], meta={'item': item}, callback=self.parse_album)
    
    def parse_album(self, response):
        """
        提取专辑名称和专辑链接
        :param response:
        :return:
        """
        
        albums = response.xpath(".//*[@class='pic']")
        for album in albums:
            album_href = album.xpath(".//a/@href").extract()[0]
            album_name = album.xpath(".//a/img/@alt").extract()[0]
            item = response.meta['item']
            item['album_name'] = album_name
            item['album_href'] = album_href
            
            yield scrapy.Request(url=item['album_href'], meta={'item': item}, callback=self.parse_img)
    
    def parse_img(self, response):
        """
        提取图片名称和链接
        :param response:
        :return:
        """
        
        img_list = response.xpath(".//p/img")
        
        for img in img_list:
            item = response.meta['item']
            img_title = img.xpath(".//@alt").extract()[0]
            if img_title == '':
                for i in range(1, len(img_list) + 1):
                    img_title = item['album_name'] + '_' + str(i)
            else:
                img_title = img_title
            img_urls = img.xpath(".//@src").extract()
            img_src = img.xpath(".//@src").extract()[0]
            item['img_title'] = img_title
            item['img_src'] = img_src
            item['img_urls'] = img_urls
            
            yield item

然后坑的地方就出现了,按照理想状态,最后的item数据每个都是唯一的,但是实际情况是最后的item很多数据都是重复和错乱的,要么只取了最后一张图片,要么图片和专辑对不上,完全不对。

后来在网上查了很久,终于找到这篇文章,作者的文章中说:

查找原因后,发现是因为使用 Request 函数传递 item 时,使用的是浅复制(对象的字段值被复制时,字段引用的对象不会被复制)

然后作者给出方法是,使用深复制,导入copy模块,将meta={'item': item} 更改为 meta={'item': copy.deepcopy(item)

果然,按照这个方法,把几个Request里面的都改了,数据是正常了。

但是,还没完。

此时,如果我打开ImagePipeline,再跑一遍查看数据,发现还是错乱的。

因为,最后yield item后,如果需要下载图片,ImagePipelineget_media_requests方法需要参数item,通过item获取图片URL再去下载,如果是浅拷贝就有可能跟上面的情况一样

于是我把爬虫里面的最后一行代码yield item 修改成 yield copy.deepcopy(item)就完全ok

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容