PycURL 附件和进度函数

Jon*_*ner 3 python curl pycurl

使用您向其发送请求的 API 处理一个小项目,然后它会返回一个带有 zip 文件的响应,然后您可以下载该文件。我第一次自动下载时尝试使用 setopt(curl.WRITEDATA, fp) 函数,但每次尝试都会使我的 Python 脚本崩溃。然后我改变了策略并使用 WRITEFUNCTION 将数据写入缓冲区,然后将其写入一个始终正常工作的文件。

这一切都很好,但后来我想添加一个进度条来查看下载了多少文件并提供一些用户反馈等。这就是事情开始变得奇怪的地方,因为现在进度条在一秒钟内达到 100%并且 zip 文件尚未完成下载。当我将进度函数更改为仅打印正在下载的文件的大小时,它会报告大约 100 字节的数量(远小于 zip 文件)。无论如何使用pycurl(和下面的curl)中的函数来跟踪附件下载的进度而不是请求本身?

此外,如果有人可以帮助解决也可能有帮助的 WRITEDATA 问题,我想这两个问题可能是相关的。

小智 5

以下代码将使用下载文件pycurl并显示当前进度(以文本形式):

import pycurl
# for displaying the output text
from sys import stderr as STREAM

# replace with your own url and path variables
url = "http://ovh.net/files/100Mb.dat"
path = 'test_file.dat'

# use kiB's
kb = 1024

# callback function for c.XFERINFOFUNCTION
def status(download_t, download_d, upload_t, upload_d):
    STREAM.write('Downloading: {}/{} kiB ({}%)\r'.format(
        str(int(download_d/kb)),
        str(int(download_t/kb)),
        str(int(download_d/download_t*100) if download_t > 0 else 0)
    ))
    STREAM.flush()

# download file using pycurl
with open(path, 'wb') as f:
    c = pycurl.Curl()
    c.setopt(c.URL, url)
    c.setopt(c.WRITEDATA, f)
    # display progress
    c.setopt(c.NOPROGRESS, False)
    c.setopt(c.XFERINFOFUNCTION, status)
    c.perform()
    c.close()

# keeps progress onscreen after download completes
print()
Run Code Online (Sandbox Code Playgroud)

输出应如下所示:

Downloading: 43563/122070 kiB (35%)
Run Code Online (Sandbox Code Playgroud)

如果您想使用实际进度条,也可以这样做。但这需要更多的工作。

以下代码使用该tqdm包生成进度条。它会在文件下载时实时更新,并显示下载速度和估计剩余时间。由于道路的限制tqdm作品中,requests也需要包装。这也与total_dl_d变量是数组而不是整数的原因有关。

import pycurl
# for displaying the output text
from sys import stderr as STREAM

# replace with your own url and path variables
url = "http://ovh.net/files/100Mb.dat"
path = 'test_file.dat'

# use kiB's
kb = 1024

# callback function for c.XFERINFOFUNCTION
def status(download_t, download_d, upload_t, upload_d):
    STREAM.write('Downloading: {}/{} kiB ({}%)\r'.format(
        str(int(download_d/kb)),
        str(int(download_t/kb)),
        str(int(download_d/download_t*100) if download_t > 0 else 0)
    ))
    STREAM.flush()

# download file using pycurl
with open(path, 'wb') as f:
    c = pycurl.Curl()
    c.setopt(c.URL, url)
    c.setopt(c.WRITEDATA, f)
    # display progress
    c.setopt(c.NOPROGRESS, False)
    c.setopt(c.XFERINFOFUNCTION, status)
    c.perform()
    c.close()

# keeps progress onscreen after download completes
print()
Run Code Online (Sandbox Code Playgroud)

对所描述问题的可能原因的解释:

(问题中没有提供代码,所以我不得不猜测一下究竟是什么导致了上述问题......)

基于变量名 ( fpie file_path) ...
文件写入 (WRITEDATA) 问题可能是由于提供了文件路径 (str) 而不是文件对象 (io.BufferedWriter)。

根据我自己的经验......
XFERINFOFUNCTION回调文件下载过程中反复调用。回调仅提供总文件大小和已下载的总数作为参数。它不计算自上次调用以来的增量(差值)。这是进度条(“进度条到达100%,在一秒钟内和zip文件尚未完成下载”)中所描述的问题可能是由于在金额(下载)被用作update量时的增量预计金额。如果进度条被在每一次的总金额,然后它不会反映下载的实际金额。它将显示更大的数量。然后,它将超过100%并出现各种故障。


资料来源: