【问题标题】:Use wget from python with Popen将 python 中的 wget 与 Popen 一起使用
【发布时间】:2012-07-20 13:44:35
【问题描述】:

我正在编写一个 python (2.7) 脚本来检查是否缺少某些文件并通过 wget 下载它们。一切正常,但是在下载完成并且脚本应该退出后,bash(我从中启动 python 脚本)没有正确显示。 我有光标并且可以输入内容,但没有显示标准提示。我必须调整终端窗口的大小才能正确显示提示。这可能是什么原因?

tilenames = ['File1', 'File2', ...]
web_url = http://...

for t in tilenames:
    try:
        open(t, 'r')
    except IOError:
        print 'file %s not found.' % (t)
        command = ['wget', '-P', './SRTM/', web_url + t ]
        output = Popen(command, stdout=subprocess.PIPE)

print "Done"

我认为这与调用 wget 进程的方式有关。最后一个命令 print "Done" 实际上是在 wget 将其所有输出写入 shell 之前完成的。

【问题讨论】:

  • 您应该考虑使用urllib.urlretrieve() 而不是wgetos.path.exists() 而不是打开所有文件(而不是关闭它们)。
  • 你真的应该考虑@SvenMarnach 的评论。如果您可以使用 Python 库执行相同的任务,则无需依赖系统程序(如 wget)。通过为每个文件启动一个新进程,处理输出更容易,并且不会产生系统开销。 docs.python.org/library/urllib2.html

标签: python shell popen


【解决方案1】:

只需在输出后添加.communicate(),如下所示:

tilenames = ['File1', 'File2', ...]
web_url = http://...

for t in tilenames:
    try:
        open(t, 'r')
    except IOError:
        print 'file %s not found.' % (t)
        command = ['wget', '-P', './SRTM/', web_url + t ]
        p = Popen(command, stdout=subprocess.PIPE)
        stdout, stderr = p.communicate()

print "Done"

communicate 将返回写入stdoutNone 的输出以用于stderr,因为它没有转发到PIPE(您将在终端上看到它)。

顺便说一句。您应该关闭打开的文件对象(要检查文件是否存在,您可以使用os.path 中的函数,例如os.path.exists

【讨论】:

  • 不,这将按原样工作,wget 标准错误输出将被重定向到控制台而不是管道,communicate 返回 None 而不是字符串。
  • 谢谢!它的工作原理如下:p = Popen(command, stdout=PIPE, stderr=PIPE) stdout, stderr = p.communicate()。这是什么原因?我是否必须获取 wget 的 stderr 输出并通过 .communicate 将其存储到 stderr 中?为什么?
  • communicate 只是等待进程结束的一种安全方式。您还可以使用它来将进程单次输入发送到标准输入:.communicate(input_to_stdin)
  • 是的,但是p.wait() 不会给你管道stdin/stderr 的输出,如果你直接从它们读取,这可能会导致麻烦(如死锁)。
【解决方案2】:

wget 将其统计信息写入stderr,这就是它扰乱您的终端的原因。 stdout 和 stderr 会以不同的时间间隔刷新和查询,因此您的 Done 可能会在 wget 的输出之前出现。

解决方法是使用-q 调用wget,或者也使用stderr=open("/dev/null", "w") 或类似的东西重定向stderr

此外,您可能应该使用.communicate() 来避免管道问题。

【讨论】:

    【解决方案3】:

    您可以使用 os.system(但请参阅 http://docs.python.org/release/2.5.2/lib/node536.html)。基本上 Popen 旨在允许您的 python 进程从命令输出中读取。您似乎不需要这样做,因此下面的片段应该可以满足您的需求:

    import os
    import subprocess
    
    p = subprocess.Popen(['wget','http://www.aol.com'],stdout=subprocess.PIPE)
    os.waitpid(p.pid,0)
    print "done"
    

    【讨论】:

    • 顺便说一句,没有任何特别的理由将标准输出定向到管道,因为您似乎没有使用它。
    【解决方案4】:

    如果你给 wget 添加 -q 选项,它也可以工作(相当模式)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-09-24
      • 1970-01-01
      • 2015-03-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-13
      • 2016-01-10
      相关资源
      最近更新 更多