(1)、前言
Scrapy框架为文件和图片的下载专门提供了两个Item Pipeline 它们分别是:
FilePipeline
ImagesPipeline
(2)、使用Scrapy内置的下载方法的好处
1、可以有效避免重复下载
2、方便指定下载路径
3、方便格式转换,例如可以有效的将图片转换为png 或jpg
4、方便生成缩略图
5、方便调整图片大小
6、异步下载,高效率
(3)、较为传统的Scrapy框架图片下载方式
1、创建项目:scrapy startproject baoma---cd baoma --创建爬虫scrapy genspider spider car.autohome.com.cn
2、使用pycharm打开项目
改写settings.py
不遵守robots协议
设置请求头
开启pipelines.py
改写spider.py
1 # -*- coding: utf-8 -*- 2 import scrapy 3 from ..items import BaomaItem 4 5 class SpiderSpider(scrapy.Spider): 6 name = 'spider' 7 allowed_domains = ['car.autohome.com.cn'] 8 start_urls = ['https://car.autohome.com.cn/pic/series/65.html'] 9 10 def parse(self, response): 11 #SelecorList类型 12 uiboxs = response.xpath('//div[@class = "uibox"]')[1:] #第一个我们不需要 13 for uibox in uiboxs: 14 catagory = uibox.xpath('.//div[@class = "uibox-title"]/a/text()').get() 15 urls = uibox.xpath('.//ul/li/a/img/@src').getall() 16 #遍历列表,并将列表中的某一项执行函数操作,再将函数的返回值以列表的形式返回 17 #map() 18 # for url in urls: 19 # # url = 'https:' + url 20 # # print(url) 21 # #方法二: 22 # url = response.urljoin(url) 23 # print(url) 24 #方法三: 25 #将列表中的每一项进行遍历传递给lambda表达式,并执行函数中的代码,再以返回值以列表形式进行返回,结果是map对象,接着使用list转换为列表 26 urls = list(map(lambda url:response.urljoin(url),urls)) 27 item = BaomaItem(catagory = catagory,urls = urls) 28 yield item
改写pipelines.py
1 # -*- coding: utf-8 -*- 2 3 # Define your item pipelines here 4 # 5 # Don't forget to add your pipeline to the ITEM_PIPELINES setting 6 # See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html 7 import os 8 from urllib import request 9 10 class BaomaPipeline(object): 11 def __init__(self): 12 self.path = os.path.join(os.path.dirname(__file__), 'images') #os.path.dirname()获取当前文件的路径,os.path.join()获取当前目录并拼接成新目录 13 if not os.path.exists(self.path): # 判断路径是否存在 14 os.mkdir(self.path) 15 16 def process_item(self, item, spider): 17 #分类存储 18 catagory = item['catagory'] 19 urls = item['urls'] 20 21 catagory_path = os.path.join(self.path,catagory) 22 if not os.path.exists(catagory_path): #如果没有该路径即创建一个 23 os.mkdir(catagory_path) 24 25 for url in urls: 26 image_name = url.split('_')[-1] #以_进行切割并取最后一个单元 27 request.urlretrieve(url,os.path.join(catagory_path,image_name)) 28 29 30 return item
新建测试py(main.py)
1 #author: "xian" 2 #date: 2018/6/14 3 from scrapy import cmdline 4 cmdline.execute('scrapy crawl spider'.split())
运行结果:(我们成功获取了以catagory分类并以图片地址_后的参数作为图片名的图片)
Scrapy框架提供了两个中间件1、下载文件的Files pipeline 和下载图片的Image pipeline
下载文件的Files pipeline
使用步骤:
1、定义好一个item,然后定义两个属性file_urls 和 files . file_urls是用来存储需要下载的文件的url链接,列表类型
2、当文件下载完成后,会把文件下载的相关信息存储到item的files属性中。例如:下载路径,下载url 和文件的效验码
3、再配置文件settings.py中配置FILES_STORE,指定文件下载路径
4、启动pipeline,在ITEM_PIPELINES中设置scrapy.pipelines.files.FilesPipeline :1
下载图片的Images Pipeline
使用步骤:
1、定义好一个item,然后定义两个属性image_urls 和 images. image_urls是用来存储需要下载的文件的url链接,列表类型
2、当文件下载完成后,会把文件下载的相关信息存储到item的images属性中。例如:下载路径,下载url 和文件的效验码
3、再配置文件settings.py中配置FILES_STORE,指定文件下载路径
4、启动pipeline,在ITEM_PIPELINES中设置scrapy.pipelines.images.ImagesPipeline :1
(4)、使用Images_pipeline进行图片下载(还是以汽车之家图片为例)
改写settings.py
开启自己定义的中间件
改写pipelines,py
1 # -*- coding: utf-8 -*- 2 3 # Define your item pipelines here 4 # 5 # Don't forget to add your pipeline to the ITEM_PIPELINES setting 6 # See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html 7 import os 8 from urllib import request 9 from scrapy.pipelines.images import ImagesPipeline 10 import settings 11 12 class BaomaPipeline(object): 13 def __init__(self): 14 self.path = os.path.join(os.path.dirname(__file__), 'images') #os.path.dirname()获取当前文件的路径,os.path.join()获取当前目录并拼接成新目录 15 if not os.path.exists(self.path): # 判断路径是否存在 16 os.mkdir(self.path) 17 18 def process_item(self, item, spider): 19 #分类存储 20 catagory = item['catagory'] 21 urls = item['urls'] 22 23 catagory_path = os.path.join(self.path,catagory) 24 if not os.path.exists(catagory_path): #如果没有该路径即创建一个 25 os.mkdir(catagory_path) 26 27 for url in urls: 28 image_name = url.split('_')[-1] #以_进行切割并取最后一个单元 29 request.urlretrieve(url,os.path.join(catagory_path,image_name)) 30 31 32 return item 33 34 35 class BMWImagesPipeline(ImagesPipeline): # 继承ImagesPipeline 36 # 该方法在发送下载请求前调用,本身就是发送下载请求的 37 def get_media_requests(self, item, info): 38 request_objects = super(BMWImagesPipeline, self).get_media_requests(item, info) # super()直接调用父类对象 39 for request_object in request_objects: 40 request_object.item = item 41 return request_objects 42 43 def file_path(self, request, response=None, info=None): 44 path = super(BMWImagesPipeline, self).file_path(request, response, info) 45 # 该方法是在图片将要被存储时调用,用于获取图片存储的路径 46 catagory = request.item.get('catagory') 47 images_stores = settings.IMAGES_STORE #拿到IMAGES_STORE 48 catagory_path = os.path.join(images_stores,catagory) 49 if not os.path.exists(catagory_path): #判断文件名是否存在,如果不存在创建文件 50 os.mkdir(catagory_path) 51 image_name = path.replace('full/','') 52 image_path = os.path.join(catagory_path,image_name) 53 return image_path
运行结果展示:
通过对比我们可以直观感受到下载速度明显提高。
下面我们对图片进行优化,获取高清图片
通过分析缩略图和高清图的url,我们发现缩略图只是多了t_罢了
缩略图地址:https://car3.autoimg.cn/cardfs/product/g24/M08/2F/9E/t_autohomecar__wKgHIVpogfqAIlTbAAUzcUgKoGY701.jpg
高清图地址:https://car3.autoimg.cn/cardfs/product/g24/M08/2F/9E/autohomecar__wKgHIVpogfqAIlTbAAUzcUgKoGY701.jpg
(5)、下面我们获取所有的高清图片
传统思路如下:找到更多获取接口的url,进入详情页--找分页接口(显然这种情况会大大提高我们的工作量,下面我们使用Scrapy框架中的CrawlSpider进行爬取,因为CrawlSpider只要指定响应的规则,爬虫会自动进行爬取,省事省力!)
我们首先分析下url的规律:
https://car.autohome.com.cn/pic/series/65-1.html(更多的第一页url)
https://car.autohome.com.cn/pic/series/65-1-p2.html(更多的第二页url)
改写spider.py
1 # -*- coding: utf-8 -*- 2 import scrapy 3 from scrapy.spiders import CrawlSpider ,Rule#导入CrawlSpider模块 需改写原来的def parse(self,response)方法 4 from scrapy.linkextractor import LinkExtractor #导入链接提取模块 5 from ..items import BaomaItem 6 7 8 class SpiderSpider(CrawlSpider): 9 name = 'spider' 10 allowed_domains = ['car.autohome.com.cn'] 11 start_urls = ['https://car.autohome.com.cn/pic/series/65.html'] 12 13 rules = { 14 Rule(LinkExtractor(allow=r'https://car.autohome.com.cn/pic/series/65.+'),callback= 'parse_page',follow=True), 15 16 } #如需要进行页面解释则使用callback回调函数 因为有下一页,所以我们需要跟进,这里使用follow令其为True 17 18 19 def parse_page(self, response): #页面解析函数 20 catagory = response.xpath('//div[@class = "uibox"]/div/text()').get() 21 srcs = response.xpath('//div[contains(@class,"uibox-con")]/ul/li//img/@src').getall() 22 srcs = list(map(lambda x:x.replace('t_',''),srcs)) #map(函数,参数二),将参数二中的每个都进行函数计算并返回一个列表 23 # urls = {} 24 # for src in srcs: 25 # url = response.url.join(src) 26 # urls.append(url) 27 srcs = list(map(lambda x:response.urljoin(x),srcs)) 28 yield BaomaItem(catagory=catagory,image_urls = srcs)
运行结果(展示):(我们成功获取了高清图片到本地)