在第 11 章,你编写了一个程序,从XKCD 网站下载所有的 XKCD 漫画。这是
一个单线程程序:它一次下载一幅漫画。程序运行的大部分时间,都用于建立网络连接来开始下载,以及将下载的图像写入硬盘。如果你有宽带因特网连接,单线程程序并没有充分利用可用的带宽。

多线程程序中有一些线程在下载漫画,同时另一些线程在建立连接,或将漫画图像文件写入硬盘。它更有效地使用 Internet 连接,更迅速地下载这些漫画。打开一个新的文件编辑器窗口,并保存为 
multidownloadXkcd.py。你将修改这个程序,添加多线程。经过全面修改的源代码可从 http://nostarch.com/automatestuff/下载。

第 1 步:修改程序以使用函数
该程序大部分是来自第 11 章的相同下载代码,所以我会跳过 Requests 和 BeautifulSoup  代码的解释。需要完成的主要变更是导入 threading  模块,并定义 
downloadXkcd()函数,该函数接受开始和结束的漫画编号作为参数。
例如,调用 downloadXkcd(140,280)将循环执行下载代码,下载漫画 http://xkcd. 
com/140、http://xkcd.com/141、http://xkcd.com/142 等,直到 
http://xkcd.com/279。你创建的每个线程都会调用downloadXkcd(),并传入不同范围的漫画进行下载。
将下面的代码添加到 multidownloadXkcd.py 程序中:

#!  python3
#  multidownloadXkcd.py  -  Downloads  XKCD  comics  using  multiple  threads.

import  requests,  os,  bs4,  threading
➊  os.makedirs('xkcd',  exist_ok=True)        #  store  comics  in  ./xkcd

➋  def  downloadXkcd(startComic,  endComic):
➌            for  urlNumber  in  range(startComic,  endComic): #  Download  the  page.
print('Downloading  page  http://xkcd.com/%s...'  %  (urlNumber))
➍                     res  =  requests.get('http://xkcd.com/%s'  %  (urlNumber)) 
res.raise_for_status()
➎                     soup  =  bs4.BeautifulSoup(res.text) #  Find  the  URL  of  the  
comic  image.
➏                     comicElem  =  soup.select('#comic  img')
if  comicElem  ==  []:
print('Could  not  find  comic  image.') else:
➐                               comicUrl  =  comicElem[0].get('src') #  Download  the  
image.
print('Downloading  image  %s...'  %  (comicUrl))
➑                               res  =  requests.get(comicUrl) res.raise_for_status()

#  Save  the  image  to  ./xkcd.
imageFile  =  open(os.path.join('xkcd',  os.path.basename(comicUrl)),  'wb') for  chunk  in  
res.iter_content(100000):
imageFile.write(chunk) imageFile.close()

#  TODO:  Create  and  start  the  Thread  objects. #  TODO:  Wait  for  all  threads  to  end.

导入需要的模块后,➊行创建了一个目录来保存漫画,并开始定义downloadxkcd()➋。循环遍历指定范围中的所有编号➌,并下载
每个页面➍。用 Beautiful Soup 查看每一

页的 HTML➎,找到漫画图像➏。如果页面上没有的漫画图像,就打印一条消息。否则,取得图片的 
URL➐,并下载图像➑。最后,将图像保存到我们创建的目录中。

第 2 步:创建并启动线程
既然已经定义 downloadXkcd() , 我们将创建多个线程, 每个线程调用 downloadXkcd(),从 XKCD 网站下载不同范围的漫画。将下面的代码添加到 
multidownloadXkcd.py 中,放在 downloadXkcd()函数定义之后:
#!  python3
#  multidownloadXkcd.py  -  Downloads  XKCD  comics  using  multiple  threads.

--snip--

#  Create  and  start  the  Thread  objects.
downloadThreads  =  []                         #  a  list  of  all  the  Thread  objects for  i  in 
 range(0,  1400,  100):        #  loops  14  times,  creates  14  threads
downloadThread  =  threading.Thread(target=downloadXkcd,  args=(i,  i  +  99)) 
downloadThreads.append(downloadThread)
downloadThread.start()
首先,我们创建了一个空列表 downloadThreads,该列表帮助我们追踪创建的多个 Thread 对象。然后开始for 循环。在每次循环中,我们利用threading.Thread()创建一个 
Thread 对象,将它追加到列表中,并调用 start(),开始在新线程中运行 downloadXkcd()。因为 for 循环将变量 i 设置为从 0 到 1400,步长为 100,所以 i 
在第一次迭代时为 0,第二次迭代时为 100,第三次为 200,以此类推。因为我们将 args=(I,  I+99)传递给 threading.Thread(),所以在第一次迭代时,传递给 
downloadXkcd()的两个参数将是 0和 99,第二次迭代是 100 和 199,第三次是 200 和 299,以次类推。
由于调用了 Thread 对象的 start()方法,新的线程开始运行 downloadXkcd()中的代码,主线程将继续 for 循环的下一次迭代,创造下一个线程。

第 3 步:等待所有线程结束
主线程正常执行,同时我们创建的其他线程下载漫画。但是假定主线程中有一些代码,你希望所有下载线程完成后再执行。调用 Thread 对象 join()方法将阻塞,直到该线程完成。利用一个 for 
循环,遍历 downloadThreads 列表中的所有 Thread对象,主线程可以调用其他每个线程的 join()方法。将以下代码添加到程序的末尾:
#!  python3
#  multidownloadXkcd.py  -  Downloads  XKCD  comics  using  multiple  threads.

