Ich versuche, die folgende Curl-Anfrage in Pycurl umzuwandeln:

curl -v
-H Accept:application/json \
-H Content-Type:application/json \
-d "{
    name: 'abc',
    path: 'def',
    target: [ 'ghi' ]
}" \
-X POST http://some-url

Ich habe folgenden Python-Code:

import pycurl, json

c = pycurl.Curl()
c.setopt(pycurl.URL, 'http://some-url')
c.setopt(pycurl.HTTPHEADER, ['Accept: application/json'])
data = json.dumps({"name": "abc", "path": "def", "target": "ghi"})
c.setopt(pycurl.POST, 1)
c.setopt(pycurl.POSTFIELDS, data)
c.setopt(pycurl.VERBOSE, 1)
c.perform()
print curl_agent.getinfo(pycurl.RESPONSE_CODE)
c.close()

Als ich dies ausführte, hatte ich einen Fehler 415: Nicht unterstützter Medientyp, daher habe ich Folgendes geändert:

c.setopt(pycurl.HTTPHEADER, ['Accept: application/json'])

In:

c.setopt(pycurl.HTTPHEADER, [ 'Content-Type: application/json' , 'Accept: application/json'])

Diesmal habe ich 400: Schlechte Anfrage. Aber Bash-Code mit Curl funktioniert. Haben Sie eine Idee, was ich im Python-Code beheben soll?

14
Konrad 5 Aug. 2015 im 11:07

5 Antworten

Beste Antwort

In Ihrem Bash-Beispiel ist die Eigenschaft target ein Array, in Ihrem Python-Beispiel eine Zeichenfolge.

Versuche dies:

data = json.dumps({"name": "abc", "path": "def", "target": ["ghi"]})

Ich rate Ihnen außerdem dringend, die requests Bibliothek mit einer viel schönere API:

import requests
data = {"name": "abc", "path": "def", "target": ["ghi"]}
response = requests.post('http://some-url', json=data)
print response.status_code
6
Daniel Hepper 5 Aug. 2015 im 09:08

Es ist einfacher, die Anforderungsbibliothek zu verwenden. (http://docs.python-requests.org/en/latest)

Ich füge Python-Code für Ihre ursprünglichen benutzerdefinierten Curl-Header hinzu.

import json
import requests

url = 'http://some-url'
headers = {'Content-Type': "application/json; charset=xxxe", 'Accept': "application/json"}
data = {"name": "abc", "path": "def", "target":  ["ghi"]}
res = requests.post(url, json=data, headers=headers)
print (res.status_code)
print (res.raise_for_status())
-6
IJL 6 Jän. 2017 im 00:22

Ich weiß, dass dies jetzt über ein Jahr alt ist, aber bitte versuchen Sie, das Leerzeichen in Ihrem Header-Wert zu entfernen.

c.setopt(pycurl.HTTPHEADER, ['Accept:application/json'])

Ich bevorzuge auch die Verwendung des Anforderungsmoduls, da die APIs / Methoden sauber und einfach zu verwenden sind.

4
Brian 5 Jän. 2017 im 17:42

Ich hatte ein ähnliches Problem und habe Ihr Codebeispiel verwendet, aber den Abschnitt httpheader wie folgt aktualisiert:

c.setopt(pycurl.HTTPHEADER, ['Content-Type:application/json'])
1
Nick Larsen 4 Jän. 2019 im 13:39

PycURL ist ein Wrapper für die libcurl-Bibliothek, der in C-Sprache geschrieben ist, sodass die Python-API etwas rätselhaft sein kann. Da einige Leute die Verwendung von Python-Anfragen befürworten, möchte ich nur darauf hinweisen, dass dies kein perfekter Ersatz ist. Für mich war das Fehlen eines Zeitlimits für die DNS-Auflösung ein Deal Breaker. Ich finde es auch viel langsamer auf meinem Raspberry Pi. Dieser Vergleich kann relevant sein: Python-Anforderungen im Vergleich zur PyCurl-Leistung

Hier ist also etwas, das sich der Frage von OP nicht entzieht:

import pycurl
import json
from cStringIO import StringIO

curl = pycurl.Curl()
curl.setopt(pycurl.URL, 'http://some-url')
curl.setopt(pycurl.HTTPHEADER, ['Accept: application/json',
                                'Content-Type: application/json'])
curl.setopt(pycurl.POST, 1)

# If you want to set a total timeout, say, 3 seconds
curl.setopt(pycurl.TIMEOUT_MS, 3000)

## depending on whether you want to print details on stdout, uncomment either
# curl.setopt(pycurl.VERBOSE, 1) # to print entire request flow
## or
# curl.setopt(pycurl.WRITEFUNCTION, lambda x: None) # to keep stdout clean

# preparing body the way pycurl.READDATA wants it
# NOTE: you may reuse curl object setup at this point
#  if sending POST repeatedly to the url. It will reuse
#  the connection.
body_as_dict = {"name": "abc", "path": "def", "target": "ghi"}
body_as_json_string = json.dumps(body_as_dict) # dict to json
body_as_file_object = StringIO(body_as_json_string)

# prepare and send. See also: pycurl.READFUNCTION to pass function instead
curl.setopt(pycurl.READDATA, body_as_file_object) 
curl.setopt(pycurl.POSTFIELDSIZE, len(body_as_json_string))
curl.perform()

# you may want to check HTTP response code, e.g.
status_code = curl.getinfo(pycurl.RESPONSE_CODE)
if status_code != 200:
    print "Aww Snap :( Server returned HTTP status code {}".format(status_code)

# don't forget to release connection when finished
curl.close()

Weitere interessante Funktionen finden Sie in der libcurl curleasy setopts-Dokumentation

2
ayush3504 11 Dez. 2019 im 00:20