Analizando HTML usando Python

185

Estoy buscando un módulo HTML Parser para Python que pueda ayudarme a obtener las etiquetas en forma de listas / diccionarios / objetos de Python.

Si tengo un documento de la forma:

<html>
<head>Heading</head>
<body attr1='val1'>
    <div class='container'>
        <div id='class'>Something here</div>
        <div>Something else</div>
    </div>
</body>
</html>

entonces debería darme una forma de acceder a las etiquetas anidadas a través del nombre o la identificación de la etiqueta HTML para que básicamente pueda pedirle que me proporcione el contenido / texto en la divetiqueta class='container'contenida dentro de la bodyetiqueta, o algo similar.

Si ha utilizado la función "Inspeccionar elemento" de Firefox (ver HTML), sabrá que le proporciona todas las etiquetas de una manera agradable y anidada como un árbol.

Prefiero un módulo incorporado, pero eso podría estar pidiendo demasiado.


Revisé muchas preguntas sobre Stack Overflow y algunos blogs en Internet y la mayoría de ellos sugieren BeautifulSoup o lxml o HTMLParser, pero pocos de estos detallan la funcionalidad y simplemente terminan como un debate sobre cuál es más rápido / más eficiente.

incipiente
fuente
2
Como todos los demás respondedores, recomendaría BeautifulSoup porque es realmente bueno en el manejo de archivos HTML rotos.
Pascal Rosin

Respuestas:

195

Para poder pedirle que me proporcione el contenido / texto en la etiqueta div con class = 'container' contenido dentro de la etiqueta del cuerpo, o algo similar.

try: 
    from BeautifulSoup import BeautifulSoup
except ImportError:
    from bs4 import BeautifulSoup
html = #the HTML code you've written above
parsed_html = BeautifulSoup(html)
print(parsed_html.body.find('div', attrs={'class':'container'}).text)

Supongo que no necesita descripciones de rendimiento, solo lea cómo funciona BeautifulSoup. Mira su documentación oficial .

Aadaam
fuente
2
¿Qué es exactamente el objeto parsed_html?
incipiente
1
parsed_html es un objeto BeautifulSoup, piense en él como un DOMElement o DOMDocument, excepto que tiene propiedades "difíciles", como "body" se referirá al objeto BeautifulSoup (recuerde, es un nodo de árbol básicamente) del primero (y en este caso , solo) elemento del cuerpo del elemento raíz (en nuestro caso, html)
Aadaam
18
Solo una actualización: a partir de BeautifulSoup 4, la línea de importación es ahorafrom bs4 import BeautifulSoup
Bailey Parker
2
Información general: si el rendimiento es crítico, mejor use la lxmlbiblioteca en su lugar (vea la respuesta a continuación). Con cssselectsu aswell bastante útil y el rendimiento suele ser de 10 a 100 veces mejor que las otras bibliotecas disponibles.
Lenar Hoyt
nota: el classatributo es especial:BeautifulSoup(html).find('div', 'container').text
jfs
85

Supongo que lo que estás buscando es pyquery :

pyquery: una biblioteca similar a jquery para python.

Un ejemplo de lo que quieres puede ser:

from pyquery import PyQuery    
html = # Your HTML CODE
pq = PyQuery(html)
tag = pq('div#id') # or     tag = pq('div.class')
print tag.text()

Y utiliza los mismos selectores que el elemento de inspección de Firefox o Chrome. Por ejemplo:

el selector de elementos es 'div # mw-head.noprint'

El selector de elementos inspeccionados es 'div # mw-head.noprint'. Entonces, en pyquery, solo necesita pasar este selector:

pq('div#mw-head.noprint')
YusuMishi
fuente
2
Te amo 3000 por esto!
Progyammer
41

Aquí puede leer más sobre los diferentes analizadores HTML en Python y su rendimiento. A pesar de que el artículo está un poco anticuado, todavía le ofrece una buena visión general.

Rendimiento del analizador HTML de Python

Recomiendo BeautifulSoup a pesar de que no está integrado. Solo porque es muy fácil trabajar para ese tipo de tareas. P.ej:

import urllib2
from BeautifulSoup import BeautifulSoup

page = urllib2.urlopen('http://www.google.com/')
soup = BeautifulSoup(page)

x = soup.body.find('div', attrs={'class' : 'container'}).text
Qiau
fuente
2
Estaba buscando algo que detalle características / funcionalidad en lugar de rendimiento / eficiencia. EDITAR: Perdón por la respuesta pre-madura, ese enlace es realmente bueno. Gracias.
incipiente
Los primeros tipos de listas de puntos resumen las características y funciones :)
Qiau
55
Si usa BeautifulSoup4 (última versión):from bs4 import BeautifulSoup
Franck Dernoncourt
29

En comparación con las otras bibliotecas de analizadores, lxmles extremadamente rápido:

Y cssselecttambién es bastante fácil de usar para raspar páginas HTML:

from lxml.html import parse
doc = parse('http://www.google.com').getroot()
for div in doc.cssselect('a'):
    print '%s: %s' % (div.text_content(), div.get('href'))

lxml.html Documentación

Lenar Hoyt
fuente
HTTPS no compatible
Sergio
@Sergio use import requests, guarde el búfer en el archivo: stackoverflow.com/a/14114741/1518921 (o urllib), después de cargar el archivo guardado usando parse,doc = parse('localfile.html').getroot()
Guilherme Nascimento
Analizo archivos HTML enormes para datos específicos. Hacerlo con BeautifulSoup tomó 1.7segundos, pero al aplicar lxml en su lugar, ¡lo impulsó casi más *100rápido! Si le importa el rendimiento, lxml es la mejor opción
Alex-Bogdanov
9

Recomiendo lxml para analizar HTML. Consulte "Análisis de HTML" (en el sitio lxml).

En mi experiencia, Beautiful Soup se equivoca en algunos HTML complejos. Creo que es porque Beautiful Soup no es un analizador sintáctico, sino un muy buen analizador de cadenas.

Amor y paz - Joe Codeswell
fuente
3
AIUI Beautiful Soup se puede hacer funcionar con la mayoría de los analizadores XML "backend", lxml parece ser uno de los analizadores compatibles crummy.com/software/BeautifulSoup/bs4/doc/#installing-a-parser
incipiente
@ffledgling Algunas funciones de BeautifulSoup son bastante lentas, sin embargo.
Lenar Hoyt
2

Recomiendo usar la biblioteca justext :

https://github.com/miso-belica/jusText

Uso: Python2:

import requests
import justext

response = requests.get("http://planet.python.org/")
paragraphs = justext.justext(response.content, justext.get_stoplist("English"))
for paragraph in paragraphs:
    print paragraph.text

Python3:

import requests
import justext

response = requests.get("http://bbc.com/")
paragraphs = justext.justext(response.content, justext.get_stoplist("English"))
for paragraph in paragraphs:
    print (paragraph.text)
Wesam Na
fuente
0

Usaría EHP

https://github.com/iogf/ehp

Aquí está:

from ehp import *

doc = '''<html>
<head>Heading</head>
<body attr1='val1'>
    <div class='container'>
        <div id='class'>Something here</div>
        <div>Something else</div>
    </div>
</body>
</html>
'''

html = Html()
dom = html.feed(doc)
for ind in dom.find('div', ('class', 'container')):
    print ind.text()

Salida:

Something here
Something else
Soldado desconocido
fuente
55
Por favor explique. ¿Qué usarías EHP sobre el popular BeautifulSoup o lxml?
ChaimG