web-dev-qa-db-fra.com

Comment faire une demande de publication avec la bibliothèque de requêtes Python?

J'utilise les filtres suivants dans Postman pour effectuer une demande POST dans une API Web, mais je ne parviens pas à effectuer une simple POST demande en Python avec la bibliothèque de demandes. 

First, j'envoie une POST demande à cette URL ( http://10.61.202.98:8081/T/a/api/rows/cat/ect/tickets ) avec les filtres suivants dans Postman appliqués au Body, avec les options raw et JSON (application/json) sélectionnées. 

Filters in Postman

{
  "filter": {
    "filters": [
      {
        "field": "RCA_Assigned_Date",
        "operator": "gte",
        "value": "2017-05-31 00:00:00"
      },
      {
        "field": "RCA_Assigned_Date",
        "operator": "lte",
        "value": "2017-06-04 00:00:00"
      },
      {
        "field": "T_Subcategory",
        "operator": "neq",
        "value": "Temporary Degradation"
      },
      {
        "field": "Issue_Status",
        "operator": "neq",
        "value": "Queued"
      }],
     "logic": "and"
    }
}

La base de données où sont stockées les données est Cassandra et, selon les liens suivants Cassandra n’est pas l’opérateur égal , Cassandra OR l’opérateur , Cassandra Entre ordre des opérateurs , Cassandra ne prend pas en charge les opérateurs NOT EGAL TO, OU, ENTRE, il est donc impossible de filtrer l'URL. avec ces opérateurs sauf avec ET

Second, j'utilise le code suivant pour appliquer un filtre simple à la bibliothèque de requêtes. 

import requests
payload = {'field':'T_Subcategory','operator':'neq','value':'Temporary Degradation'}
url = requests.post("http://10.61.202.98:8081/T/a/api/rows/cat/ect/tickets",data=payload)

Mais ce que j’ai, c’est les données complètes des tickets au lieu de ceux qui ne sont pas des dégradations temporaires. 

Troisième, le système fonctionne réellement mais nous attendons un délai de 2-3 minutes pour voir les données. La logique est la suivante: Nous avons 8 utilisateurs et nous voulons voir tous les tickets par utilisateur qui ne constituent pas une dégradation temporaire.:

def get_json():
    if user_name == "user 001":
        with urllib.request.urlopen(
    "http://10.61.202.98:8081/T/a/api/rows/cat/ect/tickets?user_name=user&001",timeout=15) as url:
            complete_data = json.loads(url.read().decode())

    Elif user_name == "user 002":
        with urllib.request.urlopen(             
    "http://10.61.202.98:8081/T/a/api/rows/cat/ect/tickets?user_name=user&002",timeout=15) as url:
            complete_data = json.loads(url.read().decode())
    return complete_data

def get_tickets_not_temp_degradation(start_date,end_date,complete_):
    return Counter([k['user_name'] for k in complete_data if start_date < dateutil.parser.parse(k.get('DateTime')) < end_date and k['T_subcategory'] != 'Temporary Degradation'])

En gros, nous obtenons l’ensemble complet des tickets de l’année en cours et de l’année dernière, puis nous laissons Python filtrer l’ensemble complet par utilisateur; jusqu’à présent, il n’ya que 10 utilisateurs, ce qui signifie que ce processus est répété 10 fois et ne me surprend Découvrez pourquoi nous avons le retard ... 

Ma question est comment puis-je résoudre ce problème de la bibliothèque de demandes? J'utilise le lien suivant Demande la documentation de la bibliothèque comme didacticiel pour le faire fonctionner, mais il semble simplement que ma charge utile ne soit pas en cours de lecture.

6
Alejandro BR

Votre requête Postman est un corps JSON. Il suffit de reproduire ce même corps en Python. Votre code Python n'envoie pas de JSON, ni les mêmes données que votre exemple Postman.

Pour commencer, l'envoi d'un dictionnaire via les arguments data permet de coder ce dictionnaire au format application/x-www-form-urlencoded et non au format JSON. Deuxièmement, vous semblez envoyer un seul filtre.

Le code suivant reproduit exactement votre message Postman:

import requests

filters = {"filter": {
    "filters": [{
        "field": "RCA_Assigned_Date",
        "operator": "gte",
        "value": "2017-05-31 00:00:00"
    }, {
        "field": "RCA_Assigned_Date",
        "operator": "lte",
        "value": "2017-06-04 00:00:00"
    }, {
        "field": "T_Subcategory",
        "operator": "neq",
        "value": "Temporary Degradation"
    }, {
        "field": "Issue_Status",
        "operator": "neq",
        "value": "Queued"
    }],
    "logic": "and"
}}

url = "http://10.61.202.98:8081/T/a/api/rows/cat/ect/tickets"
response = requests.post(url, json=filters)

Notez que filters est une structure Python data ici, et qu’elle est transmise à l’argument json. Utiliser ce dernier fait deux choses:

  • Encodez la structure de données Python en JSON (en produisant exactement la même valeur JSON que la valeur brute de votre postman).
  • Définissez l'en-tête Content-Type sur application/json (comme vous l'avez fait dans votre configuration Postman en sélectionnant l'option JSON dans le menu déroulant après avoir sélectionné raw pour le corps).

requests est sinon juste une API HTTP , cela ne peut pas faire que Cassandra fasse plus que toute autre bibliothèque HTTP. Le code urllib.request.urlopen envoie des demandes GET et est traduit trivialement en requests avec:

