【问题标题】:Cant use python subprocess to get return value from curl call无法使用 python 子进程从 curl 调用中获取返回值
【发布时间】:2018-08-07 15:56:00
【问题描述】:

所以我试图在 python 中编写一个简单的包装器来调用 rasa,一个 nlu 工具。我在命令行上写的命令是这样的:

curl -X POST "localhost:5000/parse" -d '{"q":"我在找他妈的墨西哥菜"}' | python -m json.tool

我期望的输出是这样的:

% Total % Received % Xferd 平均速度 时间 时间 时间 当前 下载上传总花费剩余速度 100 545 0 500 100 45 33615 3025 --:--:-- --:--:-- --:--:-- 35714

加上一个json文件的输出。

我用python写了这个程序:

import subprocess

utterance = "Lets say something"


result = subprocess.run(["curl", "-X", "POST", "localhost:5000/parse", "-d", "'{\"q\":\""+utterance+"\"}'", "|", "python", "-m", "json.tool"], stdout=subprocess.PIPE)
print(vars(result))
print(result.stdout.decode('utf-8'))

不幸的是我的输出是这样的,这意味着我实际上并没有从 curl 调用中得到返回:

{'args': ['curl', '-X', 'POST', 'localhost:5000/parse', '-d', '\'{"q":"让我们说点什么"}\ '', '|', 'python', '-m', 'json.tool'], 'returncode': 2, 'stdout': b'', 'stderr': 无}

如果我从命令行调用我的 python 程序,输出如下:

curl: option -m: 期望一个合适的数值参数 curl:尝试'curl --help'或'curl --manual'以获取更多信息 {'args': ['curl', '-X', 'POST', 'localhost:5000/parse', '-d', '\'{"q":"让我们说点什么"}\'', '|', 'python', '-m', 'json.tool'], 'returncode': 2, 'stdout': b'', 'stderr': 无}

我试着到处寻找,但就是无法进行。非常感谢您的帮助。

【问题讨论】:

  • 一个想法,你有没有看过 pycurl 或 requests —— 你会写原生代码,更容易实现,更容易阅读,更容易调试。

标签: python curl subprocess rasa-nlu


【解决方案1】:

更新:我第一次严重误解了这个问题。匆忙阅读细节,所以我在那里道歉。您遇到了问题,因为您试图使用 Popen 将两个命令连接在一起。然而,管道运算符是由 shell 实现的,而不是 python。所以它期望你的命令只是一个与 curl 相关的命令。这很复杂,但你有选择。

我认为对于您的特定示例,最简单的方法是不要尝试将命令链接到 json.tool。你实际上不需要它。你已经在 python 中了,所以你可以漂亮地打印你自己从 curl 获得的输出。使用 python 看起来像

import json
import shlex
from subprocess import Popen, PIPE

command = 'curl -XGET http://localhost:9200'

p = Popen(shlex.split(command), stdin=PIPE, stdout=PIPE, stderr=PIPE)
output, err = p.communicate()

if p.returncode != 0:
    print(err)

j = json.loads(output.decode("utf-8"))
print(json.dumps(j, indent=4, sort_keys=True))

但是,如果您想要长期使用管道实际连接多个进程,那么这取决于场景。最简单的方法是将shell=True 传递给Popen 并传递确切的命令(不是参数列表)。这会将所有内容委托给 shell。我需要警告您,当命令基于用户输入时,这是非常可利用的2.x pipes.quote()3.x shlex.quote() 都有关于如何转义命令的建议,因此它应该是安全的。

from subprocess import Popen, PIPE

command = 'curl -XGET http://localhost:9200 | python -m json.tool'

p = Popen(command, stdin=PIPE, stdout=PIPE, stderr=PIPE, shell=True)
output, err = p.communicate()

if p.returncode != 0:
    print(err)

print(output.decode("utf-8"))

因此,如果您发现自己需要连接进程但有一些基于用户输入的内容,您可以使用multiple processes 并自己连接它们。

import shlex
from subprocess import Popen, PIPE

command1 = 'curl -XGET http://localhost:9200'
command2 = 'python -m json.tool'

p1 = Popen(shlex.split(command1), stdout=PIPE)
p2 = Popen(shlex.split(command2), stdin=p1.stdout, stdout=PIPE)
p1.stdout.close()
output, err = p2.communicate()

if p2.returncode != 0:
    print(err)

print(output.decode("utf-8"))

This question 有更多关于这个主题的信息。

【讨论】:

  • 我尝试使用 Popen,不幸的是,您使用我的命令的确切代码产生了这个:b"curl: option -m: expected a proper numeric parameter\ncurl: try 'curl --help' or 'curl - -manual' 了解更多信息\n" b''
  • 我稍后会尝试,但您可以删除| python -m json.tool 部分。你已经在 python 中了,所以如果需要的话,你可以在你的代码中漂亮地打印出来。
  • @JulianKurz 更新了答案。我完全没有仔细阅读你的问题。 SteveJ 所说的 pycurl 看起来也很有趣,因为它是在不调用外部进程的情况下执行 curl 的更好替代方案。
  • 非常感谢,只是为了学习一些东西,我尝试了你的两个选项,它们都工作得很好。所以我当然实现了第一个。虽然我可能会尝试使用第二种选择造成伤害,因为用户输入是基于语音的,我觉得看看它是否仍然可能很有趣。
  • @JulianKurz 我又做了一个更新。 2.x 和 3.x 都建议转义我在使用 shell=True 时添加的命令。我没有立即让它工作,所以我稍后会尝试并更新示例,但也许值得一试。将文本到语音转换为代码可能很困难,但仍有可能。如果这有助于接受答案将非常有帮助。
猜你喜欢
  • 1970-01-01
  • 2012-02-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多