2010-07-18 15 views
23

Estoy tratando de obtener un valor de una página HTML utilizando la biblioteca HTMLParser de python. El valor que quiere agarrar está dentro de este elemento html:¿Cómo puedo usar la biblioteca HTMLParser de python para extraer datos de una etiqueta div específica?

... 
<div id="remository">20</div> 
... 

Ésta es mi clase HTMLParser hasta ahora:

class LinksParser(HTMLParser.HTMLParser): 
    def __init__(self): 
    HTMLParser.HTMLParser.__init__(self) 
    self.seen = {} 

    def handle_starttag(self, tag, attributes): 
    if tag != 'div': return 
    for name, value in attributes: 
    if name == 'id' and value == 'remository': 
     #print value 
     return 

    def handle_data(self, data): 
    print data 


p = LinksParser() 
f = urllib.urlopen("http://domain.com/somepage.html") 
html = f.read() 
p.feed(html) 
p.close() 

Puede alguien me punto en la dirección correcta? Quiero que la funcionalidad de clases para obtener el valor 20.

+1

Si usted está haciendo una gran cantidad de análisis de HTML, trate [Hermosa sopa] (http://www.crummy.com/software/BeautifulSoup/). – zvone

+3

¿Esa biblioteca está incluida como una biblioteca std python? Lo he encontrado, pero decidí seguir con HTMLParser. – Martin

+0

@zvone ¿Por qué BeautifulSoup es mejor para el análisis de html? ¿Sigue siendo un módulo recomendado? Gracias. –

Respuesta

44
class LinksParser(HTMLParser.HTMLParser): 
    def __init__(self): 
    HTMLParser.HTMLParser.__init__(self) 
    self.recording = 0 
    self.data = [] 

    def handle_starttag(self, tag, attributes): 
    if tag != 'div': 
     return 
    if self.recording: 
     self.recording += 1 
     return 
    for name, value in attributes: 
     if name == 'id' and value == 'remository': 
     break 
    else: 
     return 
    self.recording = 1 

    def handle_endtag(self, tag): 
    if tag == 'div' and self.recording: 
     self.recording -= 1 

    def handle_data(self, data): 
    if self.recording: 
     self.data.append(data) 

self.recording cuenta el número de etiquetas anidadas div a partir de una "activación" uno. Cuando estamos en el subárbol enraizado en una etiqueta de activación, acumulamos los datos en self.data.

Los datos al final del análisis se dejan en self.data (una lista de cadenas, posiblemente vacía si no se encontró ninguna etiqueta de activación). Su código de fuera de la clase puede acceder a la lista directamente desde la instancia al final del análisis, o puede agregar los métodos de acceso apropiados para el propósito, dependiendo de cuál es exactamente su objetivo.

La clase podría ser fácilmente hecho un poco más general mediante el uso de, en lugar de las cadenas literales constantes visto en el código anterior, 'div', 'id', y 'remository', atributos ejemplo self.tag, self.attname y self.attvalue, establecido por __init__ de argumentos Pasó a él - Evité ese paso de generalización barato en el código anterior para evitar oscurecer los puntos centrales (realizar un seguimiento de un recuento de etiquetas anidadas y acumular datos en una lista cuando el estado de grabación está activo).

+1

Gracias Alex, ese código funciona perfectamente (aparte de esta línea "if tag == div y self.recording:" - div debe ser una cadena). Lo que quise decir con la clase que devolvió un valor fue en realidad como describió, una función dentro de la clase para devolver el valor requerido. O podría acceder fácilmente a la variable 'datos'. El diccionario que tenía allí era solo un remanente de mí probando posibles soluciones :) ¡Gracias por tu ayuda! – Martin

+1

+1 para el recuento de 'div's anidados que no es tan obvio para quién se acerca al análisis de html por primera vez. –

+0

@Martin, de nada, y +1 para detectar mi distracción. Editaré ahora para corregir (citar 'div' y eliminar esa frase y comentario) para una mayor utilidad para los lectores futuros. –

4

pequeña corrección en la línea 3

HTMLParser.HTMLParser.__init__(self)

debe ser

HTMLParser.__init__(self)

Los siguientes trabajó para mí, sin embargo

import urllib2 

from HTMLParser import HTMLParser 

class MyHTMLParser(HTMLParser): 

    def __init__(self): 
    HTMLParser.__init__(self) 
    self.recording = 0 
    self.data = [] 
    def handle_starttag(self, tag, attrs): 
    if tag == 'required_tag': 
     for name, value in attrs: 
     if name == 'somename' and value == 'somevale': 
      print name, value 
      print "Encountered the beginning of a %s tag" % tag 
      self.recording = 1 


    def handle_endtag(self, tag): 
    if tag == 'required_tag': 
     self.recording -=1 
     print "Encountered the end of a %s tag" % tag 

    def handle_data(self, data): 
    if self.recording: 
     self.data.append(data) 

p = MyHTMLParser() 
f = urllib2.urlopen('http://www.someurl.com') 
html = f.read() 
p.feed(html) 
print p.data 
p.close() 

`

+3

, en realidad puede hacerlo porque ha especificado 'from HTMLParser import HTMLParser', que le permite llamar directamente a HTMLParser. Es desafortunado que ambos tengan el mismo nombre, pero son dos entidades diferentes. También podría hacer algo como 'de HTMLParser import HTMLParser como analizador' y luego simplemente usar' clase MyHTMLParser (analizador) ' –

22

¿Has probado BeautifulSoup?

from bs4 import BeautifulSoup 
soup = BeautifulSoup('<div id="remository">20</div>') 
tag=soup.div 
print(tag.string) 

Esto le da 20 en la salida.

0

Esto funciona perfectamente:

print (soup.find('the tag').text) 
Cuestiones relacionadas