使用scrapy下载图片
本案例要抓取的图片地址是汽车之家,使用scrapy
下载图片主要思路是,在Spider
中把图片的url
地址交给pipelines
来处理(前面也介绍了使用pipelines
来处理Spider
传递过来的数据)
一、创建一个基本爬虫
- 1、创建项目及创建一只爬虫
2、在
items.py
中定义汽车的item
class 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 item
2、方式二:借用
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
中注册pipeline
scrapy.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
中注册pipeline
scrapy.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、激活
pipeline
ITEM_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 ImagesPipeline
2、书写
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、更多可以参考