--snip--

#  Wait  for  all  threads  to  end.
for  downloadThread  in  downloadThreads: downloadThread.join()
print('Done.')

所有的join()调用返回后,'Done.'字符串才会打印,如果一个 Thread 对象已经完成,那么调用它的 
join()方法时,该方法就会立即返回。如果想扩展这个程序,添加一些代码,在所有漫画下载后运行,就可以用新的代码替换 print('Done.')。

15.7 项目:多线程 XKCD 下载程序相关推荐

  1. python 多线程 XKCD 下载程序

    在第 11 章,你编写了一个程序,从 XKCD 网站下载所有的 XKCD 漫画.这是一个单线程程序:它一次下载一幅漫画.程序运行的大部分时间,都用于建立网络连接来开始下载,以及将下载的图像写入硬盘.如 ...

  2. 基于Python实现的网络爬虫项目——多线程下载小说并保存为txt文件(包含完整代码及注释)

    基于Python实现的网络爬虫项目--多线程下载小说并保存为txt文件(包含完整代码及注释) 一.确立预期目标 二.完成项目所需工具 三.项目需要解决的问题 问题一 问题二 问题三 问题四 问题五 问 ...

  3. JAVA写的多线程下载程序,并具有断点续传功能

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! 前面写了 ...

  4. python实战小项目,多线程百度云盘下载,突破限速,超越迅雷超高速下载

    原帖:向日葵智能 计划做这样的多线程下载是因为百度云盘限速厉害,到了恶心的地步,我想试试用多线程下载百度云盘的资源是否能够实现加速. 百度云盘限速分析 1. 关于限速,我揣测有两种情况: 限制下载资源 ...

  5. python爬虫程序下载_Python爬虫之多线程下载程序类电子书

    近段时间,笔者发现一个神奇的网站:http://www.allitebooks.com/ ,该网站提供了大量免费的编程方面的电子书,是技术爱好者们的福音.其页面如下: ![](https://imag ...

  6. Android(java)学习笔记158:多线程断点下载的原理(JavaSE实现)

    1. 为什么需要多线程下载?     服务器的资源有限,同时的平均地分配给每个客户端.开启的线程越多抢占的服务的资源就越多,下载的速度就越块. 2. 下载速度的限制条件? (1)你的电脑手机宽带的带宽 ...

  7. 下载神器:axel aria2 mwget多线程快速下载取代curl和wget的多线程下载命令

    对于在 Linux 的下载工具而言,比较常用的就是 wget 或者 curl,吾也一直用 wget 的方式进行网络上的资源下载.偶然发现了 axel 这个支持多线程的下载工具,试用了几次之后,发现网络 ...

  8. iOS开发网络篇—多线程断点下载

    iOS开发网络篇-多线程断点下载 说明:本文介绍多线程断点下载.项目中使用了苹果自带的类,实现了同时开启多条线程下载一个较大的文件.因为实现过程较为复杂,所以下面贴出完整的代码. 实现思路:下载开始, ...

  9. Java多线程断点下载

    多线程下载已经提高了下载的效率,但是当一些特殊情况发生的时候,我们需要对程序进行处理,这样效率会更高.比如,断电断网等造成下载中断,那么我们下一次又要重新开始下载,这样效率底下,所以我们可以考虑使用断 ...

最新文章

  1. [十九]JavaIO之PipedReader 和 PipedWriter
  2. 编程软件python中的if用法-适合Python初学者的一些编程技巧
  3. 【并查集】并查集的基本操作总结
  4. c++ 12.一维数组冒泡排序
  5. 【深度学习】——模型评估指标MAP计算实例计算
  6. 网易架构师深入讲解Java开发!BAT等大厂必问技术面试题
  7. 一分钟系列:详解阿里云68款产品【热点问题+用户实践】
  8. 1029 最大公约数和最小公倍数问题(gcd) luogu洛谷
  9. zabbix之解决中文乱码
  10. win10电脑一开机提示拒绝访问怎么办
  11. 【转载】 MySQL之用户资源限制
  12. OpenCV Contours 使用记录
  13. 雷林鹏分享:jQuery Mobile 方向改变事件
  14. React 预览图片 视频 音频_HDMI录制盒斗鱼虎牙高清视频游戏直播器1080监控switch/ps4采集卡...
  15. 十二月各地中小企业扶持政策汇总
  16. R语言中 attach()与detach(),及with()的使用
  17. Bitwise Operators
  18. offiice2013全套软件,加破击工具,教程,真是验证过链接:https://pan.baidu.com/s/1Csv4ZXDQyK_cKfpIXwwn6Q 提取码:h7dp 复制这段内容后打
  19. H5之外部浏览器访问微信客户端网页
  20. 有道云笔记无法同步至本地电脑解决方法

热门文章

  1. CSS背景图片background如何改变大小以及样式设置
  2. 爬虫实战:英雄联盟手游能“干掉”王者荣耀?微博4.3亿网友吵翻了……
  3. redis-----07-----redigo基本命令操作(主要讲如何让go的struct、map展开成redis的参数,以及使用struct获取redis返回的key-value批量数组)
  4. DDR的VTT有源端接和无源端接(slua886a笔记)
  5. linux篇之安装MySQL及远程连接
  6. java arraylist 添加_java ArrayList添加元素全部一样
  7. openFOAM的基础类型汇总
  8. 袋鼠云走进四川,共话企业数字经济发展新思路
  9. html中支持透明图片的格式,IE6 png图片透明的解决方法教程
  10. PNG8格式图片详解