def get_json():
    url = "http://10.61.202.98:8081/T/a/api/rows/cat/ect/tickets"
    response = requests.get(url, params={'user_name': user}, timeout=15)    
    return response.json()

J'ai supprimé la branche if et l'ai remplacée par l'argument params, qui traduit un dictionnaire de paires clé-valeur en une requête URL correctement codée (en passant le nom d'utilisateur sous la forme de la clé user_name).

Notez l'appel json() sur la réponse; cela prend en charge le décodage des données JSON provenant du serveur. Cela prend encore longtemps, vous ne filtrez pas beaucoup les données Cassandra ici.

9
Martijn Pieters

Je recommanderais d'utiliser l'attribut json au lieu de data. Il gère le dumping pour vous.

import requests

data = {'user_name':'user&001'}
headers = {'Content-Type': 'application/json', 'Accept': 'application/json'}
url = "http://10.61.202.98:8081/T/a/api/rows/cat/ect/tickets/"
r = requests.post(url, headers=headers, json=data)

Mise à jour, réponse à la question 3. Y a-t-il une raison pour laquelle vous utilisez urllib? J’utiliserais également des requêtes Python pour cette requête.

import requests

def get_json():
    r = requests.get("http://10.61.202.98:8081/T/a/api/rows/cat/ect/tickets”, params={"user_name": user_name.replace(" ", "&")})

    return r.json

# not sure what you’re doing here, more context/code example would help
def get_tickets_not_temp_degradation(start_date, end_date, complete_):
    return Counter([k['user_name'] for k in complete_data if start_date < dateutil.parser.parse(k.get('DateTime')) < end_date and k['T_subcategory'] != 'Temporary Degradation'])

De plus, le nom d'utilisateur est-il vraiment censé être user+001 et non pas user&001 ou user 001?

4
teewuane

Mon expérience est la suivante: J'ai essayé urllib et demande beaucoup en python pour gérer les API. C'est juste très problématique. Les requêtes GET sont généralement simples, mais les requêtes POST sont très problématiques. Parfois, cela ne fonctionne pas (comme dans le cas de votre charge utile), ou pire, cela fonctionne mal. J'ai eu ce script qui a récemment passé avec succès mes tests, mais cela n'a pas fonctionné dans certains cas en production, jusqu'à ce que je découvre que les requêtes contenant des caractères spéciaux (comme ã á en portugais) ne fonctionnaient pas. :(
À un moment donné, j'ai dit "au diable avec ces dépendances de la boîte noire". En fait, on peut faire n'importe quel appel d'API sans python ou tout autre langage de script (enfin, vous avez besoin de bash au moins). En tant qu'utilisateur UNIX, vous pouvez utiliser CURL pour TOUT. C'est libérateur! Plus d'exemples qui ne fonctionnent pas, plus de versions de langues, plus de bibliothèques http. Je viens d'envoyer une demande de curl du terminal et voir si ce que je veux fonctionne. Votre cas serait:

curl -H "Content-Type: application/json" -d '{"field":"T_Subcategory","operator":"neq","value":"Temporary Degradation"}' "http://10.61.202.98:8081/T/a/api/rows/cat/ect/tickets"

Ensuite, je construis le script python suivant pour GET:

import subprocess
import json

header1 = "Content-Type: application/json"   
header2 = "app_token: your_token"
header3 = "access_token: your_token2"

url = "https://your_api"
command = ["curl","-s","-H",header1,"-H",header2,"-H",header3, url ]
raw_response = subprocess.check_output(command)
string_response = raw_response.decode('utf8')
data = json.loads(string_response)

Pour POST:

import subprocess
import json

header1 = "Content-Type: application/json"   
header2 = "app_token: your_token"
header3 = "access_token: your_token2"

data = {"my":"phyton_dictionary"}
data = json.dumps(data) #this is a json string now

url = "https://your_api"
command = ["curl","-s","-H",header1,"-H",header2,"-H",header3, -d, data, url ]
raw_response = subprocess.check_output(command)
string_response = raw_response.decode('utf8')
data = json.loads(string_response)

Il est très facile de transformer ces deux prototypes en fonctions python et de créer une "bibliothèque", car vous avez besoin d'autres appels. Vous pouvez créer les paramètres d'URL manuellement si vous utilisez une API qui en a besoin.

Donc, cette réponse ne résout pas votre problème spécifique avec les demandes. Cela vous indique simplement que j'ai eu beaucoup de ces problèmes, résolu quelques-uns par style de piratage par essais et erreurs, et finalement résolu en modifiant la façon dont je construis le script API, en supprimant toutes les dépendances que je pouvais script très propre. Je n'ai plus eu de problèmes si les docs ont l'URL que je dois atteindre et les en-têtes que je dois envoyer. 

J'espère que ça aide.

0
Alex

Je pense que vous pouvez utiliser la bibliothèque de requêtes comme suit:

import requests
import json

payload = {'field':'T_Subcategory','operator':'neq','value':'Temporary Degradation'}
url = requests.post("http://10.61.202.98:8081/T/a/api/rows/cat/ect/tickets",data=json.dumps(payload))
0
juanblo

Vous envoyez un utilisateur en url, utilisez-le via post, mais cela dépend de la manière dont les points de terminaison sont mis en œuvre. Vous pouvez essayer le code ci-dessous:

import requests
from json import dumps

data = {'user_name':'user&001'}
headers = {'Content-Type': 'application/json', 'Accept': 'application/json'}
url = "http://10.61.202.98:8081/T/a/api/rows/cat/ect/tickets/"
r = requests.post(url, headers=headers, data=dumps(data))
0
anuj249