Comment envoyer une requête POST en JSON?

105
data = {
        'ids': [12, 3, 4, 5, 6 , ...]
    }
    urllib2.urlopen("http://abc.com/api/posts/create",urllib.urlencode(data))

Je souhaite envoyer une demande POST, mais l'un des champs doit être une liste de nombres. Comment puis je faire ça ? (JSON?)

TIMEX
la source
1
N'est-ce pas déjà une liste de chiffres?
Waynn Lue
Cela ne peut pas être répondu sans savoir quel type d'entrée attend l'API.
Niklas B.
1
@WaynnLue, le serveur d'API obtient cela sous forme de chaîne, pas de liste.
TIMEX
1
Dois-je définir les en-têtes comme "application / json" ou quelque chose comme ça?
TIMEX

Réponses:

154

Si votre serveur s'attend à ce que la requête POST soit json, vous devrez alors ajouter un en-tête et sérialiser les données de votre requête ...

Python 2.x

import json
import urllib2

data = {
        'ids': [12, 3, 4, 5, 6]
}

req = urllib2.Request('http://example.com/api/posts/create')
req.add_header('Content-Type', 'application/json')

response = urllib2.urlopen(req, json.dumps(data))

Python 3.x

https://stackoverflow.com/a/26876308/496445


Si vous ne spécifiez pas l'en-tête, ce sera le application/x-www-form-urlencodedtype par défaut .

jdi
la source
J'ai une question. est-il possible d'ajouter plusieurs éléments dans l'en-tête ... comme le type de contenu et l'ID client ... @jdi
Omar Jandali
@OmarJandali, il suffit d'appeler à add_header()nouveau, pour chaque en-tête que vous souhaitez ajouter.
jdi
J'ai le code suivant mais il n'imprime rien. il était censé imprimer l'url et les en-têtes mais rien n'a été imprimé ... req = urllib.Request('http://uat-api.synapsefi.com') req.add_header('X-SP-GATEWAY', 'client_id_asdfeavea561va9685e1gre5ara|client_secret_4651av5sa1edgvawegv1a6we1v5a6s51gv') req.add_header('X-SP-USER-IP', '127.0.0.1') req.add_header('X-SP-USER', '| ge85a41v8e16v1a618gea164g65') req.add_header('Content-Type', 'application/json') print(req)...
Omar Jandali
urllib2 n'a pas été reconnu donc j'ai juste utilisé urllib. J'obtiens également une erreur avec la demande. The view tab.views.profileSetup didn't return an HttpResponse object. It returned None instead. @jdi
Omar Jandali
@OmarJandali, gardez à l'esprit que cette réponse a été donnée à l'origine en 2012, sous python 2.x. Vous utilisez Python3 donc les importations seront différentes. Ce serait maintenant import urllib.requestet urllib.request.Request(). De plus, l'impression de l'objet req n'a rien d'intéressant. Vous pouvez clairement voir que les en-têtes ont été ajoutés en imprimant req.headers. Au-delà de cela, je ne sais pas pourquoi cela ne fonctionne pas dans votre application.
jdi
113

Je recommande d'utiliser l'incroyable requests module .

http://docs.python-requests.org/en/v0.10.7/user/quickstart/#custom-headers

url = 'https://api.github.com/some/endpoint'
payload = {'some': 'data'}
headers = {'content-type': 'application/json'}

response = requests.post(url, data=json.dumps(payload), headers=headers)
FogleBird
la source
Cela me donneTypeError: post() takes from 1 to 2 positional arguments but 3 were given
zakdances
66

pour python 3.4.2 j'ai trouvé que ce qui suit fonctionnera:

import urllib.request
import json      

body = {'ids': [12, 14, 50]}  
myurl = "http://www.testmycode.com"

req = urllib.request.Request(myurl)
req.add_header('Content-Type', 'application/json; charset=utf-8')
jsondata = json.dumps(body)
jsondataasbytes = jsondata.encode('utf-8')   # needs to be bytes
req.add_header('Content-Length', len(jsondataasbytes))
response = urllib.request.urlopen(req, jsondataasbytes)
Mike Gold
la source
1
Python3.6.2 cela a fonctionné. Seul l'ajout d'en-tête avec req.add_header (...) a fonctionné pour moi.
Shalin LK
18

Cela fonctionne parfaitement pour Python 3.5 , si l'URL contient une valeur de chaîne de requête / paramètre,

URL de la requête = https://bah2.com/ws/rest/v1/concept/
Valeur du paramètre = 21f6bb43-98a1-419d-8f0c-8133669e40ca

import requests

url = 'https://bahbah2.com/ws/rest/v1/concept/21f6bb43-98a1-419d-8f0c-8133669e40ca'
data = {"name": "Value"}
r = requests.post(url, auth=('username', 'password'), verify=False, json=data)
print(r.status_code)
MAX
la source
7
dans votre snipper de code, la variable d'en-têtes reste inutilisée
shookees
4

Vous devez ajouter un en-tête, ou vous obtiendrez une erreur http 400. Le code fonctionne bien sur python2.6, centos5.4

code:

    import urllib2,json

    url = 'http://www.google.com/someservice'
    postdata = {'key':'value'}

    req = urllib2.Request(url)
    req.add_header('Content-Type','application/json')
    data = json.dumps(postdata)

    response = urllib2.urlopen(req,data)
YuanYe
la source
2

Voici un exemple d'utilisation de l'objet urllib.request de la bibliothèque standard Python.

import urllib.request
import json
from pprint import pprint

url = "https://app.close.com/hackwithus/3d63efa04a08a9e0/"

values = {
    "first_name": "Vlad",
    "last_name": "Bezden",
    "urls": [
        "https://twitter.com/VladBezden",
        "https://github.com/vlad-bezden",
    ],
}


headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
}

data = json.dumps(values).encode("utf-8")
pprint(data)

try:
    req = urllib.request.Request(url, data, headers)
    with urllib.request.urlopen(req) as f:
        res = f.read()
    pprint(res.decode())
except Exception as e:
    pprint(e)
Vlad Bezden
la source
1

Dans le dernier package de requêtes, vous pouvez utiliser le jsonparamètre dans la requests.post()méthode pour envoyer un dict json, et l' Content-Typeen-tête in sera défini sur application/json. Il n'est pas nécessaire de spécifier explicitement l'en-tête.

import requests

payload = {'key': 'value'}

requests.post(url, json=payload)
jdhao
la source
Notez que cela entraînera un JSON POSTÉ avec des guillemets simples, ce qui est techniquement invalide.
Jethro
@Jethro Avez-vous observé des erreurs lors de l'utilisation de guillemets simples? Il est valide d'utiliser des guillemets simples en Python. Personnellement, je n'ai rencontré aucun problème à ce sujet.
jdhao
Aah excuses Je me suis trompé, je pensais que mon serveur recevait du JSON à guillemets simples mais cela s'est avéré être un problème séparé et un débogage trompeur. Merci, c'est beaucoup plus ordonné que d'avoir à spécifier l'en-tête manuellement!
Jethro
0

Celui-ci fonctionne bien pour moi avec apis

import requests

data={'Id':id ,'name': name}
r = requests.post( url = 'https://apiurllink', data = data)
Sudhir G
la source