查看原文
其他

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

21CTO 2021-10-22

The following article is from 21CTO学院 Author 新楚


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


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


请来看本文。


使用 Requests


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


请看如下代码:


import requests
url = 'https://www.python.org/static/img/python-logo@2x.png'
myfile = 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 wget
url = "https://www.python.org/static/img/python-logo@2x.png"
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 requests
url = '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 requests
url = 'https://www.python.org/static/img/python-logo@2x.png'
myfile = requests.get(url)
open('c:/users/21cto/downloads/PythonImage.png', 'wb').write(myfile.content)



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


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


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


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


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


import os
import requests
from time import time
from multiprocessing.pool import ThreadPool



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


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


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




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


urls = [("Event1", "https://www.python.org/events/python-events/805/"),
("Event2", "https://www.python.org/events/python-events/801/"),
("Event3", "https://www.python.org/events/python-events/790/"),
("Event4", "https://www.python.org/events/python-events/798/"),
("Event5", "https://www.python.org/events/python-events/807/"),
("Event6", "https://www.python.org/events/python-events/807/"),
("Event7", "https://www.python.org/events/python-events/757/"),
("Event8", "https://www.python.org/events/python-user-group/816/")]



结合前一节所描述的那样,我们将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 requests
from clint.textui import progress
url = 'http://do1.dr-chuck.com/pythonlearn/EN_us/pythonlearn.pdf'
r = 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 = 2391975), 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('https://www.python.org/', '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('https://www.python.org/')



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


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


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


import requests
myProxy = { 'http': 'http://127.0.0.2:3001' }
requests.get("https://www.python.org/", proxies=myProxy)



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


使用urllib3


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


pip install urllib3

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


import urllib3, shutil

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


url = 'https://www.python.org/'

接下来,使用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 = ["https://www.python.org/events/python-events/801/",
"https://www.python.org/events/python-events/790/",
"https://www.python.org/events/python-user-group/816/",
"https://www.python.org/events/python-events/757/"]
>>> 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++


: . Video Mini Program Like ,轻点两下取消赞 Wow ,轻点两下取消在看

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存