Anfordern einer RESTful-API mithilfe von Python

221

Ich habe eine RESTful-API, die ich mithilfe einer Implementierung von Elasticsearch auf einer EC2-Instanz verfügbar gemacht habe, um einen Inhaltskorpus zu indizieren. Ich kann die Suche abfragen, indem ich Folgendes von meinem Terminal (MacOSX) aus ausführe:

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": {}
}'

Wie verwandle ich mich oben in eine API-Anfrage mit python/requestsoder python/urllib2(nicht sicher, für welche ich mich entscheiden soll - habe urllib2 verwendet, aber höre, dass Anfragen besser sind ...)? Übergebe ich als Header oder auf andere Weise?

user7289
quelle

Antworten:

340

Mit Anfragen :

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)

Abhängig davon, welche Art von Antwort Ihre API zurückgibt, möchten Sie sich dann wahrscheinlich ansehen response.textoder response.json()(oder möglicherweise response.status_codezuerst überprüfen ). Lesen Sie hier die Schnellstartdokumente , insbesondere diesen Abschnitt .

andersschuller
quelle
3
Ich denke, es sollte sein: response =
request.post
8
"request.get" akzeptiert keinen "data" -Parameter. Es kann ein optionaler Parameter "params" verwendet werden, bei dem es sich normalerweise um ein Diktat handelt, das eine Abfragezeichenfolge enthält. Wenn zum Abrufen von Daten eine Nutzlast erforderlich ist (z. B. das betreffende Beispiel), muss "request.post" verwendet werden. Darüber hinaus erleichtert die Verwendung der "json" -Bibliothek das Parsen der json-Antwort.
HVS
4
@ParveenShukhala "Requests unterstützt offiziell Python 2.6–2.7 & 3.3–3.5 und läuft hervorragend auf PyPy." - pypi.python.org/pypi/requests
danio
2
Da es sich um JSON handelt, das Sie senden, können Sie den Parameter json anstelle von Daten wie diesen verwenden: response = request.post (url, json = data)
Mark Chorley
101

Die Verwendung von Anfragen und JSON macht es einfach.

  1. Rufen Sie die API auf
  2. Angenommen, die API gibt einen JSON zurück, analysieren Sie das JSON-Objekt mithilfe der json.loadsFunktion in ein Python-Diktat
  3. Durchlaufen Sie das Diktat, um Informationen zu extrahieren.

Das Anforderungsmodul bietet Ihnen nützliche Funktionen zum Schleifen für Erfolg und Misserfolg.

if(Response.ok): hilft Ihnen festzustellen, ob Ihr API-Aufruf erfolgreich ist (Antwortcode - 200)

Response.raise_for_status() hilft Ihnen beim Abrufen des von der API zurückgegebenen http-Codes.

Unten finden Sie einen Beispielcode für solche API-Aufrufe. Kann auch in Github gefunden werden . Der Code setzt voraus, dass die API die Digest-Authentifizierung verwendet. Sie können dies entweder überspringen oder andere geeignete Authentifizierungsmodule verwenden, um den Client zu authentifizieren, der die API aufruft.

#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
quelle
2
Der letzte Teil mit Iteration über Schlüssel funktioniert nicht immer, da das JSON-Dokument möglicherweise ein Array als Element der obersten Ebene enthält. Es wäre also ein Fehler zu versuchenjData[key]
Denis The Menace
@DenisTheMenace Wenn es sich um ein Array handelt, wie würde ich es umgehen?
Qasimalbaqali
@qasimalbaqali auf die gleiche Weise, wie Sie das Wörterbuch durchlaufen. Aber Array-Elemente werden einfach jDatanicht seinjData[key]
Denis The Menace
Nebenbemerkung: Wenn Ihre API eine große JSON-Antwort zurückgibt, können Sie sie wie folgt ausdrucken: print(json.dumps(jData, indent=4, sort_keys=True))
Marco
2
Unter python3 wurde Folgendes ausgespuckt: "JSON muss str sein, keine Bytes". Dies wird durch Dekodieren der Ausgabe behoben, dh json.loads (myResponse.content.decode ('utf-8')). Außerdem sollten Sie den Schlüssel und den jData-Schlüssel mit str () umschließen, damit sich die RESTful-API nicht beschwert, wenn sie Ganzzahlen zurückgibt.
Mirkules
11

Wenn Sie also Daten im Hauptteil einer GET-Anforderung übergeben möchten, ist es besser, dies im POST-Aufruf zu tun. Sie können dies erreichen, indem Sie beide Anforderungen verwenden.

Rohe Anfrage

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": {}
}

Beispielanruf mit Anfragen

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
quelle
habe dort einen toten Link
user3157940
4
Die Header-Variable sollte verwendet werden: request.get (... headers = headers, ....)
Markus Meyer
9

Unten finden Sie das Programm zum Ausführen der restlichen API in 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.
quelle