2010-01-09 4 views
6

У меня есть веб-сайт, который я соскабливаю, который имеет похожую структуру следующим образом. Я хотел бы получить информацию из блока CData.Как я могу захватить CData из BeautifulSoup

Я использую BeautifulSoup, чтобы вытащить другую информацию со страницы, поэтому, если решение может работать с этим, это поможет сохранить мою кривую обучения, поскольку я начинающий python. В частности, я хочу получить два разных типа данных, скрытых в инструкции CData. первый, который является только текстом, я уверен, что могу набросить на него регулярное выражение и получить то, что мне нужно. Для второго типа, если бы я мог удалить данные, содержащие элементы html, в свой собственный красивый порт, я могу разобрать это.

Я просто изучаю python и beautifulsoup, поэтому я изо всех сил пытаюсь найти магическое заклинание, которое даст мне только CData.

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

Ой, это отчаянно искаженный блок сценария! Если это реальная разметка, на самом деле она нигде не будет работать, ни XHTML, ни HTML ... – bobince

+0

Это не реально, я хотел сконденсировать намного больший блок. думаю, я сорвал слишком много. –

ответ

3

Вы можете попробовать это:

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] 

Это должно дать вам содержание CDATA.

Update

Это может быть немного чище:

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

Просто личные предпочтения, но мне нравится нижняя немного лучше.

+0

спасибо за ответ, этот сайт - обширное богатство знаний –

11

BeautifulSoup видит CData как особый случай (подкласс) «судоходных строк». Так, например:

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 

В вашем случае, конечно, вы можете посмотреть в поддереве, начиная с DIV с идентификатором "ОСНОВНОЙ оглавлению, а не по всему дереву документа.

+1

спасибо. это будет хорошо, оно даже очистит начальную и конечную бит . Я попробовал BeautifulSoup.CData раньше, но это не сработало для меня. Я получил следующую ошибку: «AttributeError: класс BeautifulSoup не имеет атрибута« CData » Угадайте, мне нужно было« импортировать BeautifulSoup »вместо« из BeautifulSoup import BeautifulSoup ». –

+1

@hary, да, такого рода вещи являются частью того, почему я рекомендую всегда импортировать модуль ('import BeautifulSoup'), а не биты и куски из него! -) –

+1

Кажется, этот подход работает только для тегов CDATA, которые не имеют были прокомментированы. В примере исходного вопроса 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

одна вещь, которую вы должны заботиться о том, когда с помощью BeautifulSoup захвата CDATA не использовать LXML анализатор, по умолчанию, анализатор LXML будет раздеться секции CDATA из дерева и заменить их по простой текстовый контент, узнать больше здесь 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' 
>>> 
Смежные вопросы