美文网首页
关于Scrapy爬虫数据传递问题

关于Scrapy爬虫数据传递问题

作者: Anomaly | 来源:发表于2017-07-13 15:52 被阅读0次

    问题:

    这两天研究爬虫掉进一个大坑,爬了好久才爬出去,这里说几句,我写的爬图片的爬虫很简单,从一个图片列表进二级图片详情页,然后爬取二级详情页的所有图片,但是有个需求就是需要以二级详情页的标题为目录分类存放图片!思路很简单,就是在item里面增加一个字段title存放标题:

    class PicscrapyItem(scrapy.Item):
        image_urls = scrapy.Field() # 图片地址
        images = scrapy.Field()
        title = scrapy.Field() # 图片标题(目录)
    

    然后在pipelines里面获取item里面数据,保存的时候做一下处理:

    class PicscrapyPipeline(ImagesPipeline):
        item = []
        def get_media_requests(self, item, info):
            self.item = item
            return [Request(x) for x in item.get(self.images_urls_field, [])]
    
        # 重写函数,修改了下载图片名称的生成规则
        def file_path(self, request, response=None, info=None):
            if not isinstance(request, Request):
                url = request
            else:
                url = request.url
            url = urlparse(url)
            img_name = url.path.split('/')[5].split('.')[0]
            return self.item['title'] + '/%s.jpg' % img_name
    

    上面的代码看上去没毛病,重写了Scrapy框架ImagesPipeline的方法,根据title字段分目录存放,但是当我跑起来的时候看上去也没毛病,但是查看数据的时候却不对了,目录是出来了,但是牛头不对马嘴!


    分析:

    研究了好久我才发现问题就在于多线程,Scrapy框架默认是开启多线程的,在settings里面有个字段可以定义开启的线程数,默认是开启16个线程同时爬取:

    # Configure maximum concurrent requests performed by Scrapy (default: 16)
    # CONCURRENT_REQUESTS = 32
    

    我上面的代码如果是单线程运行没毛病,但是多线程的话,数据是共享的,就会错乱,导致图片保存的位置根本不是我想要的结果,怎么解决呢?

    1. settings

    在settings里面设置线程数为1,釜底抽薪,不过即使这样设置,偶尔也会出现错乱,这种方法牺牲了爬取效率,不可取

    2. meta

    我之所以采取类共享的方式传递item是因为在file_path函数内部我无法获取到item的值,后来,网上查了好久发现有一种方式可以在函数间安全传递数据,就是request的meta属性,所以正确的做法如下:

    class PicscrapyPipeline(ImagesPipeline):
        def get_media_requests(self, item, info):
            return [Request(x, meta={'title': item['title']}) for x in item.get(self.images_urls_field, [])]
    
        # 重写函数,修改了下载图片名称的生成规则
        def file_path(self, request, response=None, info=None):
            if not isinstance(request, Request):
                url = request
            else:
                url = request.url
            url = urlparse(url)
            img_name = url.path.split('/')[5].split('.')[0]
            return request.meta['title'] + '/%s.jpg' % img_name
    

    然后问题解决,新技能get!

    相关文章

      网友评论

          本文标题:关于Scrapy爬虫数据传递问题

          本文链接:https://www.haomeiwen.com/subject/ujgwhxtx.html