Forum Programmation.python JSON how to get the data I want.

Posté par  . Licence CC By‑SA.
Étiquettes :
1
2
sept.
2015

Le but du truc : récupérer le début d’une définition Wikipédia d’un terme quelconque.

Alors voila comment je m’y prends

#!/usr/bin/env python3

"""AskWikipédia.py: Ask Wikipédia the définition of a shit."""
__author__ = "M4rotte"
__copyright__ = "Copyright 2015, Institut Marotte pour un Mouling de Qualitäy"
__license__ = "GPL"
__version__ = "0.1"

import sys                               # SYS module (used for argument management)
import requests                          # HTTP Requests
import html.parser                       # HTML Parser (not used for anything here but imported just for fun)
import simplejson as json                # JSON is fun

def askwiki(word):
  session = requests.Session()
  url = "https://fr.wikipedia.org/w/api.php?action=query&titles="+word+"&prop=revisions&rvprop=content&format=json"
  headers = {"User-Agent": ""}
  r = requests.Request('GET', url, headers=headers)
  request = r.prepare()
  try:
    response = session.send (request)
  except requests.exceptions.ConnectionError as error:
    return error   
  return response.text


if len(sys.argv) < 2:
  print("Usage: "+sys.argv[0]+" <word>")
else:
  s_data = askwiki(sys.argv[1])
  data = json.loads(s_data)
  print()
  print(data['query']['pages'])

Comme résultat j’obtiens un truc du genre :

$ ./AskWikipédia.py Sexe

{'7631': {'revisions': [{'*': "{{Nom proté[…]

Donc je peux, dans mon code, y accéder en faisant data['query']['pages']['7631'] mais voila je voudrais que ça fonctionne pour n’importe quelle request… Quel que soit l’ID de la page en question…

Comment devrais-je m’y prendre d’après-vous ?

  • # j'y connais rien en python, alors je parle au sens general

    Posté par  . Évalué à 2.

    en lisant la sortie.

    tu obtiens un objet JSON {'ID':{'revisions:[….]}}
    actuellement tu l'imprimes à l'ecran,

    mais qu'est ce qui t'empeche de LIRE l'ID contenu dans l'objet
    pour ensuite faire le print sur data['query']['pages'][ID] ?

  • # Utilise "values"

    Posté par  (site web personnel) . Évalué à 1.

    Avec ".values()", tu extrais uniquement les valeurs du dictionnaire, sous forme d'une liste. Donc si tu as un dictionnaire qui contient un seul item, tu auras la valeur de l'item de la manière suivante :

    dictionnaire.values()[0]

    Ce qui donne :

    print(data['query']['pages'].values()[0])
    • [^] # Re: Utilise "values"

      Posté par  (site web personnel) . Évalué à 1.

      Ah non, ça marche en Python2, pas en Python3, où values() retourne un objet de type dict_values et pas list.
      Bouge pas, j'reviens ;)

      • [^] # Re: Utilise "values"

        Posté par  (site web personnel) . Évalué à 1. Dernière modification le 02 septembre 2015 à 09:52.

        Ok, tu peux transformer en liste le retour de "values" :

        Ce qui donne :

        list(dictionnaire.values())[0]

        Ton script serait d'ailleurs un peu plus pythonnesque comme ça :

        #!/usr/bin/env python3
        
        import json
        import requests
        import sys
        
        def askwiki(word):
            return list(
                json.loads(requests.get(
                    "https://fr.wikipedia.org/w/api.php?action=query&titles={}&prop=revisions&rvprop=content&format=json".format(word)
                ).text)['query']['pages'].values()
            )[0]
        
        try:
            word = sys.argv[1]
        except IndexError:
            print("Usage: {} <word>".format(sys.argv[0]))
            sys.exit(1)
        
        print(askwiki(word))
        • [^] # Re: Utilise "values"

          Posté par  (site web personnel) . Évalué à 2.

          Plutôt que

          list(my_dict.values())[0]

          je trouve plus élégant:

          next(iter(my_dict.values()))

          Remarque: du coup si c'est vide on se tapera une exception StopIteration à la place d'une KeyError. J'imagine qu'il faut gérer ce cas.

          Question pour Marotte: es-tu sûr que dans le dictionnaire la première valeur (s'il elle existe) est forcément la bonne ?

  • # jq

    Posté par  . Évalué à 5.

    Avec curl pour faire la requête HTTP et jq pour interpréter le JSON :

    curl 'https://fr.wikipedia.org/w/api.php?action=query&titles=Linux&prop=revisions&rvprop=content&format=json' | jq -r '.query.pages[] | .revisions[] | .["*"]'

  • # Merci

    Posté par  . Évalué à 4.

    Merci à tous pour votre aide. J’obtiens ce que je veux avec :

    def askwiki(word):
      session = requests.Session()
      url = "https://fr.wikipedia.org/w/api.php?action=query&titles="+word+"&prop=revisions&rvprop=content&format=json"
      headers = {"User-Agent": ""}
      r = requests.Request('GET', url, headers=headers)
      request = r.prepare()
      try:
        response = session.send (request)
      except requests.exceptions.ConnectionError as error:
        return str(error)   
      return response.text
    
    try:
      s_data = askwiki(sys.argv[1])
    except IndexError:
      print("Usage: "+sys.argv[0]+" <word>")
      exit(1)
    try:  
      data = json.loads(s_data)
      print(list(data['query']['pages'].values())[0]['revisions'][0]['*'])
    except json.scanner.JSONDecodeError:
      print(s_data)
      exit(1)
    
    exit(0)

    C’est sûrement ni pythonesque ni élégant mais ça m’ira :) J’ai tout de même pythonisé l’absence d’argument, c’est vrai que c’est plus joli.

  • # Wikipédia API

    Posté par  . Évalué à 2. Dernière modification le 06 septembre 2015 à 16:48.

    Après quelques expérimentations je précise que l’API Wikipédia offre le moyen de récupérer directement du texte brut et pas cette chose trop galère à parser nommée « wikitext » (même pandoc se vautre comme une loutre bourée, le « wikitext » c’est pas du pur « Mediawiki text »)

    Voir https://fr.wikipedia.org/wiki/Sp%C3%A9cial:ApiSandbox#action=query&prop=extracts&format=json&explaintext=&titles=moule&redirects=

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.