在 Python 脚本中执行 curl 命令

Posted

技术标签:

【中文标题】在 Python 脚本中执行 curl 命令【英文标题】:Execute curl command within a Python script 【发布时间】:2014-11-17 23:15:21 【问题描述】:

我正在尝试在 python 脚本中执行 curl 命令。

如果我在终端中执行,它看起来像这样:

curl -X POST -d  '"nw_src": "10.0.0.1/32", "nw_dst": "10.0.0.2/32", "nw_proto": "ICMP", "actions": "ALLOW", "priority": "10"' http://localhost:8080/firewall/rules/0000000000000001

我看到了使用 pycurl 的建议,但我不知道如何将它应用到我的身上。

我尝试使用:

subprocess.call([
    'curl',
    '-X',
    'POST',
    '-d',
    flow_x,
    'http://localhost:8080/firewall/rules/0000000000000001'
])

它有效,但有更好的方法吗?

【问题讨论】:

您不必使用cURL 将某些内容发布到服务器。 requests 可以很容易地做到这一点(urllib 也可以,需要更多的努力) 查看这里以了解更多关于在 python 中执行 shell cmds ***.com/questions/89228/… 【参考方案1】:

不要!

我知道,这是没人想要的“答案”。但如果某事值得做,值得做对,对吗?

这似乎是一个好主意,可能源于一个相当广泛的误解,即curl 等 shell 命令不是程序本身。

所以你要问的是“我如何从我的程序中运行这个其他程序,只是为了发出一个微不足道的网络请求?”。太疯狂了,一定有更好的方法吧?

Uxio's answer 确实有效。但它看起来并不像Pythonic,不是吗?仅仅为了一个小小的请求,就需要做很多工作。 Python 应该是flying!任何写作的人都可能希望他们只是call'd curl


它有效,但有更好的方法吗?

是的,更好的方法!

Requests: HTTP for Humans

事情不应该是这样的。不在 Python 中。

让我们获取这个页面:

import requests
res = requests.get('https://***.com/questions/26000336')

就是这样,真的!然后,您将获得原始的 res.textres.json() 输出、res.headers 等。

您可以查看文档(上面链接)以了解设置所有选项的详细信息,因为我认为 OP 现在已经继续前进,而您 - 现在的读者 - 可能需要不同的选项。

但是,例如,它很简单:

url     = 'http://example.tld'
payload =  'key' : 'val' 
headers = 
res = requests.post(url, data=payload, headers=headers)

您甚至可以使用漂亮的 Python 字典在带有 params= 的 GET 请求中提供查询字符串。

简单而优雅。保持冷静,继续飞行。

【讨论】:

我使用的是 python 2.4.3。不能使用请求。 ImportError: 没有名为 requests 的模块。 @Gary pip install requests 我必须做 json.dumps(payload),但不需要在 headers 上使用 json.dumps 方法。 +1。据我所知,任何可以用 cURL 完成的事情也可以通过 python 请求完成。不妨改用那个。 这非常适合我要寻找的东西。谢谢@OJFord【参考方案2】:

您可以像@roippi 所说的那样使用 urllib:

import urllib2
data = '"nw_src": "10.0.0.1/32", "nw_dst": "10.0.0.2/32", "nw_proto": "ICMP", "actions": "ALLOW", "priority": "10"'
url = 'http://localhost:8080/firewall/rules/0000000000000001'
req = urllib2.Request(url, data, 'Content-Type': 'application/json')
f = urllib2.urlopen(req)
for x in f:
    print(x)
f.close()

【讨论】:

与子进程相比,urllib2 的时间效率更高吗? 这取决于子进程,但是当语言有核心库时会产生调用命令的子进程,这绝对不是正确的方法 TypeError: POST 数据应该是字节、可迭代的字节或文件对象。它不能是 str 类型。【参考方案3】:

使用此tool(免费托管here)将您的 curl 命令转换为等效的 Python 请求代码:

例子:这个,

