我如何从 BeautifulSoup 中获取 CData

Posted

技术标签:

【中文标题】我如何从 BeautifulSoup 中获取 CData【英文标题】:How can i grab CData out of BeautifulSoup 【发布时间】:2011-01-03 04:21:25 【问题描述】:

我正在抓取一个具有以下类似结构的网站。我希望能够从 CData 块中获取信息。

我正在使用 BeautifulSoup 将其他信息从页面中提取出来,因此如果解决方案可以使用它,它将有助于降低我的学习曲线,因为我是 python 新手。 具体来说,我想了解隐藏在 CData 语句中的两种不同类型的数据。第一个只是文本我很确定我可以在它上面扔一个正则表达式并得到我需要的东西。对于第二种类型,如果我可以将包含 html 元素的数据放入它自己的 beautifulsoup 中,我可以解析它。

我只是在学习 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 ><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>

【问题讨论】:

哎呀,这是一个极度畸形的脚本块!如果那是真正的标记,它实际上不会在任何地方工作,无论是 XHTML 还是 HTML... 这不是真的,我想压缩一个更大的块。我猜我撕的太多了。 【参考方案1】:

BeautifulSoup 抓取 CData 需要注意的一件事是不要使用 lxml 解析器。

默认情况下,lxml 解析器将从树中删除 CDATA 部分并将其替换为纯文本内容,了解更多here

#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'
>>> 

【讨论】:

【参考方案2】:

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

在您的情况下,您当然可以查看从具有“main-contents”ID 的 div 开始的子树,而不是整个文档树。

【讨论】:

谢谢。这会做得很好,它甚至清除了开始和结束 位。我之前尝试过 BeautifulSoup.CData,但它对我不起作用。我收到以下错误:“AttributeError: class BeautifulSoup has no attribute 'CData'”猜想我需要“import BeautifulSoup”而不是“from BeautifulSoup import BeautifulSoup”。 @hary,是的,这种事情是我建议始终导入模块 (import BeautifulSoup) 而不是其中的点点滴滴的部分原因!-) 看来这种方法只适用于没有被注释掉的 CDATA 标签。在原始问题的示例中,找不到 CDATA。【参考方案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 的内容。

更新

这可能更干净一点:

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

只是个人喜好,但我更喜欢底部的那个。

【讨论】:

感谢您的回复,本网站知识丰富【参考方案4】:
import re
from bs4 import BeautifulSoup

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

【讨论】:

【参考方案5】:

对于使用 BeautifulSoup4 的任何人,Alex Martelli 的解决方案都有效,但请执行以下操作:

from bs4 import BeautifulSoup, CData

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

【讨论】:

以上是关于我如何从 BeautifulSoup 中获取 CData的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 BeautifulSoup 从父子标签中获取文本以放入 DOCX 表中

如何使用 BeautifulSoup 从 HTML 中去除评论标签?

如何在 Python 中使用 Beautifulsoup 从 Indeed 搜索中获取所有招聘信息的 href?

如何使用 beautifulsoup 从 js 和 Reactjs 获取数据? [复制]

使用 Beautifulsoup 从网站中提取数据

如何从 BeautifulSoup ( Python ) 中的表中获取第一个子表行