综述
本系列文档用于对Python爬虫技术的学习进行简单的教程讲解,巩固自己技术知识的同时,万一一不小心又正好对你有用那就更好了。
Python 版本是3.7.4
本篇文章主要pipeline模块下载文件和图片的使用。
下载文件和图片
Scrapy为下载item中包含的文件(比如再爬取到产品时,同时也想保存到对应图片)提供了一个可重用的item pipeline
。这些pipeline
有些共同的方法和结构(我们称之为media Pipeline
),一般来说我们会使用到File Pipeline
和Images Pipeline
。
使用Scrapy框架内置方法的好处
我们为什么要选择用Scrapy
内置的下载文件的防范:
- 避免重复下载最近已经下载过的数据。
- 可以方便的指定文件存储的路径。
- 可以将下载的图片转存成通用的格式,比如png或jpg
- 可以方便的生成缩略图。
- 可以方便的检测图片的宽和高,确保他们满足最小限制。
- 异步下载,效率非常高。
下载文件的File Pipeline
当使用File Pipeline
下载文件的时候,按照以下步骤来完成:
- 定义好一个
Item
,然后再这个Item
中定义两个属性,分别为file_urls
以及files
。file_urls
是用来存储需要下载的文件的url链接,需要给一个列表。 - 当文件下载完成后,会把文件下载相关的信息存储到
item
的files
属性中。比如下载路径、下载的url和文件的校验码等。 - 在配置文件
setting.py
中配置FILES_STORE
,这个配置时用来设置文件下载下来的路径。 - 启动
pipeline
:在ITEM_PIPELINES
中设置scrapy.pipelines.files.FilesPipeline:1
。
下载图片的Images Pipeline
当使用Images Pipeline
下载文件的时候,按照以下步骤来完成:
- 定义好一个
Item
,然后再这个Item
中定义两个属性,分别为image_urls
以及images
。image_urls
是用来存储需要下载的图片的url链接,需要给一个列表。 - 当文件下载完成后,会把图片下载相关的信息存储到
item
的images
属性中。比如下载路径、下载的url和图片的校验码等。 - 在配置文件
setting.py
中配置IMAGES_STORE
,这个配置时用来设置文件下载下来的路径。 - 启动
pipeline
:在ITEM_PIPELINES
中设置scrapy.pipelines.images.ImagesPipeline:1
。
实例说明
我们就以爬取汽车之家中的图片为例。
传统下载方式
传统的下载方式在这里就简单说下步骤:
- 使用scrapy命令创建项目;
- 使用命令创建爬虫;
- 更改
setting.py
文件配置信息; - 编写
items.py
代码; - 编写
spider
模块下代码(爬取网页中需要下载的图片链接); - 编写
pipelines.py
代码(进行数据处理,图片的保存等)。
pipelines.py
代码如下:
import os
import urllib.request
class BmwPipeline(object):
def __init__(self):
# 创建文件保存文件夹
self.image_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'images')
if not os.path.exists(self.image_path):
os.mkdir(self.image_path)
def process_item(self, item, spider):
category = item['category']
img_urls = item['img_urls']
# 创建图片类别文件夹
category_path = os.path.join(self.image_path, category)
if not os.path.exists(category_path):
os.mkdir(category_path)
# 根据图片url进行下载保存图片
for url in img_urls:
img_name = url.split('_')[-1]
urllib.request.urlretrieve(url=url, filename=os.path.join(category_path, img_name))
print(img_name)
return item
通过上述代码我们就可以将爬取的图片url进行处理保存图片到本地。但是这种处理方式一个很大的缺点就是图片只能一个一个下载不能进行异步下载。下面我们使用Scrapy
框架中自带的图片下载进行下载图片。
使用Scrapy
框架自带ImagesPipeline
进行下载图片
按照上述的步骤进行编写相应的代码:
- 定义好一个
Item
,然后再这个Item
中定义两个属性,分别为image_urls
以及images
。编写items.py
代码如下:import scrapy class BmwItem(scrapy.Item): category = scrapy.Field() image_urls = scrapy.Field() images = scrapy.Field()
- 在配置文件
setting.py
中配置IMAGES_STORE
。增加代码如下:# 图片下载路径,供image pipeline使用 IMAGES_STORE = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'images')
- 启动
pipeline
:在ITEM_PIPELINES
中设置scrapy.pipelines.images.ImagesPipeline:1
。修改代码如下:ITEM_PIPELINES = { # 'bmw.pipelines.BmwPipeline': 300, 'scrapy.pipelines.images.ImagesPipeline': 1 }
- 编写
spider
模块代码如下:import scrapy from bmw.items import BmwItem class Bmw5Spider(scrapy.Spider): name = 'bmw5' allowed_domains = ['car.autohome.com.cn'] start_urls = ['https://car.autohome.com.cn/pic/series/65.html'] def parse(self, response): uiboxs = response.xpath('//div[@class="uibox"]')[1:] for uibox in uiboxs: category = uibox.xpath('.//div[@class="uibox-title"]/a/text()').get() img_urls_tmp = uibox.xpath('.//ul/li/a/img/@src').getall() img_urls = list(map(lambda url:response.urljoin(url),img_urls_tmp)) item = BmwItem(category=category,image_urls=img_urls) yield item
运行代码你会发现其能很快的将图片下载完成。下载完成后你会在你定义的图片保存文件夹images
下多了一个full
文件夹,这个里面就是所下载下来的所有图片。有的想问如果我还想要根据分类继续保存图片需要怎么办呢?这就需要我们去重写ImagesPipeline
类中的一些方法了。通过读ImagesPipeline
类的代码我们可以知道,类中有两个方法分别是get_media_requests
和file_path
。
get_media_requests
: 这个方法是在发送下载请求之前调用,其实这个方法本身就是去发送下载请求的。file_path
: 这个方式是在图片将要被存储时候调用,来获取这个图片的存储路径。
优化方案如下:
- 在
pipelines.py
中重写声明定义一个类,继承ImagesPipeline
; - 在此子类中重新这两个方法代码如下:
import os import urllib.request from scrapy.pipelines.images import ImagesPipeline from bmw import settings class BmwImagesPipeline(ImagesPipeline): # 重写get_media_requests方法 def get_media_requests(self, item, info): # 这个方法是在发送下载请求之前调用 # 其实这个方法本身就是去发送下载请求的 request_objs = super(BmwImagesPipeline, self).get_media_requests(item, info) # 将item数据加入到请求中 for requests_obj in request_objs: requests_obj.item = item return request_objs # 重写file_path方法 def file_path(self, request, response=None, info=None): # 这个方式是在图片将要被存储时候调用,来获取这个图片的存储路径 # 获取父类返回的保存地址 path = super(BmwImagesPipeline, self).file_path(request, response, info) category = request.item.get('category') images_store = settings.IMAGES_STORE # 创建图片分类文件夹 category_path = os.path.join(images_store, category) if not os.path.exists(category_path): os.mkdir(category_path) # 重新返回新的图片保存路径 image_name = path.replace('full/', '') image_path = os.path.join(category_path, image_name) return image_path
- 重新修改
setting.py
中的ITEM_PIPELINES
配置如下:ITEM_PIPELINES = { # 'bmw.pipelines.BmwPipeline': 300, # 'scrapy.pipelines.images.ImagesPipeline': 1 'bmw.pipelines.BmwImagesPipeline': 300, }
之后运行代码即可。
其他博文链接
- Python爬虫1.1 — urllib基础用法教程
- Python爬虫1.2 — urllib高级用法教程
- Python爬虫1.3 — requests基础用法教程
- Python爬虫1.4 — requests高级用法教程
- Python爬虫2.1 — BeautifulSoup用法教程
- Python爬虫2.2 — xpath用法教程
- Python爬虫3.1 — json用法教程
- Python爬虫3.2 — csv用法教程
- Python爬虫3.3 — txt用法教程
- Python爬虫4.1 — threading(多线程)用法教程
- Python爬虫4.2 — ajax(动态网页数据抓取)用法教程
- Python爬虫4.3 — selenium基础用法教程
- Python爬虫4.4 — selenium高级用法教程
- Python爬虫4.5 — tesseract(图片验证码识别)用法教程
- Python爬虫5.1 — scrapy框架简单入门
- Python爬虫5.2 — scrapy框架pipeline模块的使用
- Python爬虫5.3 — scrapy框架spider[Request和Response]模块的使用
- Python爬虫5.4 — scrapy框架items模块的使用
- Python爬虫5.5 — scrapy框架logging模块的使用
- Python爬虫5.6 — scrapy框架setting模块的使用
- Python爬虫5.7 — scrapy框架Shell命令的使用
- Python爬虫5.8 — scrapy框架CrawlSpider模块的使用
转载:https://blog.csdn.net/Zhihua_W/article/details/105200916