使用Python下载文件之最佳实践

在本教程中,我们将学习到使用不同的Python模块从网页上下载文件,包括常规文件,网页和其它来源。

我们会在其中遇到各种可能的挑战,比如下载重定向,大文件下载,多线程下载等。

请来看本文。

使用 Requests

从某个网址下载文件可以使用 requests 模块。

请看如下代码:

import requestsurl = https://www.python.org/static/img/[email protected] = requests.get(url)open(c:/users/21cto/downloads/PythonImage.png, wb).write(myfile.content)

只需要使用request模块的get方法获取URL,接着将结果存储到myfile变量中即可,最后将变量的内容写入到文件。

使用 wget

还可以使用 wget 模块来从URL上下载文件,它也是Python的标准模块,如果没有安装,使用pip命令开始安装:

pip install wget

如下代码,我们将下载Python的logo和相关图片:

import wgeturl = ""wget.download(url, c:/users/LikeGeeks/downloads/pythonLogo.png)

在以上代码中,URL和图片的全路径会传递到wget模块的download方法,最后文件如果存在就会下载到目的路径和文件存储。

下载重定向文件

在本节中,我们将学习到从URL下载,该URL将请求会重定向到另一个URL中,比如如下URL:

https://readthedocs.org/projects/python-guide/downloads/pdf/latest/

想要下载该pdf文件,我们使用如下代码:

import requestsurl = https://readthedocs.org/projects/python-guide/downloads/pdf/latest/myfile = requests.get(url, allow_redirects=True)open(c:/users/21cto/documents/PythonBook.pdf, wb).write(myfile.content)

在以上代码中,我们第一步是指定URL,然后使用requests模块的get方法来获取URL内容。在get方法中,需要设置allow_redirects为True,也就是允许URL重定向,然后将重定向的内容分配给myfile变量。

最后,打开一个文件用来写入获取到的内容,完成下载。

下载大尺寸文件

请看如下代码:

import requestsurl = https://www.python.org/static/img/[email protected] = requests.get(url)open(c:/users/21cto/downloads/PythonImage.png, wb).write(myfile.content)

第一步,我们和前面一样使用requests模块的get方法,但是在此处,需要把stream属性设置为True。接下来,在当前工作目录中创建一个名叫PythonBook.pdf的文件,打开并开始写入。

接下来指定一次要下载的块尺寸,我们将其设置为1024字节,然后遍历每个块,接着把这些块写入文件中,直接块全部写完为止。

貌似不是很好看?不有担心,一会我们使用显示进度条的下载方式。

下载多个文件(并行/批量下载)

如果要一次下载多个文件,需要导入如下模块:

import osimport requestsfrom time import timefrom multiprocessing.pool import ThreadPool

从上面代码中,我们可以导入了os和time模块,用来检查下载文件花了多少时间。模块ThreadPool线程池用来处理多个线程和进程。

我们来创建一个函数,将返回内容分块写入到文件中:

def url_response(url):path, url = urlr = requests.get(url, stream = True)with open(path, wb) as f:for ch in r:f.write(ch)

URL将是一个二维数组,用来指定下载的网页路径或文件。

urls = [("Event1", ""),("Event2", ""),("Event3", ""),("Event4", ""),("Event5", ""),("Event6", ""),("Event7", ""),("Event8", "")]

结合前一节所描述的那样,我们将URL传递给request.get,接着打开文件(URL中指定之路径)并写入页面内容。

现在,我们就可以为每个网址下载调用此函数,也可以同时为所有网址调用此函数。接下来分别在for循环中为每个URL进行操作,请注意计时器:

start = time()for x in urls:url_response (x)print(f"Time to download: {time() - start}")

接下来,使用如下代码替换for循环:

ThreadPool(9).imap_unordered(url_response, urls)

运行该脚本即可。

下载显示状态条

Python中的进度条是clint模块的UI组件,需要安装Clint模块,命令如下:

pip install clint

接下来使用如下代码:

import requestsfrom clint.textui import progressurl = http://do1.dr-chuck.com/pythonlearn/EN_us/pythonlearn.pdfr = requests.get(url, stream=True)with open("LearnPython.pdf", "wb") as Pypdf:total_length = int(r.headers.get(content-length))for ch in progress.bar(r.iter_content(chunk_size = ), expected_size=(total_length/1024) + 1):if ch:Pypdf.write(ch)

