python 多线程 XKCD 下载程序
在第 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 下载程序相关推荐
- 15.7 项目:多线程 XKCD 下载程序
在第 11 章,你编写了一个程序,从XKCD 网站下载所有的 XKCD 漫画.这是 一个单线程程序:它一次下载一幅漫画.程序运行的大部分时间,都用于建立网络连接来开始下载,以及将下载的图像写入硬盘.如 ...
- python多线程端口扫描程序
下面的程序给出了对给定的ip主机进行多线程扫描的python代码 #!/usr/bin/env python #encoding: utf-8import socket, sys, thread, t ...
- python分割压缩_【python 多线程】下载文件分批压缩
大体做的功能为: 1.调用api接口,获取json数据:2.json 数据转换为一个csv文件:3.csv文件里的每行数据转换成单个xml文件:4.每5个xml文件进行打包 用到的模块为: csv,x ...
- python 多线程自动刷票程序
#!/usr/bin/python # -*- coding: utf-8 -*- #coding=utf-8 import urllib2 import urllib import re impor ...
- python实战小项目,多线程百度云盘下载,突破限速,超越迅雷超高速下载
原帖:向日葵智能 计划做这样的多线程下载是因为百度云盘限速厉害,到了恶心的地步,我想试试用多线程下载百度云盘的资源是否能够实现加速. 百度云盘限速分析 1. 关于限速,我揣测有两种情况: 限制下载资源 ...
- python爬虫程序下载_Python爬虫之多线程下载程序类电子书
近段时间,笔者发现一个神奇的网站:http://www.allitebooks.com/ ,该网站提供了大量免费的编程方面的电子书,是技术爱好者们的福音.其页面如下: ![](https://imag ...
- 2021-03-10 Python多线程爬虫快速批量下载图片
Python多线程爬虫快速批量下载图片 1.完成这个需要导入的模块 urllib,random,queue(队列),threading,time,os,json 第三方模块的安装 键盘win+R,输入 ...
- Python多线程下载网络URL图片的方法
Python多线程下载网络URL图片的方法 采用多线程的方法,通过URL地址,下载资源图片 GitHub地址:https://github.com/PanJinquan/python-learning ...
- python写机器人程序_用Python写的一个多线程机器人聊天程序
本人是从事php开发的, 近来想通过php实现即时通讯(兼容windows).后来发现实现起来特别麻烦, 就想到python.听说这家伙在什么地方都能发挥作用.所以想用python来做通讯模块...所 ...
最新文章
- A potentially dangerous Request.Form value was detected from the client
- matlab里performance,关于神经网络performance图的问题
- UPS不间断电源常见故障及如何排除故障
- prototype 1.5 中文说明.doc
- Java开发专业通过swot分析岗位_掌起智能科技 | 你们要的安卓岗位来了,还有JAVA,技术经理等岗位...
- java:十进制转十六进制
- exit()与_exit()函数的区别
- “您的Microsoft Internet Explorer浏览器包含最新版本的内置Adobe Flash Player“解决
- oracle集群监听启动,在RAC中lsnrctl和srvctl操作监听区别
- 重庆中职计算机试题及答案,重庆市计算机专业高职复习题参考答案
- [Other] Inno Setup 使用心德-一个完整的项目 包括.NET组建捆绑 去空格等
- 条形码图像生成库barcodelib使用介绍
- php结合phantomjs实现网页截屏、抓取js渲染的页面
- 怎么做扁平化ps图标长投影效果
- 程序员必须了解的10大技术搜索引擎
- 专业解读:从央行征信系统看你的哪些行为会影响你的信用
- 为什么很少人用redmine_为什么古代书法家要把字写歪?
- 博士毕业答辩会上的感言——余子濠
- RabbitMQ快速入门
- 产品驱动增长模式的最佳实践
热门文章
- 【C++】C++PrimerPlus(第6版)中文版 第9章 内存模型和名称空间 编程练习 参考答案
- adm怎么下bt连接_【使用教程】序列模式——福禄克BT系列电池测试仪
- 软工实践 - 第十一次作业 Alpha 冲刺 (3/10)
- 【AR】AR 的几种底层实现方式
- 读书:《人人都是产品经理》-苏杰
- 【云原生】在 React Native 中使用 AWS Textract 实现文本提取
- 华为手机语音通话时断时续原因
- 2021年数学建模国赛B题优秀论文(Word)(04烯焼制备分析与试验设计)
- MySQL5.7修改root账户密码
- 如何处理表情字符入库问题