在第 11 章,你编写了一个程序,从 XKCD 网站下载所有的 XKCD 漫画。这是一个单线程程序:它一次下载一幅漫画。程序运行的大部分时间,都用于建立网络连接来开始下载,以及将下载的图像写入硬盘。如果你有宽带因特网连接,单线程程序并没有充分利用可用的带宽。多线程程序中有一些线程在下载漫画,同时另一些线程在建立连接,或将漫画图像文件写入硬盘。它更有效地使用 Internet 连接,更迅速地下载这些漫画。打开一个新的文件编辑器窗口,并保存为 multidownloadXkcd.py。你将修改这个程序,添加多线程。经过全面修改的源代码可从 http://nostarch.com/automatestuff/下载。

修改程序以使用函数
该程序大部分是来自第 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 ./xkcddef downloadXkcd(startComic, endComic):for urlNumber in range(startComic, encComic):# 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 ./xkcdimageFile = 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,并下载图像。最后,将图像保存到我们创建的目录中。

创建并启动线程
既 然已经 定义 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 threadsdownloadThread = 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 循环的下一次迭代,创造下一个线程。

等待所有线程结束
主线程正常执行,同时我们创建的其他线程下载漫画。但是假定主线程中有一些代码,你希望所有下载线程完成后再执行。调用 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.')。

完整代码

#! python3
# multidownloadXkcd.py - Downloads XKCD comics using multiple threads.import requests, os, bs4, threading
os.makedirs('xkcd', exist_ok=True)       # store comics in ./xkcddef downloadXkcd(startComic, endComic):for urlNumber in range(startComic, encComic):# 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 ./xkcdimageFile = open(os.path.join('xkcd', os.path.basename(comicUrl)), 'wb')for chunk in res.iter_content(100000):imageFile.write(chunk)imageFile.close()# 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 threadsdownloadThread = threading.Thread(target=downloadXkcd, args=(i, i + 99))downloadThreads.append(downloadThread)downloadThread.start()# Wait for all threads to end.
for downloadThread in downloadThreads:downloadThread.join()
print('Done.')

python 多线程 XKCD 下载程序相关推荐

  1. 15.7 项目:多线程 XKCD 下载程序

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

  2. python多线程端口扫描程序

    下面的程序给出了对给定的ip主机进行多线程扫描的python代码 #!/usr/bin/env python #encoding: utf-8import socket, sys, thread, t ...

  3. python分割压缩_【python 多线程】下载文件分批压缩

    大体做的功能为: 1.调用api接口,获取json数据:2.json 数据转换为一个csv文件:3.csv文件里的每行数据转换成单个xml文件:4.每5个xml文件进行打包 用到的模块为: csv,x ...

  4. python 多线程自动刷票程序

    #!/usr/bin/python # -*- coding: utf-8 -*- #coding=utf-8 import urllib2 import urllib import re impor ...

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

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

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

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

  7. 2021-03-10 Python多线程爬虫快速批量下载图片

    Python多线程爬虫快速批量下载图片 1.完成这个需要导入的模块 urllib,random,queue(队列),threading,time,os,json 第三方模块的安装 键盘win+R,输入 ...

  8. Python多线程下载网络URL图片的方法

    Python多线程下载网络URL图片的方法 采用多线程的方法,通过URL地址,下载资源图片 GitHub地址:https://github.com/PanJinquan/python-learning ...

  9. python写机器人程序_用Python写的一个多线程机器人聊天程序

    本人是从事php开发的, 近来想通过php实现即时通讯(兼容windows).后来发现实现起来特别麻烦, 就想到python.听说这家伙在什么地方都能发挥作用.所以想用python来做通讯模块...所 ...

最新文章

  1. A potentially dangerous Request.Form value was detected from the client
  2. matlab里performance,关于神经网络performance图的问题
  3. UPS不间断电源常见故障及如何排除故障
  4. prototype 1.5 中文说明.doc
  5. Java开发专业通过swot分析岗位_掌起智能科技 | 你们要的安卓岗位来了,还有JAVA,技术经理等岗位...
  6. java:十进制转十六进制
  7. exit()与_exit()函数的区别
  8. “您的Microsoft Internet Explorer浏览器包含最新版本的内置Adobe Flash Player“解决
  9. oracle集群监听启动,在RAC中lsnrctl和srvctl操作监听区别
  10. 重庆中职计算机试题及答案,重庆市计算机专业高职复习题参考答案
  11. [Other] Inno Setup 使用心德-一个完整的项目 包括.NET组建捆绑 去空格等
  12. 条形码图像生成库barcodelib使用介绍
  13. php结合phantomjs实现网页截屏、抓取js渲染的页面
  14. 怎么做扁平化ps图标长投影效果
  15. 程序员必须了解的10大技术搜索引擎
  16. 专业解读:从央行征信系统看你的哪些行为会影响你的信用
  17. 为什么很少人用redmine_为什么古代书法家要把字写歪?
  18. 博士毕业答辩会上的感言——余子濠
  19. RabbitMQ快速入门
  20. 产品驱动增长模式的最佳实践

热门文章

  1. 【C++】C++PrimerPlus(第6版)中文版 第9章 内存模型和名称空间 编程练习 参考答案
  2. adm怎么下bt连接_【使用教程】序列模式——福禄克BT系列电池测试仪
  3. 软工实践 - 第十一次作业 Alpha 冲刺 (3/10)
  4. 【AR】AR 的几种底层实现方式
  5. 读书:《人人都是产品经理》-苏杰
  6. 【云原生】在 React Native 中使用 AWS Textract 实现文本提取
  7. 华为手机语音通话时断时续原因
  8. 2021年数学建模国赛B题优秀论文(Word)(04烯焼制备分析与试验设计)
  9. MySQL5.7修改root账户密码
  10. 如何处理表情字符入库问题