[英]Should I switch from "urllib.request.urlretrieve(..)" to "urllib.request.urlopen(..)"?
在Python 3.7 中,我使用urllib.request.urlretrieve(..)
函數從URL
下載一個大文件。 在文檔( https://docs.python.org/3/library/urllib.request.html )中,我在urllib.request.urlretrieve(..)
文檔上方閱讀了以下內容:
傳統界面
以下函數和類是從 Python 2 模塊 urllib(與 urllib2 相對)移植的。 它們可能會在未來的某個時候被棄用。
為了保持我的代碼面向未來,我正在尋找替代方案。 官方 Python 文檔沒有提到具體的文檔,但看起來urllib.request.urlopen(..)
是最直接的候選者。 它位於文檔頁面的頂部。
不幸的是,替代方案 - 像urlopen(..)
-不提供reporthook
參數。 此參數是您傳遞給urlretrieve(..)
函數的可調用urlretrieve(..)
。 反過來, urlretrieve(..)
使用以下參數定期調用它:
我用它來更新進度條。 這就是為什么我錯過了替代方案中的reporthook
論點。
我發現urlretrieve(..)
只是使用urlopen(..)
。 參見Python 3.7安裝中的request.py
代碼文件(Python37/Lib/urllib/request.py):
_url_tempfiles = []
def urlretrieve(url, filename=None, reporthook=None, data=None):
"""
Retrieve a URL into a temporary location on disk.
Requires a URL argument. If a filename is passed, it is used as
the temporary file location. The reporthook argument should be
a callable that accepts a block number, a read size, and the
total file size of the URL target. The data argument should be
valid URL encoded data.
If a filename is passed and the URL points to a local resource,
the result is a copy from local file to new file.
Returns a tuple containing the path to the newly created
data file as well as the resulting HTTPMessage object.
"""
url_type, path = splittype(url)
with contextlib.closing(urlopen(url, data)) as fp:
headers = fp.info()
# Just return the local path and the "headers" for file://
# URLs. No sense in performing a copy unless requested.
if url_type == "file" and not filename:
return os.path.normpath(path), headers
# Handle temporary file setup.
if filename:
tfp = open(filename, 'wb')
else:
tfp = tempfile.NamedTemporaryFile(delete=False)
filename = tfp.name
_url_tempfiles.append(filename)
with tfp:
result = filename, headers
bs = 1024*8
size = -1
read = 0
blocknum = 0
if "content-length" in headers:
size = int(headers["Content-Length"])
if reporthook:
reporthook(blocknum, bs, size)
while True:
block = fp.read(bs)
if not block:
break
read += len(block)
tfp.write(block)
blocknum += 1
if reporthook:
reporthook(blocknum, bs, size)
if size >= 0 and read < size:
raise ContentTooShortError(
"retrieval incomplete: got only %i out of %i bytes"
% (read, size), result)
return result
從這一切中,我看到了三個可能的決定:
我保持我的代碼不變。 讓我們希望urlretrieve(..)
函數不會很快被棄用。
我給自己寫了一個替換函數,在外部表現得像urlretrieve(..)
,在內部使用urlopen(..)
。 實際上,這樣的函數就是上面代碼的復制粘貼。 這樣做感覺不干凈 - 與使用官方urlretrieve(..)
。
我給自己寫了一個替換函數,在外部表現得像urlretrieve(..)
,而在內部使用完全不同的東西。 但是,嘿,我為什么要這樣做? urlopen(..)
沒有被棄用,為什么不使用它呢?
你會做出什么決定?
以下示例使用urllib.request.urlopen
從糧農組織統計數據庫下載包含大洋洲作物生產數據的 zip 文件。 在那個例子中,有必要定義一個最小的標題,否則 FAOSTAT 會拋出一個Error 403: Forbidden
。
import shutil
import urllib.request
import tempfile
# Create a request object with URL and headers
url = “http://fenixservices.fao.org/faostat/static/bulkdownloads/Production_Crops_Livestock_E_Oceania.zip”
header = {'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) '}
req = urllib.request.Request(url=url, headers=header)
# Define the destination file
dest_file = tempfile.gettempdir() + '/' + 'crop.zip'
print(f“File located at:{dest_file}”)
# Create an http response object
with urllib.request.urlopen(req) as response:
# Create a file object
with open(dest_file, "wb") as f:
# Copy the binary content of the response to the file
shutil.copyfileobj(response, f)
基於https://stackoverflow.com/a/48691447/2641825的請求部分和https://stackoverflow.com/a/66591873/2641825頁眉部分,也看到urllib的文檔在HTTPS://docs.python .org/3/howto/urllib2.html
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.