给定wget命令的Python等价实现

122 投票
10 回答
352993 浏览
提问于 2025-04-18 10:38

我想写一个Python函数,功能和这个wget命令一样:

wget -c --read-timeout=5 --tries=0 "$URL"

-c - 如果下载中断了,可以从中断的地方继续下载。

--read-timeout=5 - 如果超过5秒没有新数据进来,就放弃这次尝试,然后再试一次。结合-c的功能,这意味着它会从中断的地方继续尝试下载。

--tries=0 - 一直重试,直到成功。

这三个参数一起使用,可以实现一个不会失败的下载。

我想在我的Python脚本中复制这些功能,但我不知道从哪里开始……

10 个回答

20

在编程中,有时候我们需要让程序做一些事情,比如在特定的条件下执行某段代码。这就像给程序下达命令,让它根据我们设定的规则来行动。

当我们提到“条件”时,实际上是在说“如果发生了某件事,就执行某个操作”。比如,如果你在一个网站上输入了正确的密码,那么系统就会让你进入你的账户;如果密码错误,系统就会拒绝你。

在编程里,我们通常使用“条件语句”来实现这种逻辑。条件语句就像是一个分岔路口,程序会根据条件的真假来选择不同的路径。

总之,理解条件和条件语句是编程的基础,它们帮助我们控制程序的行为,让程序能够根据不同的情况做出不同的反应。

import urllib2
import time

max_attempts = 80
attempts = 0
sleeptime = 10 #in seconds, no reason to continuously try if network is down

#while true: #Possibly Dangerous
while attempts < max_attempts:
    time.sleep(sleeptime)
    try:
        response = urllib2.urlopen("http://example.com", timeout = 5)
        content = response.read()
        f = open( "local/index.html", 'w' )
        f.write( content )
        f.close()
        break
    except urllib2.URLError as e:
        attempts += 1
        print type(e)
28

我发现一个更简单、更可靠的解决办法,就是直接在Python中执行终端命令。在你的情况下:

import os
import shlex
url = 'https://www.someurl.com'
os.system(f"wget -c --read-timeout=5 --tries=0 {shlex.quote(url)}")

不过,记得要注意输入的安全性,避免被恶意代码利用。shlex.quote 这个方法只适合Unix系统的命令行。

32

我在一个没有正确选项的Linux版本上需要做类似的事情,那个版本的wget不支持我想要的功能。这个例子是用来下载内存分析工具'guppy'的。我不太确定这是否重要,但我把目标文件的名字保持和网址的名字一样...

这是我想出来的:

python -c "import requests; r = requests.get('https://pypi.python.org/packages/source/g/guppy/guppy-0.1.10.tar.gz') ; open('guppy-0.1.10.tar.gz' , 'wb').write(r.content)"

这是一个简单的一行代码,下面是更易读的版本:

import requests
fname = 'guppy-0.1.10.tar.gz'
url = 'https://pypi.python.org/packages/source/g/guppy/' + fname
r = requests.get(url)
open(fname , 'wb').write(r.content)

这个方法可以用来下载一个压缩包。我下载后能够解压这个包。

编辑:

为了回答一个问题,这里有一个带进度条的实现,进度条会显示在标准输出上。可能有更通用的方法可以做到这一点,而不需要clint这个包,但这个在我的机器上测试过,效果很好:

#!/usr/bin/env python

from clint.textui import progress
import requests

fname = 'guppy-0.1.10.tar.gz'
url = 'https://pypi.python.org/packages/source/g/guppy/' + fname

r = requests.get(url, stream=True)
with open(fname, 'wb') as f:
    total_length = int(r.headers.get('content-length'))
    for chunk in progress.bar(r.iter_content(chunk_size=1024), expected_size=(total_length/1024) + 1): 
        if chunk:
            f.write(chunk)
            f.flush()
158

还有一个很不错的Python模块叫做 wget,使用起来非常简单。不过要注意,这个模块自2015年就没有更新过,缺少一些重要的功能,所以在某些情况下,可能更适合使用其他方法。具体要看你要做什么。如果只是简单下载,这个模块就足够了。如果需要做更多的事情,还有其他的解决方案可以选择。

>>> import wget
>>> url = 'http://www.futurecrew.com/skaven/song_files/mp3/razorback.mp3'
>>> filename = wget.download(url)
100% [................................................] 3841532 / 3841532>
>> filename
'razorback.mp3'

希望你喜欢。

不过,如果 wget 不能正常工作(我在处理某些PDF文件时遇到过问题),可以试试 这个解决方案

补充:你还可以使用 out 参数来指定一个自定义的输出目录,而不是使用当前的工作目录。

>>> output_directory = <directory_name>
>>> filename = wget.download(url, out=output_directory)
>>> filename
'razorback.mp3'
44

urllib.request 应该可以用。你只需要在一个循环里设置好(直到下载完成),检查一下本地文件是否已经存在。如果存在,就发送一个带有 RANGE 头的 GET 请求,告诉服务器你已经下载到哪儿了。记得使用 read() 方法来不断地把数据追加到本地文件中,直到出现错误为止。

这可能也是 Python urllib2 断点续传在网络重新连接时不工作 的重复问题。

撰写回答