curl 'https://www.example.com/' -H 'Connection: keep-alive' -H 'Cache-Control: max-age=0' -H 'Origin: https://www.example.com' -H 'Accept-Encoding: gzip, deflate, br' -H 'Cookie: SESSID=ABCDEF' --data-binary 'Pathfinder' --compressed

整齐地转换为:

import requests

cookies = 
    'SESSID': 'ABCDEF',


headers = 
    'Connection': 'keep-alive',
    'Cache-Control': 'max-age=0',
    'Origin': 'https://www.example.com',
    'Accept-Encoding': 'gzip, deflate, br',


data = 'Pathfinder'

response = requests.post('https://www.example.com/', headers=headers, cookies=cookies, data=data)

【讨论】:

虽然@OJFord 启发了我们为什么不在 python 中使用 curl,但 Nitin 描述了使用“请求”实现相同功能的最简单方法。我强烈推荐这个答案。 哇太棒了!这不仅仅是“让我为你做”的解决方案。我一直在努力弄清楚为什么我的命令不起作用,即使一切似乎都是正确的。该工具向我指出,我的请求的基本 url 中包含导致问题的额外参数。对于刚开始提出此类请求的人来说,这个工具非常适合检查这些简单的疏忽。很好的答案。【参考方案4】:

如果你没有过多地调整 curl 命令,你也可以直接调用 curl 命令

import shlex
cmd = '''curl -X POST -d  '"nw_src": "10.0.0.1/32", "nw_dst": "10.0.0.2/32", "nw_proto": "ICMP", "actions": "ALLOW", "priority": "10"' http://localhost:8080/firewall/rules/0000000000000001'''
args = shlex.split(cmd)
process = subprocess.Popen(args, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = process.communicate()

【讨论】:

谢谢,我使用 subprocess.call() 实现了它 @Ollie Ford 的建议让我得到了很好的帮助:我已经在 W10 下安装了 Requests。从命令行启动 Python,然后编写我请求的 URL。从现在开始,我必须弄清楚如何在 .py 文件中设置(并查看其内容)流。欢迎提出建议!【参考方案5】:

尝试子进程

CurlUrl="curl 'https://www.example.com/' -H 'Connection: keep-alive' -H 'Cache- 
          Control: max-age=0' -H 'Origin: https://www.example.com' -H 'Accept-Encoding: 
          gzip, deflate, br' -H 'Cookie: SESSID=ABCDEF' --data-binary 'Pathfinder' -- 
          compressed"

使用getstatusoutput 存储结果

status, output = subprocess.getstatusoutput(CurlUrl)

【讨论】:

【参考方案6】:

你可以使用下面的代码sn-p

import shlex
import subprocess
import json

def call_curl(curl):
    args = shlex.split(curl)
    process = subprocess.Popen(args, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    stdout, stderr = process.communicate()
    return json.loads(stdout.decode('utf-8'))


if __name__ == '__main__':
    curl = '''curl - X
    POST - d
    '"nw_src": "10.0.0.1/32", "nw_dst": "10.0.0.2/32", "nw_proto": "ICMP", "actions": "ALLOW", "priority": "10"'
    http: // localhost: 8080 / firewall / rules / 0000000000000001 '''
    output = call_curl(curl)
    print(output)

【讨论】:

【参考方案7】:

改写这篇文章中的一个答案,而不是使用 cmd.split()。尝试使用:

import shlex

args = shlex.split(cmd)

然后将 args 提供给 subprocess.Popen。

查看此文档了解更多信息:https://docs.python.org/2/library/subprocess.html#popen-constructor

【讨论】:

以上是关于在 Python 脚本中执行 curl 命令的主要内容,如果未能解决你的问题,请参考以下文章

python如何重新执行脚本?

在 php 脚本中执行 curl 命令并从服务器获取响应并提取它

~艾比郎~学Python之Python基础

PHP 使用curl 执行远程服务器的一个shell脚本

shell脚本实现执行http的一个post或者get方法是怎么实现的吖?

在 Unix shell 脚本中以可读的 JSON 格式显示 curl 输出