python批量下载图片用多线程_简单使用python多进程并发下载大量图片

news/2024/12/30 1:02:03/

如果有大量图片想要下载,肯定希望速度越快越好,那么就要使用多任务。

python支持多线程和多进程。但是解释器中的GIL锁导致任何Python线程执行前,必须先获得GIL锁,然后,每执行100条字节码,解释器就自动释放GIL锁,让别的线程有机会执行。所以多线程并不能达到理想的效果。

使用多进程的话,mutilprocessing是个很好用的库。如果是一个进程一个进程的创建,使用其中的Process类;如果是大量的,要使用其中的Pool类。如果涉及到进程间的通讯,还要使用其中Queue类、Pipes类。

综合考虑,选用Pool。

首先要获取所有图片的url(这一步也可以使用多进程),然后创建Pool,其中的子进程从前往后读取url,然后将图片信息保存到本地。

其中主要的两个函数如下所示,在save_pictures(urls)里面创建容量为40的Pool对象(默认情况下是和系统的CPU核数相同,可用通过multiprocessing.cput_count()来得知此数值),然后不停创建子进程,进行下载任务。p.close()表示不能再增加子进程,p.join()表示要等到所有子进程任务都完成后才会继续往下执行。

在save_pic(pic_url,filename)函数中进行单进程的下载图片操作。使用url lib.urlretrieve(url,filename,reporthook,data)函数来下载,这个函数是一块一块下载的,比较方便。report hook回调函数可以用来计算下载进度,此处没有使用。具体实现方法可以看源码。

在主函数中,通过以下形式来计算耗时。

d1 = datetime.datetime.now()

save_pictures(result)

d2 = datetime.datetime.now()

这是简单的一个多进程和单进程的对比结果。实际中是开了40个进程,下载了5000+张图片,共5.56G。

#单任务,urlopen:0:15:26.152427 38 pictures 38.1MB 42.12kb/s

#8进程,urlretrieve:0:09:47.217917 38 pictures 38.1MB 66.46kb/s

#40进程,urlretrieve:1:43:06.125514 5.56G 943.38kb/s

其实可以从Mac的活动监视器中看到实时的网络下载速度,半夜三更时40个进程可以达到4M/s。所以说对于处理这种重复大量的任务,一定要选用多任务。

然而代码不是一下子就写成这样的,即使这个场景一点都不复杂。

首先第一次跑的时候,跑了一个晚上都没下载完,我查看了下文件的修改时间,发现都是第二天早上,猜测某个部分循环错误,导致文件不停地重新下载写入。后来的确发现是某个地方多了个循环,导致每个图片能多下载一百多次。

后来发现刚开始下载很快,然后就慢得不可思议。同时还有个现象就是在下载之前创建目录,只能创建一部分就停止了,也就是说下载循环停止了。后来我把创建目录分离,防止受到下载图片任务的影响。慢的原因,我怀疑是之前Pool对象创建有问题,导致大量子进程被创建,然后又因为通讯超时、进程太多导致调度困难等等。这个问题后来改了代码后就不再出现,也就没有深挖。

再跑的时候跑完了,但是有的图片下载完全,有的就下载了部分,剩下的都是黑块,并且这种现象不是零星出现,而是大规模出现。还有的图片根本打不开,只有1k或者2k。

这种现象我怀疑是超时导致的,因为urlretrieve并没有超时设置参数,所以通过socket.setdefaulttimeout(30)来强制设置。同时使用异常处理来处理超时时的循环操作,采用的结构如下。

(

while:

try:

...

except ...:

...

else:

...

)

然而这种现象并没有消除,后来我尝试使用terminal来复现这些照片的下载流程时发现,还会抛出其他的一些错误,主要的原因是我要下载的这个服务器不太稳定,一不小心就访问失败了(我怀疑是由于我的大量进程访问导致的)。所以看我的save_pic函数中是有2个except的,一个单独处理socket.timeout异常,另一个用来处理其他异常。

