Beautiful Soup 中文文档之二

剖析 HTML 使用 BeautifulSoup 类剖析HTML文档。 BeautifulSoup会得出以下一些信息:
  • 有些标签可以内嵌 如:BLOCKQUOTE,有些不行 如:P
  • table和list标签有一个自然的内嵌顺序。例如,TD标签内为TR标签,而不会相反。
  • SCRIPT 标签的内容不会被剖析为HTML。
  • META 标签可以知道文档的编码类型。
这是运行例子:
  1. 这是运行例子: 
  2.  
  3. from BeautifulSoup import BeautifulSoup
  4. html "<html><p>Para 1<p>Para 2<blockquote>Quote 1<blockquote>Quote 2"
  5. soup BeautifulSoup(html)
  6. print soup.prettify()
  7. # <html>
  8. #  <p>
  9. #   Para 1
  10. #  </p>
  11. #  <p>
  12. #   Para 2
  13. #   <blockquote>
  14. #    Quote 1
  15. #    <blockquote>
  16. #     Quote 2
  17. #    </blockquote>
  18. #   </blockquote>
  19. #  </p>
  20. # </html>
注意:BeautifulSoup 会智能判断那些需要添加关闭标签的位置,即使原始的文档没有。 也就是说那个文档不是一个有效的HTML,但是它也不是太糟糕。下面是一个比较糟糕的文档。在一些问题中,它的<FORM>的开始在 <TABLE> 外面,结束在<TABLE>里面。 (这种HTML在一些大公司的页面上也屡见不鲜)
  1. from BeautifulSoup import BeautifulSoup
  2. html """
  3. <html>
  4. <form>
  5.  <table>
  6.  <td><input name="input1">Row 1 cell 1
  7.  <tr><td>Row 2 cell 1
  8.  </form> 
  9.  <td>Row 2 cell 2<br>This</br> sure is a long cell
  10. </body> 
  11. </html>"""
Beautiful Soup 也可以处理这个文档:
  1. print BeautifulSoup(html).prettify()
  2. # <html>
  3. #  <form>
  4. #   <table>
  5. #    <td>
  6. #     <input name="input1" />
  7. #     Row 1 cell 1
  8. #    </td>
  9. #    <tr>
  10. #     <td>
  11. #      Row 2 cell 1
  12. #     </td>
  13. #    </tr>
  14. #   </table>
  15. #  </form>
  16. #  <td>
  17. #   Row 2 cell 2
  18. #   <br />
  19. #   This 
  20. #   sure is a long cell
  21. #  </td>
  22. # </html>
table的最后一个单元格已经在标签<TABLE>外了;Beautiful Soup 决定关闭<TABLE>标签当它在<FORM>标签哪里关闭了。写这个文档家伙原本打算使用<FORM>标签扩展到table的结尾,但是Beautiful Soup 肯定不知道这些。即使遇到这样糟糕的情况, Beautiful Soup 仍可以剖析这个不合格文档,使你开业存取所有数据。

剖析 XML

BeautifulSoup 类似浏览器,是个具有启发性的类,可以尽可能的推测HTML文档作者的意图。但是XML没有固定的标签集合,因此这些启发式的功能没有作用。因此 BeautifulSoup处理XML不是很好。 使用BeautifulStoneSoup类剖析XML文档。它是一个概括的类,没有任何特定的XML方言已经简单的标签内嵌规则。下面是范例:
  1. from BeautifulSoup import BeautifulStoneSoup
  2. xml "<doc><tag1>Contents 1<tag2>Contents 2<tag1>Contents 3"
  3. soup BeautifulStoneSoup(xml)
  4. print soup.prettify()
  5. # <doc>
  6. #  <tag1>
  7. #   Contents 1
  8. #   <tag2>
  9. #    Contents 2
  10. #   </tag2>
  11. #  </tag1>
  12. #  <tag1>
  13. #   Contents 3
  14. #  </tag1>
  15. # </doc>
BeautifulStoneSoup的一个主要缺点就是它不知道如何处理自结束标签 。 HTML 有固定的自结束标签集合,但是XML取决对应的DTD文件。你可以通过传递selfClosingTags 的参数的名字到 BeautifulStoneSoup的构造器中,指定自结束标签:
  1. from BeautifulSoup import BeautifulStoneSoup
  2. xml "<tag>Text 1<selfclosing>Text 2"
  3. print BeautifulStoneSoup(xml).prettify()
  4. # <tag>
  5. #  Text 1
  6. #  <selfclosing>
  7. #   Text 2
  8. #  </selfclosing>
  9. # </tag>
  10.  
  11. print BeautifulStoneSoup(xmlselfClosingTags=['selfclosing']).prettify()
  12. # <tag>
  13. #  Text 1
  14. #  <selfclosing />
  15. #  Text 2
  16. # </tag>

