Je souhaiterais faire un petit script assez simple en python (voire plusieurs si je m'en sors bien) qui aura simplement pour but d'aller récupérer des informations sur une page web.
Sans m'y connaître beaucoup, je sais qu'une page web est composée de html essentiellement, et que ce langage propose des balises, qui identifient des champs. Je cherche donc un module python (simple, pas forcément performant) qui me permettra de parser une page html sans que je me prenne la tête.
Je sais qu'il existe des modules du genre HTMLparser, beautifulSoup et autres, mais je voudrais votre avis: connaissez vous un module simple, qui fasse bien son travail?
Je cherche donc un module python (simple, pas forcément performant) qui me permettra de parser une page html sans que je me prenne la tête.
Citation
Je sais qu'il existe des modules du genre HTMLparser, beautifulSoup et autres, mais je voudrais votre avis: connaissez vous un module simple, qui fasse bien son travail?
Ne le sont-ils pas? Sinon oui il y a autre chose mais c'est plus complexe et ça dépend de ce que tu cherches, les expressions régulières.
Le principe c'est que justement, je ne veux pas me farcir d'expression régulière.
Je demandais juste si vous utilisiez quelque chose de particulier pour faire ça. Un avis informé est toujours bon à prendre.
Oui, j'avais noté beautifulSoup, mais il n'est pas bien adapté pour python3.
J'ai essayé lxml. Bon alors ne vous moquez pas, mais je ne sais pas bien comment je dois procéder. Les infos que je trouve sont en anglais et pas appropriées la plupart du temps. Je vous donne mon code comme point de départ, qui récupère la page d'accueil d'allocine:
Voilà. Ça ça me donne un bon gros pavé de texte bien illisible. Je voudrais commencer souple:
-Dans un premier temps, afficher ça avec l'indention qu'il faut.
-Dans un deuxième temps, pouvoir extraire les infos d'un champ en particulier. Je ne sais pas, les titres des films qui sont dans la section "bandes annonces" par exemple.
J'ai déja essayé les exemples de la doc de lxml, mais ça ne donne rien de bon:
Tu risques de ne pas avoir que ce module non compatible avec python3, je te conseille la version 2.7, maintenant si tu veux absolument la version 3, rien ne t'empêche de trouver son équivalent sur le net
La seule raison qui me pousse à utiliser python 3, bin c'est que j'ai appris le python avec le tuto du sdz, qui présente la version 3.
En plus de ça, sur Arch, tous les modules et bibliothèques s'installent dans le dossier de python 3 (et c'est cette version l'interpréteur pas défaut). Alors c'est pas grand chose, mais ça m'evite de devoir bien indiquer le chemin de python, et d'installer les bibliothèques ailleurs.
Et puis je ne sais pas quelles différences il y a entre la 2.7 et la 3.2. Ça a vraiment changé?
Sous arch, tu peux installer nativement les paquets pour python 2 et python 3 (tente un yaourt -Ss python2, tu verras), et tu n'as pas à spécifier les chemins. Il suffit juste de taper python2 tonscript.py (ou bien de spécifier un shebang du style #!/usr/bin/env python2)…
C'est probablement la distro sur laquelle il est le plus facile de travailler avec les 2 versions de Python.
En ce qui concerne les différences, oui, plusieurs trucs ont changé, mais moyennant la doc sous les yeux, ça n'est pas non plus un handicap énorme (on s'habitue vite aux différences).
Ok, j'avoue, ça marche bien avec beautifulSoup et python 2.7.
En plus j'avais pas fait attention, mais dans les dépôts de Arch il y a python2-pip et python-pip, ce qui fait que je peux installer des modules spécifiquement pour une version sans me prendre la tête.
Mais c'est quand même bien dommage que je ne puisse pas faire ça avec python3. On m'avait conseillé lxml qui marche pour python3 normalement.
Vous vous préférez utiliser python2 à ce que j'ai compris? Mais est ce que quelqu'un pourrait se pencher sur mon code ci-dessus et me dire s'il y a un truc que je fais mal?
En regardant la doc je dirais un truc comme ça, attention code non testé
import urllib.request
from lxml import etree
from StringIO import StringIO
data = urllib.request.urlopen(url).read() # url est ton url
parser = etree.HTMLParser()
tree = etree.parse(StringIO(data), parser)
result = etree.tostring(tree.getroot(),pretty_print=True,
method="html")
print(result)
Il y a peut-être des erreurs mais c'est cohérent, ça se tente
@fred1599, merci mais est ce que tu pourrais faire un peu attention à ce que j'écris quand même?
J'ai posté plus ou moins le même code il y a 3 messages, donc la doc tu peux supposer que je l'ai lue.
Mon seul problème c'est que:
tree = etree.parse(StringIO(data), parser)
donne cette erreur:
tree = etree.parse(StringIO(data), parser)
TypeError: initial_value must be str or None, not bytes
Voilà pourquoi dans mon code je faisais:
page = str(url.read())
[...]
tree = etree.parse(StringIO(page), parser)
Ça marche sans erreur, mais ça ne renvoie pas la même chose que BeautifulSoup, à savoir la page avec l'indention. J'ai bien le code HTML, mais non formaté, en vrac.
#!/usr/bin/python
import urllib.request
from lxml import etree
from io import StringIO
with urllib.request.urlopen('http://www.allocine.fr/') as file:
pagedata = file.read()
page = pagedata.decode('UTF-8')
parser = etree.HTMLParser()
tree = etree.parse(StringIO(page), parser)
result = etree.tostring(tree.getroot(), pretty_print=True, method="html", encoding='UTF-8')
print(result)
Pas d'erreur, juste un gros pavé de texte désordonné...
C'ets bien comme ça que s'utilise la fonction decode() non? J'ai regardé le code source de la page, et j'ai trouvé une balise tout en haut avec text/html; charset=UTF-8 à l'intérieur.
Traceback (most recent call last):
File "/home/djipey/Desktop/python/allocine/allocine.py", line 22, in <module>
encoding = file.headers.getparam('charset')
AttributeError: 'HTTPMessage' object has no attribute 'getparam'
le shell a retourné 1
Appuyez sur ENTRÉE ou tapez une commande pour continuer
with urllib.request.urlopen('http://www.allocine.fr/') as file:
charset = file.info().get_charset()
if not charset:
charset = "ascii"
pagedata = file.read()
page = pagedata.decode('ascii')
Mais ça ne va pas poser problème pour les caractères spéciaux? (Ceux qui dépassent 255 en ascii)
Bon, j'ai fini par suivre vos conseils, j'ai préféré faire ce script avec python 2.7. Plus de modules compatibles, plus facile.
Je voudrais vous montrer un bout de code, avec les modules beautifulSoup et Requests, qui me simplifient beaucoup la tâche. Pouvez vous me dire si ma manière de récupérer les informations importantes est bonne, et ce qu'il y aurait à améliorer?
Pour l'instant le script charge une page que j'ai choisie (harry potter). Je n'ai pas encore fait de gestion d'erreurs, et c'est du code un peu dégueulasse. Je me suis basé sur le code source de la page, et j'ai cherché des éléments qui me permettent de dégager les informations, comme des chaînes de caractères spécifiques, ou certains tags.
Qu'en pensez vous?
#!/usr/bin/python
# -*-coding:Utf-8 -*
import requests
from BeautifulSoup import BeautifulSoup
import re
req = requests.get('http://www.allocine.fr/film/fichefilm_gen_cfilm=134925.html')
page = req.content
soup = BeautifulSoup(page)
#print soup.prettify()
# Renvoie le titre du film
titre=soup.findAll('title')
print(titre[0].renderContents())
# Renvoie le synopsis
#soup.findAll('p', limit=1)
synopsis=soup.findAll(property='v:summary')
print(synopsis[0].renderContents())
# Renvoie le genre
genre=soup.findAll(href=re.compile(".?/film/tous/genre.?"))
print(genre[0].renderContents())
# Renvoie la durée
duree=soup.findAll(text=re.compile(".?Dur.?e.?"))
duree=str(duree[0])
print(duree[10:18])
# Renvoie l'année de production
annee=soup.findAll(href=re.compile(".?/film/tous/decennie.?"))
print(annee[0].renderContents())
# Renvoie la compagnie qui produit le film
distributeur=soup.findAll(href=re.compile(".?/societe/fichesociete.?"))
print(distributeur[0].renderContents())
# Renvoie les notes du film
notes=soup.findAll(attrs={"class" : "moreinfo"})
print(notes[0].renderContents())
print(notes[1].renderContents())
print(notes[2].renderContents())
# Renvoie le réalisateur
realisateur=soup.findAll(rel='v:directedBy')
print(realisateur[0].renderContents())
# Renvoie le titre original
titre_original=soup.findAll(attrs={"class" : "purehtml"})
titre_original=titre_original[0].renderContents()
titre_original=titre_original[4:]
titre_original=titre_original[:len(titre_original)-5]
print(titre_original)
# Renvoie le casting
acteurs=soup.findAll(rel='v:starring')
for case in acteurs:
print(case.renderContents())
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
Blond, bouclé, toujours le sourire aux lèvres...