Faire une demande à une API RESTful à l'aide de python

221

J'ai une API RESTful que j'ai exposée en utilisant une implémentation d'Elasticsearch sur une instance EC2 pour indexer un corpus de contenu. Je peux interroger la recherche en exécutant ce qui suit à partir de mon terminal (MacOSX):

curl -XGET 'http://ES_search_demo.com/document/record/_search?pretty=true' -d '{
  "query": {
    "bool": {
      "must": [
        {
          "text": {
            "record.document": "SOME_JOURNAL"
          }
        },
        {
          "text": {
            "record.articleTitle": "farmers"
          }
        }
      ],
      "must_not": [],
      "should": []
    }
  },
  "from": 0,
  "size": 50,
  "sort": [],
  "facets": {}
}'

Comment puis-je transformer ci-dessus en une demande d'API en utilisant python/requestsou python/urllib2( je ne sais pas laquelle choisir - j'ai utilisé urllib2, mais j'entends que les demandes sont meilleures ...)? Dois-je passer comme en-tête ou autrement?

user7289
la source

Réponses:

340

Utilisation des demandes :

import requests
url = 'http://ES_search_demo.com/document/record/_search?pretty=true'
data = '''{
  "query": {
    "bool": {
      "must": [
        {
          "text": {
            "record.document": "SOME_JOURNAL"
          }
        },
        {
          "text": {
            "record.articleTitle": "farmers"
          }
        }
      ],
      "must_not": [],
      "should": []
    }
  },
  "from": 0,
  "size": 50,
  "sort": [],
  "facets": {}
}'''
response = requests.post(url, data=data)