在这段代码中,我们引入了requests组件,接下来在clint.textui中导入进度条组件,与前面的唯一区别在于for循环,在把内容写入文件时,我们使用了progress模块的bar方法。

使用urllib下载

我们也可以使用urllib来下载网页。urllib库是Python的标准库,不需要额外再安装。

可以用如下代码来下载URL资源:

urllib.request.urlretrieve(url, path)

接下来要指定要保存的路径,如下:

urllib.request.urlretrieve(, c:/users/21cto/documents/PythonOrganization.html)

在此段代码中,使用urlretrieve方法,传给了源下载文件的网址以及文件存储的路径,扩展名为.html。

通过代理服务器下载

因为相关原因,我们需要使用代理服务器下载时,则可以使用urllib模块的ProxyHandler。

来看如下代码:

import urllib.request>>> myProxy = urllib.request.ProxyHandler({http: 127.0.0.2})>>> openProxy = urllib.request.build_opener(myProxy)>>> urllib.request.urlretrieve()

在此段代码中,首先创建了代理对象,通过调用urllib的build_opener方法打开代理服务器,传递代理对象。

接着,开始发起检索页面之请求。

另外,还可以使用Python官方文档中的requests模块来运行。代码如下:

import requestsmyProxy = { http: http://127.0.0.2:3001 }requests.get("", proxies=myProxy)

只需导入requests模块,创建自己的代理对象,就可以下载文件了。

使用urllib3

urllib3是urllib模块的改进版本。需要使用pip下载并安装它:

pip install urllib3

接下来下载一个网页,使用urllib3来把它存储在文本文件中。

import urllib3, shutil

shutil是用来处理文件时使用。接下来,初始化URL字符串变量:

url = 

接下来,使用PoolManager来跟踪相关的连接池。

c = urllib3.PoolManager()

接下来,创建一个文件。

filename = "mytest.txt"

最后,使用GET方式来请求并获取URL内容,接下来打开文件,将返回的响应写入该文件中。代码如下:

with c.request(GET, url, preload_content=False) as res, open(filename, wb) as out_file:shutil.copyfileobj(res, out_file)

异步下载

asyncio模块专门用来处理系统事件,它围绕着事件循环来工作,循环等待,事件发生,然后对该事件进行反应,该反应可能是调用另一个函数。

asyncio模块使用协程进行事件处理。

接下来使用asyncio事件处理和协程功能,导入asyncio模块:

import asyncio

接下来,定义异步协程之方法:

async def coroutine():await my_func()

这里给大家说明一下,关键字asyncz表示是一个本地asyncio协程。在协程主体内部,有await关键字,此关键字返回某值,亦可以使用return关键字。

现在,我们使用协程来创建一段完整代码,从Python官方网站下载文件:

>>> import os>>> import urllib.request>>> async def coroutine(url):r = urllib.request.urlopen(url)filename = "couroutine_downloads.txt"with open(filename, wb) as f:for ch in r:f.write(ch)print_msg = 下载已经成功return print_msg>>> async def main_func(urls_to_download):co = [coroutine(url) for url in urls_to_download]downloaded, downloading = await asyncio.wait(co)for i in downloaded:print(i.result())urls_to_download = ["","", "", ""]>>> eventLoop = asyncio.get_event_loop()>>> eventLoop.run_until_complete(main_func(urls_to_download))

在上面的Python代码中,我们创建了一个异步协程函数,该函数下载文件后会返回一条消息,接下来有另一个异步协程调用,main_fun形成队列,asyncio等待功能完成后,协程结束。

如果要启动协程,需要使用asyncio的get_event_loop()方法把协程放入事件循环中,最后用run_until_complete()执行事件循环。

使用Pyton下载文件非常有趣,多磨练,会有更多有益的东西。希望本教程对大家有帮助,如果有,欢迎分享转发!

作者:新楚

来源:21CTO学院

推荐阅读:

你用代码写作业,他用Python让樱花绽放,美哭了!

让Python帮你搞定MySQL数据库

特斯拉嫌弃Python,追捧C++