2010-01-09 21 views
6

Tengo un sitio web que estoy raspando que tiene una estructura similar a la siguiente. Me gustaría poder extraer la información del bloque CData.¿Cómo puedo tomar CData de BeautifulSoup

Estoy usando BeautifulSoup para extraer otra información de la página, por lo que si la solución puede funcionar con eso, ayudaría a mantener mi curva de aprendizaje baja ya que soy un principiante de Python. Específicamente, quiero obtener los dos tipos diferentes de datos ocultos en la declaración de CData. el primero, que es solo texto, estoy bastante seguro de que puedo lanzar una expresión regular y obtener lo que necesito. Para el segundo tipo, si puedo soltar los datos que tienen elementos html en su propio beautifulsoup, puedo analizarlos.

Estoy aprendiendo python y beautifulsoup, así que estoy luchando para encontrar el hechizo mágico que me dará simplemente el CData por sí mismo.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml"> 
<head> 
<title> 
    Cows and Sheep 
    </title> 
</head> 
<body> 
<div id="main"> 
    <div id="main-precontents"> 
    <div id="main-contents" class="main-contents"> 
    <script type="text/javascript"> 
     //<![CDATA[var _ = g_cow;_[7654]={cowname_enus:'cows rule!',leather_quality:99,icon:'cow_level_23'};_[37357]={sheepname_enus:'baa breath',wool_quality:75,icon:'sheep_level_23'};_[39654].cowmeat_enus = '<table><tr><td><b class="q4">cows rule!</b><br></br> 
     <!--ts--> 
     get it now<table width="100%"><tr><td>NOW</td><th>NOW</th></tr></table><span>244 Cows</span><br></br>67 leather<br></br>68 Brains 
     <!--yy--> 
     <span class="q0">Cow Bonus: +9 Cow Power</span><br></br>Sheep Power 60/60<br></br>Sheep 88<br></br>Cow Level 555</td></tr></table> 
     <!--?5695:5:40:45--> 
     '; 
     //]]> 
     </script> 
    </div> 
    </div> 
    </div> 
</body> 
</html> 
+0

¡Ouch, eso es un bloque de script desesperadamente mal formado! Si ese es el marcado real, en realidad no funcionará en ninguna parte, ni XHTML ni HTML ... – bobince

+0

no es real, quería condensar un bloque mucho más grande. Supongo que arranqué demasiado. –

Respuesta

3

Usted podría intentar esto:

from BeautifulSoup import BeautifulSoup 

// source.html contains your html above 
f = open('source.html') 
soup = BeautifulSoup(''.join(f.readlines())) 
s = soup.findAll('script') 
cdata = s[0].contents[0] 

Eso te dará el contenido de CDATA.

actualización

Esto puede ser un poco más limpio: la preferencia

from BeautifulSoup import BeautifulSoup 
import re 

// source.html contains your html above 
f = open('source.html') 
soup = BeautifulSoup(''.join(f.readlines())) 
cdata = soup.find(text=re.compile("CDATA")) 

Sólo personal, pero me gusta la de abajo un poco mejor.

+0

gracias por la respuesta, este sitio web es una gran riqueza de conocimiento –

11

BeautifulSoup ve a CData como un caso especial (subclase) de "cadenas navegables". Así, por ejemplo:

import BeautifulSoup 

txt = '''<foobar>We have 
     <![CDATA[some data here]]> 
     and more. 
     </foobar>''' 

soup = BeautifulSoup.BeautifulSoup(txt) 
for cd in soup.findAll(text=True): 
    if isinstance(cd, BeautifulSoup.CData): 
    print 'CData contents: %r' % cd 

En su caso, por supuesto, usted podría mirar en el subárbol comenzando en el div con ID 'los principales contenidos de', en lugar de toda la estructura del documento.

+1

gracias. esto funcionará muy bien, incluso limpió los bits inicial y final . Había probado BeautifulSoup.CData antes, pero no funcionó para mí. Obtuve el siguiente error: "AttributeError: clase BeautifulSoup no tiene ningún atributo 'CData'" supongo que necesitaba "importar BeautifulSoup" en lugar de "desde BeautifulSoup importamos BeautifulSoup". –

+1

@hary, sí, este tipo de cosas es parte de por qué recomiendo siempre importar el módulo ('importando BeautifulSoup') en lugar de bits y piezas dentro de él! -) –

+1

Parece que este enfoque solo funciona para las etiquetas CDATA que no tienen sido comentado En el ejemplo de la pregunta original, no se encontraría el CDATA. – amergin

0
import re 
from bs4 import BeautifulSoup 

soup = BeautifulSoup(content) 
for x in soup.find_all('item'): 
    print re.sub('[\[CDATA\]]', '', x.string) 
2

una cosa que necesita ser cuidado al utilizar BeautifulSoup agarrar programable CData no es utilizar analizador lxml, de forma predeterminada, el analizador de lxml se tira de las secciones CDATA desde el árbol y reemplazarlos por su contenido de texto sin formato, aprender más aquí https://groups.google.com/forum/?fromgroups=#!topic/beautifulsoup/whLj3jMRq7g

>>> from bs4 import BeautifulSoup 
>>> import bs4 
>>> s='''<?xml version="1.0" ?> 
<foo> 
    <bar><![CDATA[ 
     aaaaaaaaaaaaa 
    ]]></bar> 
</foo>''' 
>>> soup = BeautifulSoup(s, "html.parser") 
>>> soup.find(text=lambda tag: isinstance(tag, bs4.CData)).string.strip() 
'aaaaaaaaaaaaa' 
>>>