En fonction du type de réponse renvoyé par votre API, vous voudrez alors probablement regarder response.textou response.json()(ou éventuellement inspecter d' response.status_codeabord). Voir les documents de démarrage rapide ici , en particulier cette section .

andersschuller
la source
3
je pense que cela devrait être: response = requests.post (url, data = data)
CK.Nguyen
8
"requests.get" ne prend pas le paramètre "data". Il peut prendre un paramètre "params" facultatif qui est généralement un dict contenant une chaîne de requête. Si une charge utile est nécessaire pour récupérer des données (comme l'exemple publié en question), alors "request.post" doit être utilisé. De plus, l'utilisation de la bibliothèque "json" facilite l'analyse de la réponse json.
HVS du
4
@ParveenShukhala "Les demandes prennent officiellement en charge Python 2.6–2.7 & 3.3–3.5 et fonctionnent parfaitement sur PyPy." - pypi.python.org/pypi/requests
danio
2
Comme c'est du JSON que vous envoyez, vous pouvez utiliser le paramètre json plutôt que des données comme ceci: response = requests.post (url, json = data)
Mark Chorley
101

L'utilisation des requêtes et de json simplifie les choses.

  1. Appelez l'API
  2. En supposant que l'API renvoie un JSON, analysez l'objet JSON dans un dict Python en utilisant la json.loadsfonction
  3. Parcourez le dict pour extraire des informations.

Le module Requests vous offre une fonction utile pour boucler pour le succès et l'échec.

if(Response.ok): vous aidera à déterminer si votre appel API a réussi (code de réponse - 200)

Response.raise_for_status() vous aidera à récupérer le code http renvoyé par l'API.

Vous trouverez ci-dessous un exemple de code pour effectuer de tels appels API. Peut également être trouvé dans github . Le code suppose que l'API utilise l'authentification Digest. Vous pouvez ignorer cela ou utiliser d'autres modules d'authentification appropriés pour authentifier le client appelant l'API.

#Python 2.7.6
#RestfulClient.py

import requests
from requests.auth import HTTPDigestAuth
import json

# Replace with the correct URL
url = "http://api_url"

# It is a good practice not to hardcode the credentials. So ask the user to enter credentials at runtime
myResponse = requests.get(url,auth=HTTPDigestAuth(raw_input("username: "), raw_input("Password: ")), verify=True)
#print (myResponse.status_code)

# For successful API call, response code will be 200 (OK)
if(myResponse.ok):

    # Loading the response data into a dict variable
    # json.loads takes in only binary or string variables so using content to fetch binary content
    # Loads (Load String) takes a Json file and converts into python data structure (dict or list, depending on JSON)
    jData = json.loads(myResponse.content)

    print("The response contains {0} properties".format(len(jData)))
    print("\n")
    for key in jData:
        print key + " : " + jData[key]
else:
  # If response code is not ok (200), print the resulting http error code with description
    myResponse.raise_for_status()
HVS
la source
2
La dernière partie avec itération sur les clés ne fonctionnera pas toujours car le document JSON peut avoir un tableau comme élément de niveau supérieur. Donc, ce serait une erreur d'essayer d'obtenirjData[key]
Denis The Menace
@DenisTheMenace s'il s'agit d'un tableau, comment pourrais-je le boucler?
qasimalbaqali
@qasimalbaqali de la même manière que vous bouclez sur le dictionnaire. Mais les éléments du tableau seront tout simplement jData, pasjData[key]
Denis The Menace
Sidenote: Si votre API renvoie une réponse JSON volumineuse, vous pouvez l'imprimer comme ceci: print(json.dumps(jData, indent=4, sort_keys=True))
Marco
2
Sous python3, ce qui suit a été craché «JSON doit être str et non des octets». Ceci est corrigé en décodant la sortie, c'est-à-dire json.loads (myResponse.content.decode ('utf-8')). Vous devez également encapsuler la clé et la clé jData avec str () afin que lorsque l'API RESTful retourne des entiers, elle ne se plaint pas.
Mirkules
11

Donc, vous voulez passer des données dans le corps d'une demande GET, mieux vaut le faire dans un appel POST. Vous pouvez y parvenir en utilisant les deux requêtes.

Demande brute

GET http://ES_search_demo.com/document/record/_search?pretty=true HTTP/1.1
Host: ES_search_demo.com
Content-Length: 183
User-Agent: python-requests/2.9.0
Connection: keep-alive
Accept: */*
Accept-Encoding: gzip, deflate

{
  "query": {
    "bool": {
      "must": [
        {
          "text": {
            "record.document": "SOME_JOURNAL"
          }
        },
        {
          "text": {
            "record.articleTitle": "farmers"
          }
        }
      ],
      "must_not": [],
      "should": []
    }
  },
  "from": 0,
  "size": 50,
  "sort": [],
  "facets": {}
}

Exemple d'appel avec demandes

import requests

def consumeGETRequestSync():
data = '{
  "query": {
    "bool": {
      "must": [
        {
          "text": {
            "record.document": "SOME_JOURNAL"
          }
        },
        {
          "text": {
            "record.articleTitle": "farmers"
          }
        }
      ],
      "must_not": [],
      "should": []
    }
  },
  "from": 0,
  "size": 50,
  "sort": [],
  "facets": {}
}'
url = 'http://ES_search_demo.com/document/record/_search?pretty=true'
headers = {"Accept": "application/json"}
# call get service with headers and params
response = requests.get(url,data = data)
print "code:"+ str(response.status_code)
print "******************"
print "headers:"+ str(response.headers)
print "******************"
print "content:"+ str(response.text)

consumeGETRequestSync()
gvir
la source
a obtenu un lien mort là
user3157940
4
la variable headers doit être utilisée: requests.get (... headers = headers, ....)
Markus Meyer
9

Ci-dessous se trouve le programme pour exécuter les autres api en python-

import requests
url = 'https://url'
data = '{  "platform": {    "login": {      "userName": "name",      "password": "pwd"    }  } }'
response = requests.post(url, data=data,headers={"Content-Type": "application/json"})
print(response)
sid=response.json()['platform']['login']['sessionId']   //to extract the detail from response
print(response.text)
print(sid)
Shashank G
la source