将curl POST请求转换为仅使用标准库的Python代码

20 投票
4 回答
34345 浏览
提问于 2025-04-15 17:33

我想把这个curl命令转换成可以在Python中使用的代码,以便在我现有的脚本里用。

curl -u 7898678:X -H 'Content-Type: application/json' \
-d '{"message":{"body":"TEXT"}}' http://sample.com/36576/speak.json

这里的TEXT是我想用脚本生成的消息来替换的。(这个脚本已经能正常工作了,不过我觉得它可能没有遵循最佳实践,也不太可靠。- 我需要找到正确的学习编程的方法(也就是不要总是依赖谷歌来拼凑代码))

如果可能的话,我希望能使用标准库来实现这个功能。

4 个回答

2

谢谢大家

这个方法有效

import urllib2

def speak(status):

    def basic_authorization(user, password):
        s = user + ":" + password
        return "Basic " + s.encode("base64").rstrip()

    req = urllib2.Request("http://example.com/60/speak.json",
                  headers = {
       "Authorization": basic_authorization("2345670", "X"),
     "Content-Type": "application/json",


        "Accept": "*/*",   
        "User-Agent": "my-python-app/1", 
        },
                      data = '{"message":{"body":'+ status +'}}')

    f = urllib2.urlopen(req)


speak('Yay')
12

虽然有一些方法可以在 urllib2 中处理身份验证,但如果你使用的是基本授权(也就是直接发送用户名和密码),那么你可以通过 urllib2.Request 和 urllib2.urlopen 来完成你想做的所有事情:

import urllib2

def basic_authorization(user, password):
    s = user + ":" + password
    return "Basic " + s.encode("base64").rstrip()

req = urllib2.Request("http://localhost:8000/36576/speak.json",
                      headers = {
        "Authorization": basic_authorization("7898678", "X"),
        "Content-Type": "application/json",

        # Some extra headers for fun
        "Accept": "*/*",   # curl does this
        "User-Agent": "my-python-app/1", # otherwise it uses "Python-urllib/..."
        },
                      data = '{"message":{"body":"TEXT"}}')

f = urllib2.urlopen(req)

我用 netcat 测试过,这样我可以看到发送的数据在排序上有所不同,但内容是完全一样的。第一个是用 curl 做的,第二个是用 urllib2 做的。

% nc -l 8000
POST /36576/speak.json HTTP/1.1
Authorization: Basic Nzg5ODY3ODpY
User-Agent: curl/7.19.4 (universal-apple-darwin10.0) libcurl/7.19.4 OpenSSL/0.9.8k zlib/1.2.3
Host: localhost:8000
Accept: */*
Content-Type: application/json
Content-Length: 27

{"message":{"body":"TEXT"}} ^C

% nc -l 8000
POST /36576/speak.json HTTP/1.1
Accept-Encoding: identity
Content-Length: 27
Connection: close
Accept: */*
User-Agent: my-python-app/1
Host: localhost:8000
Content-Type: application/json
Authorization: Nzg5ODY3ODpY

{"message":{"body":"TEXT"}}^C

(这个输出稍微做了一些调整。我的测试案例没有使用你所用的相同网址路径。)

其实不需要使用底层的 httplib,因为它不支持 urllib2 提供的一些功能,比如代理支持。不过,我发现 urllib2 在处理简单请求之外会有点复杂,如果你想更好地控制发送的头信息及其顺序,建议使用 httplib。

23

我希望这个能在标准库中工作,如果可能的话。

标准库提供了 urllibhttplib 来处理网址:

>>> import httplib, urllib
>>> params = urllib.urlencode({'apple': 1, 'banana': 2, 'coconut': 'yummy'})
>>> headers = {"Content-type": "application/x-www-form-urlencoded",
...            "Accept": "text/plain"}
>>> conn = httplib.HTTPConnection("example.com:80")
>>> conn.request("POST", "/some/path/to/site", params, headers)
>>> response = conn.getresponse()
>>> print response.status, response.reason
200 OK

不过,如果你想直接执行 curl 命令,可以使用 os.system() 来实现:

import os
TEXT = ...
cmd = """curl -u 7898678:X -H 'Content-Type: application/json'""" \
  """-d '{"message":{"body":"%{t}"}}' http://sample.com/36576/speak.json""" % \
  {'t': TEXT}

如果你愿意放宽只使用标准库的限制,可以使用 PycURL。不过要注意,这个库不是很符合 Python 的风格(它其实就是在 libcurl 上加了一层薄薄的包装),而且我不确定它和 Python 3 的兼容性如何。

撰写回答