Как я могу получить CData из BeautifulSoup - PullRequest
6 голосов
/ 09 января 2010

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

Я использую 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>

Ответы [ 5 ]

12 голосов
/ 09 января 2010

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 с идентификатором 'main-contents', а не по всему дереву документа.

3 голосов
/ 28 декабря 2016

Одна вещь, с которой нужно быть осторожным BeautifulSoup захватывает CData - не использовать анализатор lxml.

По умолчанию синтаксический анализатор lxml удаляет секции CDATA из дерева и заменяет их на текстовое содержимое. Подробнее здесь

#Trying it with html.parser


>>> 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'
>>> 
3 голосов
/ 09 января 2010

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

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.

Обновление

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

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 голосов
/ 15 марта 2019

Для тех, кто использует BeautifulSoup4, решение Алекса Мартелли работает, но сделайте это:

from bs4 import BeautifulSoup, CData

soup = BeautifulSoup(txt)
for cd in soup.findAll(text=True):
  if isinstance(cd, Cdata):
    print 'CData contents: %r' % cd
0 голосов
/ 20 мая 2014
import re
from bs4 import BeautifulSoup

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