一、spider类(基础类)下载图片
不需要allowed_domains限制,就可以删去
用不用管道都可以,管道的open和close不影响
二、ImagesPipeline类(媒体管道类,还能下载音频视频等)下载图片
图片、音频、视频等都是二进制数据
把获取媒体数据的代码封装到媒体管道类中
导入from scrapy.pipelines.images import ImagesPipeline
然后class Bdimgpipeline(ImagesPipeline):用一个类来继承媒体管道类
pass
settings中打开管道(管道的名字要和创建的一样)来使用,然后设置媒体管道类特有的路径设置,
IMAGES_STORE = ‘/path/to/valid/dir’(复制的路径往往是反斜杠的,所以要换(不换的可以在前面写一个r防止转义),否则转义,路径最后要写多一个‘/文件名’来创建文件名装图片)
编写items.py文件:(注意:使用媒体管道类的话,这个字段名必须是image_urls,因为源码中默认的字段名就是这个)
class BDpipeline(object):
num=0
def process_item(self, item, spider):
if isinstance(item,BdItem):
if not os.path.exists("dir_pipe"):
os.mkdir("dir_pipe")
filename="dir_pipe/%s.jpg"%str(self.num)
self.num += 1
with open(filename,"wb")as f:
f.write(item["img_data"])
return item
这个代码全部都可以通过导入媒体管道类来继承,无需输入以下这些代码操作
from scrapy.pipelines.images import ImagesPipeline用媒体管道类,两行代码就行
class Bdimgpipeline(ImagesPipeline):
pass
更方便的是,可以不用写管道:(在settings设置)
ITEM_PIPELINES = {
这是原始的方式使用媒体管道类,不用继承
'scrapy.pipelines.images.ImagesPipeline': 300, # 注意:一定要开启此pipeline管道!
}
# 注意:一定要指定媒体管道存储的路径!
IMAGES_STORE = r'C:/my/pycharm_work/爬虫/baiduimgs/baiduimgs/dir0'
需要爬取多页图片,就在爬虫文件里构造多页format代码就行,和原来的一样不变其他的
存储管道>>开启管道>>新建管道
媒体管道特性:
媒体管道都实现了以下特性:
避免重新下载最近下载的媒体
指定存储位置(文件系统目录,Amazon S3 bucket,谷歌云存储bucket)
图像管道具有一些额外的图像处理功能:
将所有下载的图片转换为通用格式(JPG)和模式(RGB)
生成缩略图
检查图像的宽度/高度,进行最小尺寸过滤
媒体管道的设置:(在settings设置加入)、
ITEM_PIPELINES = {‘scrapy.pipelines.images.ImagesPipeline’: 1} (在settings的管道开启设置加入,1是优先级数) 启用
FILES_STORE = ‘/path/to/valid/dir’ 文件管道存放位置(继承文件类)
IMAGES_STORE = ‘/path/to/valid/dir’ 图片管道存放位置
FILES_URLS_FIELD = ‘field_name_for_your_files_urls’ 自定义文件url字段
FILES_RESULT_FIELD = ‘field_name_for_your_processed_files’ 自定义结果字段
IMAGES_URLS_FIELD = ‘field_name_for_your_images_urls’ 自定义图片url字段
IMAGES_RESULT_FIELD = ‘field_name_for_your_processed_images’ 结果字段
FILES_EXPIRES = 90 文件过期时间 默认90天
IMAGES_EXPIRES = 90 图片过期时间 默认90天
IMAGES_THUMBS = {‘small’: (50, 50), ‘big’:(270, 270)} 缩略图尺寸(除了执行原始图,还分别生成出两种图,一种是缩略图,一种为放大图)
IMAGES_MIN_HEIGHT = 110 过滤最小高度
IMAGES_MIN_WIDTH = 110 过滤最小宽度
MEDIA_ALLOW_REDIRECTS = True 是否重定向
三、ImagesPipeline类源码简介
生成媒体请求和获取文件名的源码方法可以进行重写或改写
def get_media_requests(self, item, info):
urls = ItemAdapter(item).get(self.images_urls_field, [])
列表表达式 return [Request(u) for u in urls]
重写后:(使其能在爬虫文件中允许)
def get_media_requests(self, item, info):
for x in item【“image_urls”】:
yield scrapy.request(x)
得到的请求结果传给下面的 results
def item_completed(self, results(接收返回值的参数), item, info):
其中 for u in ItemAdapter(item).get(self.images_urls_field, [])
相当于 for x in item【“image_urls”】:
def item_completed(self, results, item, info):
with suppress(KeyError):
ItemAdapter(item)[self.images_result_field] = [x for ok, x in results if ok]
return item
重写后:
def item_completed(self, results, item, info):
for ok, x in results:
if ok:(如果results中有true则判断为ok)
要得到路径就可以设 image_path =[x['path']for ok, x in results if ok]
接着可以将得到的结果改写路径:
for image_path in image_paths:
os.rename(IMAGES_STORE(settings传入的路径)+“/”+image_pat(原路径),IMAGES_STORE+“/”+str(self.image_num)(新路径)+“.jpg”)
四、ImagesPipeline类方法重写
API:
在媒体管道中,我们可以重写的方法:
get_media_requests(item, info) 根据item中的file_urls/image_urls生成请求
def get_media_requests(self, item, info):
for file_url in item[‘file_urls’]:
yield scrapy.Request(file_url)
item_completed(requests, item, info) 当item里的 所有媒体文件请求完成调用
from scrapy.exceptions import DropItem
def item_completed(self, results, item, info):
file_paths = [x[‘path’] for ok, x in results if ok]
if not file_paths:
raise DropItem(“Item contains no files”)
item[‘file_paths’] = file_paths
return item
自定义图片管道案例:
它的工作流是这样的:
1.在爬虫中,您可以返回一个item,并将所需的url放入file_urls字段。
2.item从爬虫返回并进入item管道。
3.当item到达文件管道时,file_urls字段中的url将使用标准的Scrapy调度器和下载程序(这意味着将重用调度器和下载程序中间件)计划下载, 但是具有更高的优先级,在其他页面被爬取之前处理它们。在文件下载完成(或由于某种原因失败)之前,该项在特定管道阶段保持“锁定”状态。
4.下载文件后,将使用另一个字段(files)填充results。这个字段将包含一个包含有关下载文件信息的dicts列表,例如下载的路径、原始的剪贴url(从file_urls字段中获得)和文件校验和。文件字段列表中的文件将保持原来file_urls字段的顺序。如果某些文件下载失败,将记录一个错误,文件将不会出现在files字段中。
yield:执行第一次迭代时(其实就是调用next()方法),如果有左节点并且距离满足要求,会执行第一个yield,这时会返回self._leftchild并完成第一个迭代。
执行第二次迭代时,从第一个yield后面开始,如果有右节点并且距离满足要求,会执行第二个yield,这时会返回self._rightchild并完成第一个迭代。
执行第三次迭代时,第二个yield后再无代码,捕获异常,退出迭代