其实这种现象没经验的话是很难判断的,因为我设置的是30s超时,那么按照理想情况,所有正在下载的图片在文件系统的修改时间应该都在30s之内,只有下载好了的才会超过这个时间。然而实际情况那些只下载了部分的图片的修改时间也是好几分钟之前了。查看打印消息,也发现这些图片只有try部分的没有else部分的也没有except socket.timeout部分。

那为什么打印消息中没有抛出的异常信息,程序没有崩溃?我觉得由于是子进程出错,所以并不会对主进程造成影响导致。

所以说,异常处理一定要对每种场景都包括,要有对默认出错的处理方法,特别是多进程时,无声无息被kill,让人摸不着头脑。

另外还犯了一个错,就是在except中把urllib.urlretrieve也写到下面,这样导致在except中出异常时,不再能够处理异常。后续把urlretrieve只放到try中,其他的except只进行打印和计数,然后让循环来帮我重新下载。

修改完毕后基本跑通,各种异常信息都能够打印出来并处理,整体无比和谐,除了个别图片依然是1k或2k的大小,查了下网页代码,发现是bug,也就不作理会了。

总结:多任务很好用,异常处理要用心。


http://www.ppmy.cn/news/561988.html

相关文章

python 使用 requests 库爬取百度图片脚本

# coding utf-8"""爬取百度壁纸图片 """/* 优秀开源电商系统学习地址:http://github.crmeb.net/u/fei */import requests,re,time,warnings,os warnings.filterwarnings("ignore")def search(key_word):# 百度获取风景壁纸…

python图片识别是否p过_Python+Opencv进行识别相似图片

标签:在网上看到python做图像识别的相关文章后,真心感觉python的功能实在太强大,因此将这些文章总结一下,建立一下自己的知识体系。 当然了,图像识别这个话题作为计算机科学的一个分支,不可能就在本文简单几句就说清,所以本文只作基本算法的科普向。 看到一篇博客是介绍…

php 比对两张图片,Python+Opencv识别两张相似图片

在网上看到python做图像识别的相关文章后,真心感觉python的功能实在太强大,因此将这些文章总结一下,建立一下自己的知识体系。 当然了,图像识别这个话题作为计算机科学的一个分支,不可能就在本文简单几句就说清&#x…

python 缩放图片_Python实现图片尺寸缩放脚本

分享一个图片按比例缩小的代码 在一篇文章中,事先并不知道是否存在图片。如果存在,且图片的宽度超过 TEST function resizeimage(){ var imgs=document.images; var rate,_height; if (imgs){ for(var i=0;i400){ rate=imgs[i].width/400.0; _height=imgs[i].height imgs[i].…

synchronized、指令重排序、有序性

问题1,为什么synchronized未禁止指令重排序,却可以保证有序性? 因为加锁之后,同一时间只有一个线程执行,相当于单线程。指令重排序的特点是可以保证串行语义一致,虽然不保证多线程间的语义也一致 。简单来说…

php合成图片系统,php图片合成

// 新建一个新的 GD 图像流并输出图像 //header("Content-type: image/png"); function combine_image($image1, $image2, $opt 100) { $wimage_data GetImageSize($image1); $width_im1 $wimage_data[0]; $height_im1 $wimage_data[1]; switch ($wimage_data[2]…

php 图片处理库 Imagick 代替 gd

一般用php处理图片都是使用GD库或者GD2的函数库,一般编译php环境都会搭上GD库,大多数开源程序也是用GD来处理图片的,但是它只能现实诸如调整大小、增加水印等基础功能,要想用GD来做复杂图形是非常困难的。 还好有个基于命令行的图…

英特尔固态硬盘测试软件,SSD固态硬盘检测测试软件(Intel SSD Toolbox)

Intel SSD Toolbox是一个功能非常不错的SSD固态硬盘检测测试软件,除了一般的检测项目外,它还拥有三项特色的检测项目。 Intel SSD Toolbox特色功能: “05:Re-allocated Sector Count”:重映射扇区数量。闪存本身有一定…