给定wget命令的Python等价实现
我想写一个Python函数,功能和这个wget命令一样:
wget -c --read-timeout=5 --tries=0 "$URL"
-c
- 如果下载中断了,可以从中断的地方继续下载。
--read-timeout=5
- 如果超过5秒没有新数据进来,就放弃这次尝试,然后再试一次。结合-c
的功能,这意味着它会从中断的地方继续尝试下载。
--tries=0
- 一直重试,直到成功。
这三个参数一起使用,可以实现一个不会失败的下载。
我想在我的Python脚本中复制这些功能,但我不知道从哪里开始……
10 个回答
在编程中,有时候我们需要让程序做一些事情,比如在特定的条件下执行某段代码。这就像给程序下达命令,让它根据我们设定的规则来行动。
当我们提到“条件”时,实际上是在说“如果发生了某件事,就执行某个操作”。比如,如果你在一个网站上输入了正确的密码,那么系统就会让你进入你的账户;如果密码错误,系统就会拒绝你。
在编程里,我们通常使用“条件语句”来实现这种逻辑。条件语句就像是一个分岔路口,程序会根据条件的真假来选择不同的路径。
总之,理解条件和条件语句是编程的基础,它们帮助我们控制程序的行为,让程序能够根据不同的情况做出不同的反应。
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)
我发现一个更简单、更可靠的解决办法,就是直接在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系统的命令行。
我在一个没有正确选项的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()
还有一个很不错的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'
urllib.request 应该可以用。你只需要在一个循环里设置好(直到下载完成),检查一下本地文件是否已经存在。如果存在,就发送一个带有 RANGE 头的 GET 请求,告诉服务器你已经下载到哪儿了。记得使用 read() 方法来不断地把数据追加到本地文件中,直到出现错误为止。
这可能也是 Python urllib2 断点续传在网络重新连接时不工作 的重复问题。