9.3 项目实战:下载360图片
下面来完成一个使用ImagesPipeline下载图片的实战项目。360图片是一个知名的图片搜索网站,在浏览器中打开http://image.so.com,页面如图9.3-1所示。
9.3.1 项目需求
下载360图片网站中汽车分类下的所有图片到本地。
9.3.2 页面分析
在图9.3-1所示的页面中向下滚动鼠标滚轮,便会有更多图片加载出来,图片加载是由JavaScript脚本完成的,在图9.3.2-1中可以看到jQuery发送的请求,其响应结果是一个json串。
复制图中jQuery发送请求的url,使用scrapy shell进行访问,查看响应结果的内容(json):
$ (Scrapy_env) so_image>scrapy shell https://image.so.com/zjl?ch=car&listtype=new&sn=30
...
[s] Available Scrapy objects:
[s] scrapy scrapy module (contains scrapy.Request, scrapy.Selector, etc)
[s] crawler <scrapy.crawler.Crawler object at 0x000001A664818310>
[s] item {}
[s] request <GET https://image.so.com/zjl?ch=car>
[s] response <200 https://image.so.com/zjl?ch=car>
[s] settings <scrapy.settings.Settings object at 0x000001A664815DF0>
[s] spider <DefaultSpider 'default' at 0x1a664bdd520>
[s] Useful shortcuts:
[s] fetch(url[, redirect=True]) Fetch URL and update local objects (by default, redirects are followed)
[s] fetch(req) Fetch a scrapy.Request and update local objects
[s] shelp() Shell help (print this help)
[s] view(response) View response in a browser
>>> response
<200 https://image.so.com/zjl?ch=car>
>>> import json
>>> res =json.loads(response.body.decode('utf-8'))
>>> res
{'end': False,
'count': 30,
'lastid': 30,
'prevsn': '0',
'list': [{
'id': 'f5661fd288648a3f07161687b66575ca',
'index': 1,
'grpmd5': '7544f034562ec9531b290745fe82266f',
'grpseq': '1',
'grpcnt': '1',
'imgkey': 't0108d75cea79237c90.jpg',
'width': '1024',
'height': '768',
'title': '【美车致】未来科技 Rinspeed Etos',
'imgurl': 'http://img1c.xgo-img.com.cn/pics/2547/2546478.jpg',
'purl': 'http://photo.58che.com/car/14285_2546478.html',
'site': 'photo.58che.com',
'imgsize': '0',
'label': '概念车',
'sitename': '58che.com',
'siteid': '11943280',
'src': '0',
'fnum': '0',
'qhimg_thumb_width': 200,
'qhimg_thumb_height':150,
'qhimg_downurl': 'https://dl.image.so.com/dimgurl=https%3A%2F%2Fp0.ssl.qhimgs1.com%2Ft0108d75cea79237c90.jpg&purl=https%3A%2F%2Fimage.so.com%2F%3Fsrc%3Ddl.image&key=d825af2f3c',
'qhimg_url': 'https://p0.ssl.qhimgs1.com/t0108d75cea79237c90.jpg',
'qhimg_thumb': 'https://p0.ssl.qhimgs1.com/sdr/200_200_/t0108d75cea79237c90.jpg', 'qhimg_qr_key': 'b8887e3c5f',
'tag':'0',
'rdate': '1502943765',
'ins_time': '2017-08-17 12:22:45',
'dsptime': '',
'summary': [],
'pic_desc': ' 【美车致】未来科技 Rinspeed Etos'},
...省略
{'id': '14075fea0b788704778180d964a74433',
'index': 30, 'grpmd5': 'c326588444a6a6abfa4938e415e587ac',
'grpseq': '1',
'grpcnt': '1',
'imgkey': 't0123e59e97f75e03c4.jpg',
'width': '1600',
'height': '1200',
'title': '宝马旅行版概念车',
'imgurl': 'http://img1b.xgo-img.com.cn/pics/1521/1520902.jpg',
'purl': 'http://photo.58che.com/car/10398_1520902.html',
'site': 'photo.58che.com',
'imgsize': '0',
'label': '概念车',
'sitename': '58che.com',
'siteid': '11943280',
'src': '0',
'fnum': '0',
'qhimg_thumb_width': 200,
'qhimg_thumb_height': 150,
'qhimg_downurl': 'https://dl.image.so.com/d宝马旅行版概念车',
'imgurl': 'http://img1b.xgo-img.com.cn/pics/1521/1520902.jpg',
'purl':'http://photo.58che.com/car/10398_1520902.html',
'site': 'photo.58che.com',
'imgsize': '0',
'label': '概念车',
'sitename': '58che.com',
'siteid': '11943280',
'src': '0',
'fnum': '0',
'qhimg_thumb_width': 200,
'qhimg_thumb_height': 150,
'qhimg_downurl': 'https://dl.image.so.com/dimgurl=https%3A%2F%2Fp0.ssl.qhimgs1.com%2Ft0123e59e97f75e03c4.jpg&purl=https%3A%2F%2Fimage.so.com%2F%3Fsrc%3Ddl.image&key=d7c8a3d64d',
'qhimg_url': 'https://p0.ssl.qhimgs1.com/t0123e59e97f75e03c4.jpg',
'qhimg_thumb': 'https://p0.ssl.qhimgs1.com/sdr/200_200_/t0123e59e97f75e03c4.jpg', 'qhimg_qr_key':
'a6e2994700',
'tag': '0',
'rdate':
'1502943765',
'ins_time': '2017-08-17 12:22:45',
'dsptime': '',
'summary': [],
'pic_desc': ' 宝马旅行版概念车'}]}
>>>
如上所示,响应结果(json)中的list字段是一个图片信息列表,count字段是列表中图片信息的数量,每一项图片信息的qhimg_url字段是图片下载地址。
连续滚动鼠标滚轮加载图片,捕获更多jQuery发送的请求:
第1次加载:https://image.so.com/zjl?ch=car&listtype=new&sn=30
第2次加载:https://image.so.com/zjl?ch=car&listtype=new&sn=60
第3次加载:https://image.so.com/zjl?ch=car&listtype=new&sn=90
……
经过观察,可以总结出这些url的规律:
● ch参数 分类标签。
● sn参数 从第几张图片开始加载,即结果列表中第一张图片在服务器端的序号。
我们可以通过这个API每次获取固定数量的图片信息,从中提取每一张图片的url(下载地址),直到响应结果中的count字段为0(意味着没有更多图片了)。
到此,页面分析工作完成了。
9.3.3 编码实现
接下来,我们按以下3步完成该项目:
(1)创建Scrapy项目,并使用scrapy genspider命令创建Spider。
(2)在配置文件中启用ImagesPipeline,并指定图片下载目录。
(3)实现ImagesSpider。
步骤 01 首先创建Scrapy项目,取名为so_image,再使用scrapygenspider命令创建Spider。
$ scrapy startproject so_image
$ cd so_image
$ scrapy genspider images image.so.com
步骤 02 在配置文件settings.py中启用ImagesPipeline,并指定图片下载目录,代码如下:
ITEM_PIPELINES = {
'scrapy.pipelines.images.ImagesPipeline': 1,
}
IMAGES_STORE = 'download_images_car'
步骤 03 实现IamgesSpider,代码如下:
import scrapy
import json
from scrapy import Request
from ..items import SoImageItem
class ImagesSpider(scrapy.Spider):
BASE_URL = 'https://image.so.com/zjl?ch=car&listtype=new&sn=%s'
start_index = 0
# 限制最大下载数量,防止磁盘用量过大
MAX_DOWNLOAD_NUM = 200
name = 'images'
# allowed_domains = ['image.so.com']
start_urls = [BASE_URL % 0] # 'http://image.so.com/'
def parse(self, response):
#item = SoImageItem()
# 使用json 模块解析响应结果
infos = json.loads(response.body.decode('utf-8'))
# 提取所有图片下载url 到一个列表, 赋给item的'image_urls'字段
yield {'image_urls': [info['qhimg_url'] for info in infos['list']]}
#yield item
# 如count 字段大于0,并且下载数量不足MAX_DOWNLOAD_NUM,继续获取下图片信息
self.start_index += infos['count']
if infos['count'] > 0 and self.start_index < self.MAX_DOWNLOAD_NUM:
yield Request(self.BASE_URL % self.start_index)
# pass
编码完成后,运行爬虫:
$ scrapy crawl images
运行结束后,查看图片下载目录download_images,如图9.3.3-1所示,我们成功爬取到了210张汽车图片。
9.4 本章小结
本章我们学习了在Scrapy中下载文件和图片的方法,先简单介绍了Scrapy提供的FilesPipeline和ImagesPipeline,然后通过两个实战项目演示了FilesPipeline和ImagesPipeline的使用。
延申:
注意:
1.下载需要模块需齐全
在下载图片之前,必须保证下载所需模块pillow
pip install pillow
否则,会出现运行无错误,但无下载文件的情况。
2.调试文件
如果需要调试文件,可以在scrapy.cfg同级目录,自己建立一个main,py ,设置断点进行调试,main,py 内容如下所示:
from scrapy.cmdline import execute
import os
import sys
if __name__ == '__main__':
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
execute(['scrapy', 'crawl', 'images'])
3.改目录及名字
由于生成文件目录和文件名类似于filespipeline中对request.url 进行sha加密的方法,因此名字不太清楚,如果需要自己要修改名字还需要进行进一步的处理。
1.新建Item field ,在item.py 新建url 和title Field()
2.修改spider中的数据保存方式
3. 自己建立pipeline继承imagepipeline类,来处理item数据以及变换保存路径
其中,在保存图片名字时候传输的title 可能有重复的情况,为了区分,在保存图片时候,加入了时间和随机数的组合来保存不同图片。
4.更改setting.py 中的item_pipelines 的内容,为自己建立的pipeline子类,并设置图片保存路径。
由于不需要浏览器其他的设置就能下载之后就可以运行了
找到对应路径 ,运行以下代码,,如果都正确的话,即可得到结果:
# scrapy crawl images
打开对应文件目录可以得到下载的图片,大概一千张图片:
本文开头参照《精通Scrapy网络爬虫+(刘硕著)》PDF,并自己跑相关代码,后来根据自己的想法将代码内容稍作修改以作尝试,仅做参考和笔记复习使用