D'après ce que je peux comprendre, les deux principales bibliothèques d'analyse HTML dans Python sont lxml et BeautifulSoup. J'ai choisi BeautifulSoup pour un projet sur lequel je travaille, mais je l'ai choisi pour aucune particularité autre raison que de trouver la syntaxe un peu plus facile à apprendre et à comprendre. Mais je vois que beaucoup de gens semblent favoriser le lxml et j'ai entendu dire que le lxml est plus rapide.
Je me demande donc quels sont les avantages de l'un par rapport à l'autre? Quand voudrais-je utiliser lxml et quand serais-je mieux d'utiliser BeautifulSoup? Y a-t-il d'autres bibliothèques qui méritent d'être envisagées?
Pour commencer, BeautifulSoup n'est plus activement maintenu et l'auteur recommande même des alternatives comme lxml.
Citant de la page liée:
La version 3.1.0 de Beautiful Soup fait bien pire sur le HTML réel que la version 3.0.8. Les problèmes les plus courants sont la gestion incorrecte des balises, les erreurs "balise de début malformée" et les erreurs "balise de fin incorrecte". Cette page explique ce qui s'est passé, comment le problème sera résolu et ce que vous pouvez faire dès maintenant.
Cette page a été écrite à l'origine en mars 2009. Depuis lors, la série 3.2 a été publiée, remplaçant la série 3.1, et le développement de la série 4.x a commencé. Cette page restera affichée à des fins historiques.
tl; dr
Utilisez plutôt 3.2.0.
Pyquery
fournit l'interface du sélecteur jQuery à Python (en utilisant lxml sous le capot).
http://pypi.python.org/pypi/pyquery
C'est vraiment génial, je n'utilise plus rien d'autre.
En résumé, lxml
est positionné comme un analyseur html et xml de qualité production ultra-rapide qui, en passant, comprend également un module soupparser
pour se rabattre sur les fonctionnalités de BeautifulSoup. BeautifulSoup
est un projet d'une seule personne, conçu pour vous faire gagner du temps pour extraire rapidement des données hors de html ou xml mal formé.
documentation lxml indique que les deux analyseurs ont des avantages et des inconvénients. Pour cette raison, lxml
fournit un soupparser
afin que vous puissiez basculer d'avant en arrière. Citant,
BeautifulSoup utilise une approche d'analyse différente. Ce n'est pas un véritable analyseur HTML mais utilise des expressions régulières pour plonger dans la soupe de balises. Elle est donc plus indulgente dans certains cas et moins bonne dans d'autres. Il n'est pas rare que lxml/libxml2 analyse et corrige mieux le HTML cassé, mais BeautifulSoup a un support supérieur pour la détection de l'encodage. Cela dépend beaucoup de l'entrée qui fonctionne le mieux.
En fin de compte, ils disent:
L'inconvénient de l'utilisation de cet analyseur est qu'il est beaucoup plus lent que l'analyseur HTML de lxml. Donc, si les performances sont importantes, vous pouvez envisager d'utiliser soupparser uniquement comme solution de rechange dans certains cas.
Si je les comprends correctement, cela signifie que l'analyseur de soupe est plus robuste --- il peut gérer une "soupe" de balises malformées en utilisant des expressions régulières --- tandis que lxml
est plus simple et analyse simplement les choses et construit un arbre comme vous vous en doutez. Je suppose que cela s'applique également à BeautifulSoup
lui-même, pas seulement à soupparser
pour lxml
.
Ils montrent également comment bénéficier de la détection de l'encodage de BeautifulSoup
, tout en analysant rapidement avec lxml
:
>>> from BeautifulSoup import UnicodeDammit
>>> def decode_html(html_string):
... converted = UnicodeDammit(html_string, isHTML=True)
... if not converted.unicode:
... raise UnicodeDecodeError(
... "Failed to detect encoding, tried [%s]",
... ', '.join(converted.triedEncodings))
... # print converted.originalEncoding
... return converted.unicode
>>> root = lxml.html.fromstring(decode_html(tag_soup))
(Même source: http://lxml.de/elementsoup.html ).
En mots du créateur de BeautifulSoup
,
C'est ça! S'amuser! J'ai écrit Beautiful Soup pour gagner du temps à tout le monde. Une fois que vous vous y êtes habitué, vous devriez être en mesure d'extraire des données de sites Web mal conçus en quelques minutes. Envoyez-moi un e-mail si vous avez des commentaires, rencontrez des problèmes ou si vous souhaitez que je connaisse votre projet qui utilise Beautiful Soup.
--Leonard
Cité de la documentation Beautiful Soup .
J'espère que c'est maintenant clair. La soupe est un brillant projet individuel conçu pour vous faire gagner du temps pour extraire des données de sites Web mal conçus. L'objectif est de vous faire gagner du temps dès maintenant, de faire le travail, pas nécessairement de vous faire gagner du temps sur le long terme, et certainement pas d'optimiser les performances de votre logiciel.
En outre, à partir du site Web lxml ,
lxml a été téléchargé à partir de l'index de package Python plus de deux millions de fois et est également disponible directement dans de nombreuses distributions de packages, par exemple pour Linux ou MacOS-X.
Et, de Pourquoi lxml? ,
Les bibliothèques C libxml2 et libxslt présentent d'énormes avantages: ... conformes aux normes ... complètes ... rapides. vite! VITE! ... lxml est une nouvelle liaison Python pour libxml2 et libxslt ...
N'utilisez pas BeautifulSoup, utilisez lxml.soupparser alors vous êtes au sommet de la puissance de lxml et pouvez utiliser les bons morceaux de BeautifulSoup qui sont pour faire face au HTML vraiment cassé et merdique.
J'ai utilisé lxml avec un grand succès pour l'analyse HTML. Il semble également faire un bon travail de gestion de HTML "soupy". Je le recommande vivement.
Voici un test rapide que j'ai eu pour essayer de manipuler du HTML laid:
import unittest
from StringIO import StringIO
from lxml import etree
class TestLxmlStuff(unittest.TestCase):
bad_html = """
<html>
<head><title>Test!</title></head>
<body>
<h1>Here's a heading
<p>Here's some text
<p>And some more text
<b>Bold!</b></i>
<table>
<tr>row
<tr><td>test1
<td>test2
</tr>
<tr>
<td colspan=2>spanning two
</table>
</body>
</html>"""
def test_soup(self):
"""Test lxml's parsing of really bad HTML"""
parser = etree.HTMLParser()
tree = etree.parse(StringIO(self.bad_html), parser)
self.assertEqual(len(tree.xpath('//tr')), 3)
self.assertEqual(len(tree.xpath('//td')), 3)
self.assertEqual(len(tree.xpath('//i')), 0)
#print(etree.tostring(tree.getroot(), pretty_print=False, method="html"))
if __== '__main__':
unittest.main()
Pour sûr, j'utiliserais EHP. Il est plus rapide que lxml, beaucoup plus élégant et plus simple à utiliser.
Check-out. https://github.com/iogf/ehp
<body ><em > foo <font color="red" ></font></em></body>
from ehp import *
data = '''<html> <body> <em> Hello world. </em> </body> </html>'''
html = Html()
dom = html.feed(data)
for ind in dom.find('em'):
print ind.text()
Production:
Hello world.
Une comparaison de vitesse quelque peu dépassée peut être trouvée ici , qui recommande clairement lxml, car les différences de vitesse semblent drastiques.