如果它不工作

这里有 一些其他的剖析类 使用与上述两个类不同的智能感应。你也可以子类化以及定制一个剖析器 使用你自己的智能感应方法。

使用Unicode的Beautiful Soup,Dammit

当你的文档被剖析之后,它就自动被转换为unicode。 Beautiful Soup 只存储Unicode字符串。
from BeautifulSoup import BeautifulSoup
soup = BeautifulSoup("Hello")
soup.contents[0]#u'Hello'
soup.originalEncoding#'ascii'
使用UTF-8编码的日文文档例子:
from BeautifulSoup import BeautifulSoup
soup = BeautifulSoup("xe3x81x93xe3x82x8cxe3x81xaf")
soup.contents[0]#u'u3053u308cu306f'
soup.originalEncoding#'utf-8'

str(soup)#'xe3x81x93xe3x82x8cxe3x81xaf'
#Note: this bit uses EUC-JP, so it only works if you have cjkcodecs#installed, or are running Python 2.4.
soup.__str__('euc-jp')#'xa4xb3xa4xecxa4xcf'
Beautiful Soup 使用一个称为UnicodeDammit 的类去来检测文档的编码,并将其转换为Unicode。如果你需要为其他文档(没有石油Beautiful Soup剖析过得文档)使用这转换,你也可以直接使用UnicodeDammit。它是基于Universal Feed Parser开发的。 如果你使用Python2.4之前的版本,请下载和安装cjkcodecs 以及iconvcodec 是python支持更多的编码,特别是CJK编码。要想更好地自动检测,你也要安装chardet Beautiful Soup 会按顺序尝试不同的编码将你的文档转换为Unicode:
  • 可以通过fromEncoding参数传递编码类型给soup的构造器
  • 通过文档本身找到编码类型:例如XML的声明或者HTML文档http-equiv的META标签。如果Beautiful Soup在文档中发现编码类型,它试着使用找到的类型转换文档。但是,如果你明显的指定一个编码类型,并且成功使用了编码:这时它会忽略任何它在文档中发现的编码类型。
  • 通过嗅探文件开头的一下数据,判断编码。如果编码类型可以被检测到,它将是这些中的一个:UTF-*编码,EBCDIC或者ASCII。
  • 通过chardet 库,嗅探编码,如果你安装了这个库。
  • UTF-8
  • Windows-1252
Beautiful Soup总是会猜对它可以猜测的。但是对于那些没有声明以及有着奇怪编码的文档,它会常常会失败。这时,它会选择Windows-1252编码,这个可能是错误的编码。下面是EUC-JP的例子,Beautiful Soup猜错了编码。(重申一下:因为它使用了EUC-JP, 这个例子只会在 python 2.4或者你安装了cjkcodecs的情况下才工作。):
from BeautifulSoup import BeautifulSoup
euc_jp = 'xa4xb3xa4xecxa4xcf'

soup = BeautifulSoup(euc_jp)
soup.originalEncoding#'windows-1252'

str(soup)#'xc2xa4xc2xb3xc2xa4xc3xacxc2xa4xc3x8f' # Wrong!
但如果你使用fromEncoding参数指定编码,它可以正确的剖析文档,并可以将文档转换为UTF-8或者转回EUC-JP。
soup = BeautifulSoup(euc_jp, fromEncoding="euc-jp")
soup.originalEncoding#'windows-1252'

str(soup)#'xe3x81x93xe3x82x8cxe3x81xaf' # Right!

soup.__str__(self, 'euc-jp') == euc_jp#True
如果你指定Beautiful Soup使用 Windows-1252编码(或者类似的编码如ISO-8859-1,ISO-8859-2), Beautiful Soup会找到并破坏文档的smart quotes以及其他的Windows-specific 字符。这些字符不会转换为相应的Unicode,而是将它们变为HTML entities(BeautifulSoup) 或者XML entitis(BeautifulStoneSoup)。 但是,你可以指定参数smartQuotesTo=None 到soup构造器:这时 smart quotes会被正确的转换为Unicode。你也可以指定smartQuotesTo为"xml"或"html" 去改变BeautifulSoupBeautifulStoneSoup的默认操作。
from BeautifulSoup import BeautifulSoup, BeautifulStoneSoup
text = "Deploy the x91SMART QUOTESx92!"

str(BeautifulSoup(text))#'Deploy the &lsquo;SMART QUOTES&rsquo;!'

str(BeautifulStoneSoup(text))#'Deploy the &#x2018;SMART QUOTES&#x2019;!'

str(BeautifulSoup(text, smartQuotesTo="xml"))#'Deploy the &#x2018;SMART QUOTES&#x2019;!'

BeautifulSoup(text, smartQuotesTo=None).contents[0]#u'Deploy the u2018SMART QUOTESu2019!'