使用scrapy下载图片
本案例要抓取的图片地址是汽车之家,使用scrapy下载图片主要思路是,在Spider中把图片的url地址交给pipelines来处理(前面也介绍了使用pipelines来处理Spider传递过来的数据)
一、创建一个基本爬虫
- 1、创建项目及创建一只爬虫
2、在
items.py中定义汽车的itemclass CarItem(scrapy.Item): category = scrapy.Field() # 存储每次请求的url地址 urls = scrapy.Field()3、
Spider爬虫的书写import scrapy from urllib import parse from jobbloe.items import CarItem class CarSpider(scrapy.Spider): name = 'car' allowed_domains = ['car.autohome.com.cn'] start_urls = ['https://car.autohome.com.cn/pic/series/65.html#pvareaid=3454438'] def parse(self, response): uibox_list = response.xpath('//div[@class="uibox"]')[1:] for uibox in uibox_list: category = uibox.xpath('./div[@class="uibox-title"]/a/text()').extract_first() urls = uibox.xpath('.//img/@src').getall() # 这里也可以使用传统的for遍历后把数据存储到一个列表中 urls = list(map(lambda url: parse.urljoin(response.url, url), urls)) # 遍历一次发送一次数据到pipelines中 yield CarItem(category=category, urls=urls)
二、不继承scrapy类自带文件的类中书写下载图片的方式有
1、方式一:直接使用
urllib库中的request请求图片的url地址import os from urllib import request class CarPipeline(object): """ 下载图片的pipeline """ def __init__(self): # 生成最外面的文件夹 self.path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'images') if not os.path.exists(self.path): os.makedirs(self.path) def process_item(self, item, spider): if spider.name == 'car': category = item['category'] urls = item['urls'] # 生成分类的文件夹 category_path = os.path.join(self.path, category) if not os.path.exists(category_path): os.makedirs(category_path) # 遍历全部的url地址写入 for url in urls: imgage_name = url.split('_')[-1] request.urlretrieve(url, os.path.join(category_path, imgage_name)) return item2、方式二:借用
requests库请求Spider过来的url地址,请求,手动写入到本地import os import requests class CarPipeline(object): """ 手动下载图片 """ def __init__(self): # 生成最外面的文件夹 self.path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'images') if not os.path.exists(self.path): os.makedirs(self.path) def process_item(self, item, spider): if spider.name == 'car': category = item['category'] urls = item['urls'] # 生成分类的文件夹 category_path = os.path.join(self.path, category) if not os.path.exists(category_path): os.makedirs(category_path) # 遍历全部的url地址写入 for url in urls: imgage_name = url.split('_')[-1] response = requests.get(url) with open(os.path.join(category_path, imgage_name), 'wb') as f: f.write(response.content) return item
三、继承scrapy中自带文件写入、图片写入的类来实现图片的认识
1、下载文件的
File pipeline:当使用
File pipeline下载文件的时候,需要根据下面步骤来完成- 定义好一个
Item,然后再这个Item中定义两个属性,分别为file_urls以及files。file_urls是用来存储需要下载的文件的url链接,需要给一个列表; - 当文件下载完成后,会把文件下载的相关信息存储到
Item的files属性中。比如下载路径、下载的url和文件的校验码等; - 在配置文件
settings.py中配置FILES_STORE,这个配置是用来设置文件下载来的路径(存储到本地的目录文件); 在
settings.py中的ITEM_PIPELINES中注册pipelinescrapy.pipelines.files.FilesPipeline: 1
- 定义好一个
2、下载图片的
Images pipeline:当使用
Images pipeline下载文件的时候,需要根据下面步骤来完成- 定义好
Item,然后再这个Item中定义两个属性,分别为image_urls以及images,image_urls是用来存储需要下载的图片的url连接,需要给一个列表; - 当文件下载完成后,会把文件下载的相关信息存储到
item的images属性中,比如下载路径、下载的url和图片相关的校验码等; - 在配置文件
settings.py中配置IMAGES_STORE,这个配置是用来设置文件下载来的路径(存储到本地的目录文件); 在
settings.py中的ITEM_PIPELINES中注册pipelinescrapy.pipelines.images.ImagesPipeline: 1
- 定义好
四、使用自带的pipeline下载改写上面的代码
1、定义
items.py文件class CarItem(scrapy.Item): category = scrapy.Field() # 下面两个字段必须要有,别的字段就看业务需要 image_urls = scrapy.Field() images = scrapy.Field()2、修改
spider爬虫文件import scrapy from urllib import parse from jobbloe.items import CarItem class CarSpider(scrapy.Spider): name = 'car' allowed_domains = ['car.autohome.com.cn'] start_urls = ['https://car.autohome.com.cn/pic/series/65.html#pvareaid=3454438'] def parse(self, response): uibox_list = response.xpath('//div[@class="uibox"]')[1:] for uibox in uibox_list: category = uibox.xpath('./div[@class="uibox-title"]/a/text()').extract_first() urls = uibox.xpath('.//img/@src').getall() urls = list(map(lambda url: parse.urljoin(response.url, url), urls)) # image_urls必须是一个列表 yield CarItem(category=category, image_urls=urls)3、在
settings.py配置下载路径# 配置图片下载路径 import os IMAGES_STORE = os.path.join(os.path.dirname(__file__), 'cat_images')4、激活
pipelineITEM_PIPELINES = { 'scrapy.pipelines.images.ImagesPipeline': 1, }5、可能会缺少
PIL模块,需要安装pillow图片包pip3 install pillow
五、如果有特殊的要求就要重写pipeline(类似重命名或者分目录)
1、导包
from scrapy import Request from scrapy.exceptions import DropItem from scrapy.pipelines.images import ImagesPipeline2、书写
pipeline代码class CarImagePipeline(ImagesPipeline): """ 定义一个下载图片的pipeline """ def file_path(self, request, response=None, info=None): """ 用来存储图片的路径 :param request: :param response: :param info: :return: """ url = request.url file_name = url.split('/')[-1] return file_name def item_completed(self, results, item, info): image_paths = [x['path'] for ok, x in results if ok] if not image_paths: raise DropItem('Image Downloaded Failed') return item def get_media_requests(self, item, info): """ 这个函数是先获取item中过来的image_urls重新发送请求 :param item: :param info: :return: """ for url in item['image_urls']: yield Request(url)3、激活
pipeline- 4、更多可以参考