2010-01-09 16 views
6

Mam stronę internetową, którą skrobię, która ma podobną strukturę. Chciałbym móc pobrać informacje z bloku CData.Jak mogę pobrać CData z BeautifulSoup

Używam BeautifulSoup do wyciągania innych informacji poza stronę, więc jeśli rozwiązanie może z tym pracować, to pomoże mi utrzymać moją krzywą uczenia się, ponieważ jestem początkującym pytonem. W szczególności chcę uzyskać dwa różne typy danych ukryte w instrukcji CData. pierwszy, który jest tylko tekstem, jestem pewien, że mogę rzucić na niego wyrażenie i dostać to, czego potrzebuję. Dla drugiego typu, jeśli mógłbym upuścić dane, które mają elementy html do jego własnego beautifulsoup, mogę sparsować to.

Po prostu uczę się Pythona i Beautifulsoup, więc staram się znaleźć magiczną inkantację, która da mi samą CDatę.

<!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

Ou, to rozpaczliwie zniekształcony blok skryptu! Jeśli to jest prawdziwy znacznik, to nie zadziała nigdzie, ani XHTML, ani HTML ... – bobince

+0

to nie jest rzeczywiste, chciałem skondensować o wiele większy blok. zgadnij, że wyrwałem za dużo. –

Odpowiedz

3

Można spróbować to:

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] 

To powinno dać zawartość CDATA.

Aktualizacja

To może być trochę czystsze:

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")) 

tylko osobiste preferencje, ale podoba mi się dolny trochę lepiej.

+0

dzięki za odpowiedź, ta strona internetowa jest ogromnym bogactwem wiedzy –

11

BeautifulSoup widzi CData jako specjalny przypadek (podklasę) "żeglownych ciągów". Tak na przykład:

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 

w Twoim przypadku oczywiście można patrzeć w poddrzewie zaczynając div z id „Main-TREŚCI”, zamiast całego drzewa dokumentu.

+1

dzięki. to ładnie się sprawdzi, wyczyści nawet początkowe i końcowe bity. Próbowałem wcześniej BeautifulSoup.CData, ale to nie działało dla mnie. Otrzymałem następujący błąd: "AttributeError: klasa BeautifulSoup nie ma atrybutu" CData "" zgaduję, że potrzebowałem "importować BeautifulSoup" zamiast "from BeautifulSoup import BeautifulSoup". –

+1

@hary, tak, tego typu rzeczy jest częścią, dlatego polecam zawsze importowanie modułu ('import BeautifulSoup') zamiast bity i kawałki z wewnątrz! -) –

+1

Wydaje się, że to podejście działa tylko dla tagów CDATA, które nie zostały skomentowane. W oryginalnym pytaniu na pytanie CDATA nie zostanie znaleziona. – 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

jedno trzeba mieć opiekę podczas korzystania BeautifulSoup chwytając CDATA nie jest w użyciu lxml parser domyślnie parser lxml będzie rozebrać sekcje CDATA z drzewa i zastępowania ich zwykłym zawartości tekstowej, aby dowiedzieć się więcej tutaj 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' 
>>>