Analisando HTML usando Python

185

Estou procurando um módulo Parser HTML para Python que possa me ajudar a obter as tags na forma de listas / dicionários / objetos em Python.

Se eu tiver um documento do formulário:

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

então, ele deve me dar uma maneira de acessar as tags aninhadas por meio do nome ou ID da tag HTML, para que eu possa basicamente solicitar que o conteúdo / texto da divtag class='container'contido na bodytag ou algo semelhante.

Se você usou o recurso "Inspecionar elemento" do Firefox (visualizar HTML), saberia que ele fornece todas as tags de maneira agradável e aninhada, como uma árvore.

Eu preferiria um módulo interno, mas isso pode estar pedindo um pouco demais.


Passei por muitas perguntas sobre o Stack Overflow e alguns blogs na Internet, e a maioria deles sugere BeautifulSoup ou lxml ou HTMLParser, mas poucos detalham a funcionalidade e simplesmente terminam como um debate sobre qual deles é mais rápido / eficaz.

briguento
fonte
2
como todos os outros respondentes, eu recomendaria o BeautifulSoup porque é realmente bom no manuseio de arquivos HTML quebrados.
Pascal Rosin

Respostas:

195

Para que eu possa solicitar o conteúdo / texto na tag div com class = 'container' contido na tag body, ou algo semelhante.

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)

Acho que você não precisa de descrições de desempenho - basta ler como o BeautifulSoup funciona. Veja a documentação oficial .

Aadaam
fonte
2
O que exatamente é o objeto parsed_html?
Ffledgling 29/07/12
1
parsed_html é um objeto BeautifulSoup, pense nele como um DOMElement ou DOMDocument, exceto que possui propriedades "complicadas", como "body" fará referência ao objeto BeautifulSoup (lembre-se, é basicamente um nó de árvore) do primeiro (e neste caso , apenas) elemento do corpo do elemento de raiz (no nosso caso, html)
Aadaam
18
Apenas uma atualização: a partir BeautifulSoup 4, a linha de importação é agorafrom bs4 import BeautifulSoup
Bailey Parker
2
Informações gerais: se o desempenho for crítico, use melhor a lxmlbiblioteca (veja a resposta abaixo). Com cssselectisso, é bastante útil também e o desempenho costuma ser 10 a 100 vezes melhor do que as outras bibliotecas disponíveis.
Lenar Hoyt
note: o classatributo é especial:BeautifulSoup(html).find('div', 'container').text
jfs
85

Eu acho que o que você está procurando é pyquery :

pyquery: uma biblioteca semelhante a jquery para python.

Um exemplo do que você deseja pode ser:

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

E usa os mesmos seletores do elemento de inspeção do Firefox ou Chrome. Por exemplo:

o seletor de elemento é 'div # mw-head.noprint'

O seletor de elemento inspecionado é 'div # mw-head.noprint'. Portanto, no pyquery, você só precisa passar neste seletor:

pq('div#mw-head.noprint')
YusuMishi
fonte
2
Eu te amo 3000 por isso!
Progyammer 28/05/19
41

Aqui você pode ler mais sobre os diferentes analisadores de HTML no Python e seu desempenho. Embora o artigo seja um pouco datado, ele ainda oferece uma boa visão geral.

Desempenho do analisador HTML do Python

Eu recomendaria o BeautifulSoup mesmo que não esteja incorporado. Só porque é muito fácil trabalhar com esses tipos de tarefas. Por exemplo:

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
fonte
2
Eu estava procurando por algo que detalha recursos / funcionalidades, em vez de desempenho / eficiência. EDIT: Desculpe pela resposta pré-madura, esse link é realmente bom. Obrigado.
Ffledgling 29/07/12
Os primeiros-lista ponto de tipos de resumir os recursos e funções :)
Qiau
5
Se você usa BeautifulSoup4 (versão mais recente):from bs4 import BeautifulSoup
Franck Dernoncourt
29

Comparado com as outras bibliotecas do analisador, lxmlé extremamente rápido:

E cssselecttambém é 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'))

Documentação lxml.html

Lenar Hoyt
fonte
HTTPS não suportado
Sergio
@Sergio uso import requests, save buffer para file: stackoverflow.com/a/14114741/1518921 (ou urllib), após a carga arquivo salvo usando análise,doc = parse('localfile.html').getroot()
Guilherme Nascimento
Analiso HTMLs enormes para dados específicos. Fazer isso com o BeautifulSoup demorou um 1.7pouco, mas a aplicação do lxml o aumentou quase *100vezes MAIS RAPIDAMENTE! Se se preocupa com desempenho, lxml é a melhor opção
Alex-Bogdanov
9

Eu recomendo o lxml para analisar o HTML. Consulte "Analisando HTML" (no site lxml).

Na minha experiência, a Beautiful Soup mexe com alguns HTML complexos. Acredito que é porque Beautiful Soup não é um analisador, mas um analisador de cordas muito bom.

Amor e paz - Joe Codeswell
fonte
3
É possível criar uma sopa bonita da AIUI para funcionar com a maioria dos analisadores XML "back-end", o lxml parece ser um dos analisadores suportados crummy.com/software/BeautifulSoup/bs4/doc/#installing-a-parser
enfrentando
@ffledgling Algumas funções do BeautifulSoup são bastante lentas.
Lenar Hoyt
2

Eu recomendo usar a 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
fonte
0

Eu usaria EHP

https://github.com/iogf/ehp

Aqui 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()

Resultado:

Something here
Something else
Soldado desconhecido
fonte
5
Por favor explique. O que você usaria o EHP sobre o popular BeautifulSoup ou lxml?
ChaimG