问题:
这两天研究爬虫掉进一个大坑,爬了好久才爬出去,这里说几句,我写的爬图片的爬虫很简单,从一个图片列表进二级图片详情页,然后爬取二级详情页的所有图片,但是有个需求就是需要以二级详情页的标题为目录分类存放图片!思路很简单,就是在item里面增加一个字段title存放标题:
1 | class PicscrapyItem(scrapy.Item): |
然后在pipelines里面获取item里面数据,保存的时候做一下处理:
1 | class PicscrapyPipeline(ImagesPipeline): |
上面的代码看上去没毛病,重写了Scrapy框架ImagesPipeline的方法,根据title字段分目录存放,但是当我跑起来的时候看上去也没毛病,但是查看数据的时候却不对了,目录是出来了,但是牛头不对马嘴!
分析:
研究了好久我才发现问题就在于多线程,Scrapy框架默认是开启多线程的,在settings里面有个字段可以定义开启的线程数,默认是开启16个线程同时爬取:
1 | # Configure maximum concurrent requests performed by Scrapy (default: 16) |
我上面的代码如果是单线程运行没毛病,但是多线程的话,数据是共享的,就会错乱,导致图片保存的位置根本不是我想要的结果,怎么解决呢?
1. settings
在settings里面设置线程数为1,釜底抽薪,不过即使这样设置,偶尔也会出现错乱,这种方法牺牲了爬取效率,不可取
2. meta
我之所以采取类共享的方式传递item是因为在file_path函数内部我无法获取到item的值,后来,网上查了好久发现有一种方式可以在函数间安全传递数据,就是request的meta属性,所以正确的做法如下:
1 | class PicscrapyPipeline(ImagesPipeline): |
然后问题解决,新技能get!