12-案例:并发下载器
目标¶
- 能够使用协程实现网络图片下载
1. 并发下载多张图片¶
2. 实现效果¶
3. 核心方法¶
urllib.request.urlopen()
—— 打开网址并返回对应的内容(二进制流)
# 导入urllib模块
import urllib.request
import gevent
def download_img(img_url, filename):
try:
# 打开url
response = urllib.request.urlopen(img_url)
# 创建文件
with open(filename, "wb") as img_file:
# 通过循环不断读取数据
while True:
# 将读取到的数据保存到变量中
img_data = response.read(1024)
# 如果读取成功,则写数据到文件中
if img_data:
# 写数据
img_file.write(img_data)
else:
break
except Exception as e:
print("文件 %s 下载失败! %s" % (file_name,str(e)))
else:
print("图片 %s 下载完成!" % filename)
def main():
# 定义变量保存要下载的图片地 址
img_url1 = "http://img.mp.itc.cn/upload/20170716/8e1b835f198242caa85034f6391bc27f.jpg"
img_url2 = "http://img.mp.sohu.com/upload/20170529/d988a3d940ce40fa98ebb7fd9d822fe2.png"
img_url3 = "http://image.uczzd.cn/11867042470350090334.gif?id=0&from=export"
# 开启协程 调用下载方法
gevent.joinall([
gevent.spawn(download_img, img_url1, "1.gif"),
gevent.spawn(download_img, img_url2, "2.gif"),
gevent.spawn(download_img, img_url3, "3.gif")
])
# 主入口
if __name__ == '__main__':
main()
运行结果
图片 1.gif 下载完成!
图片 2.gif 下载完成!
图片 3.gif 下载完成!
Process finished with exit code 0
4. 打补丁,识别耗时操作¶
# 导入模块
from gevent import monkey
# 调用patch_all() 方法
monkey.patch_all()
注意,尽可能把 from gevent import monkey
放到第一行
运行结果:
/home/teacher/PycharmProjects/day08/04-多线程下载图片.py:9: MonkeyPatchWarning: Monkey-patching ssl after ssl has already been imported may lead to errors, including RecursionError on Python 3.6. Please monkey-patch earlier. See https://github.com/gevent/gevent/issues/1016
monkey.patch_all()
图片 2.gif 下载完成!
图片 3.gif 下载完成!
图片 1.gif 下载完成!
Process finished with exit code 0
我们可以看到,下载的顺序不再是1、2、3了,可能变成无序了,主要原因就是开启协程后多个协程同时工作!注意,此处可能会报报一个警告,不影响程序运行
警告的问题见:https://github.com/gevent/gevent/issues/1016
5. 并发下载视频¶
from gevent import monkey
import gevent
import urllib.request
#有IO才做时需要这一句
monkey.patch_all()
def my_downLoad(file_name, url):
print('GET: %s' % url)
resp = urllib.request.urlopen(url)
data = resp.read()
with open(file_name, "wb") as f:
f.write(data)
print('%d bytes received from %s.' % (len(data), url))
gevent.joinall([
gevent.spawn(my_downLoad, "1.mp4", 'http://oo52bgdsl.bkt.clouddn.com/05day-08-%E3%80%90%E7%90%86%E8%A7%A3%E3%80%91%E5%87%BD%E6%95%B0%E4%BD%BF%E7%94%A8%E6%80%BB%E7%BB%93%EF%BC%88%E4%B8%80%EF%BC%89.mp4'),
gevent.spawn(my_downLoad, "2.mp4", 'http://oo52bgdsl.bkt.clouddn.com/05day-03-%E3%80%90%E6%8E%8C%E6%8F%A1%E3%80%91%E6%97%A0%E5%8F%82%E6%95%B0%E6%97%A0%E8%BF%94%E5%9B%9E%E5%80%BC%E5%87%BD%E6%95%B0%E7%9A%84%E5%AE%9A%E4%B9%89%E3%80%81%E8%B0%83%E7%94%A8%28%E4%B8%8B%29.mp4'),
])
上面的url可以换为自己需要下载视频、音乐、图片等网址