【问题标题】:BeautifulSoup trips up on meta tagsBeautifulSoup 在元标签上绊倒
【发布时间】:2014-08-04 09:49:01
【问题描述】:

我有这个功能可以读取保存在计算机上的 HTML 文件:

 def get_doc_ondrive(self,mypath):
  the_file = open(mypath,"r")
  line = the_file.readline()
  if(line != "")and (line!=None):
   self.soup = BeautifulSoup(line)
  else:
   print "Something is wrong with line:\n\n%r\n\n" % line
   quit()
  print "\t\t------------ line: %r ---------------\n" % line
  while line != "":
   line = the_file.readline()
   print "\t\t------------ line: %r ---------------\n" % line
   if(line != "")and (line!=None):
    print "\t\t\tinner if executes: line: %r\n" % line
    self.soup.feed(line)
  self.get_word_vector()
  self.has_doc = True

执行self.soup = BeautifulSoup(open(mypath,"r")) 返回无,但逐行输入至少会崩溃并让我有一些东西可以查看。

我在 BeautifulSoup.py 和 sgmllib.py 中编辑了 traceback 列出的函数

当我尝试运行它时,我得到:

me@GIGABYTE-SERVER:code$ python test_docs.py
in sgml.finish_endtag

in _feed: inDocumentEncoding: None, fromEncoding: None, smartQuotesTo: 'html'
in UnicodeDammit.__init__: markup: '<!DOCTYPE html>\n'
in UnicodeDammit._detectEncoding: xml_data: '<!DOCTYPE html>\n'
in sgmlparser.feed: rawdata: '', data: u'<!DOCTYPE html>\n' self.goahead(0)
        ------------ line: '<!DOCTYPE html>\n' ---------------
        ------------ line: '<html dir="ltr" class="client-js ve-not-available" lang="en"><head>\n' ---------------
            inner if executes: line: '<html dir="ltr" class="client-js ve-not-available" lang="en"><head>\n'
in sgmlparser.feed: rawdata: u'', data: '<html dir="ltr" class="client-js ve-not-available" lang="en"><head>\n' self.goahead(0)
in sgmlparser.goahead: end: 0,rawdata[i]: u'<', i: 0,literal:0
in sgmlparser.parse_starttag: i: 0, __starttag_text: None, start_pos: 0, rawdata: u'<html dir="ltr" class="client-js ve-not-available" lang="en"><head>\n'
in sgmlparser.goahead: end: 0,rawdata[i]: u'<', i: 61,literal:0
in sgmlparser.parse_starttag: i: 61, __starttag_text: None, start_pos: 61, rawdata: u'<html dir="ltr" class="client-js ve-not-available" lang="en"><head>\n'
        ------------ line: '<meta http-equiv="content-type" content="text/html; charset=UTF-8">\n' ---------------
            inner if executes: line: '<meta http-equiv="content-type" content="text/html; charset=UTF-8">\n'
in sgmlparser.feed: rawdata: u'', data: '<meta http-equiv="content-type" content="text/html; charset=UTF-8">\n' self.goahead(0)
in sgmlparser.goahead: end: 0,rawdata[i]: u'<', i: 0,literal:0
in sgmlparser.parse_starttag: i: 0, __starttag_text: None, start_pos: 0, rawdata: u'<meta http-equiv="content-type" content="text/html; charset=UTF-8">\n'
in sgml.finish_starttag: tag: u'meta', attrs: [(u'http-equiv', u'content-type'), (u'content', u'text/html; charset=UTF-8')]
in start_meta: attrs: [(u'http-equiv', u'content-type'), (u'content', u'text/html; charset=UTF-8')] declaredHTMLEncoding: u'UTF-8'
in _feed: inDocumentEncoding: u'UTF-8', fromEncoding: None, smartQuotesTo: 'html'
in UnicodeDammit.__init__: markup: None
in UnicodeDammit._detectEncoding: xml_data: None

和追溯:

Traceback (most recent call last):
  File "test_docs.py", line 28, in <module>
    newdoc.get_doc_ondrive(testeee)
  File "/home/jddancks/Capstone/Python/code/pkg/vectors/DOCUMENT.py", line 117, in get_doc_ondrive
    self.soup.feed(line)
  File "/usr/lib/python2.7/sgmllib.py", line 104, in feed
    self.goahead(0)
  File "/usr/lib/python2.7/sgmllib.py", line 139, in goahead
    k = self.parse_starttag(i)
  File "/usr/lib/python2.7/sgmllib.py", line 298, in parse_starttag
    self.finish_starttag(tag, attrs)
  File "/usr/lib/python2.7/sgmllib.py", line 348, in finish_starttag
    self.handle_starttag(tag, method, attrs)
  File "/usr/lib/python2.7/sgmllib.py", line 385, in handle_starttag
    method(attrs)
  File "/usr/lib/python2.7/dist-packages/BeautifulSoup.py", line 1618, in start_meta
    self._feed(self.declaredHTMLEncoding)
  File "/usr/lib/python2.7/dist-packages/BeautifulSoup.py", line 1172, in _feed
    smartQuotesTo=self.smartQuotesTo, isHTML=isHTML)
  File "/usr/lib/python2.7/dist-packages/BeautifulSoup.py", line 1776, in __init__
    self._detectEncoding(markup, isHTML)
  File "/usr/lib/python2.7/dist-packages/BeautifulSoup.py", line 1922, in _detectEncoding
    '^<\?.*encoding=[\'"](.*?)[\'"].*\?>').match(xml_data)
TypeError: expected string or buffer

所以这一行

<meta http-equiv="content-type" content="text/html; charset=UTF-8">\n

以某种方式导致在 UnicodeDammit 中解析空字符串。为什么会这样?

【问题讨论】:

  • 你为什么不用bs4?

标签: python python-2.7 beautifulsoup python-2.x


【解决方案1】:

我刚刚通读了the source,我想我理解了这个问题。从本质上讲,BeautifulSoup 认为事情应该是这样的:

  1. 您使用整个标记调用 BeautifulSoup
  2. 它将self.markup 设置为该标记。
  3. 它自己调用_feed,它会重置文档并以最初检测到的编码对其进行解析。
  4. 在给自己喂食时,它会找到一个 meta 标记,该标记表示不同的编码。
  5. 要使用这种新编码,它会再次调用自己的_feed,然后重新解析self.markup
  6. 在第一个_feed 以及它递归到的_feed 完成后,它将self.markup 设置为None。 (毕竟,我们现在已经解析了所有内容;&lt;sarcasm&gt;曾经还需要原始标记?&lt;/sarcasm&gt;

但是你使用它的方式:

  1. 您使用标记的第一行调用BeautifulSoup
  2. 它将self.markup 设置为标记的第一行并调用_feed
  3. _feed 在第一行没有看到有趣的 meta 标记,因此成功完成。
  4. 构造函数认为我们已经完成了解析,因此它将self.markup 设置回None 并返回。
  5. 您在BeautifulSoup 对象上调用feed,它直接进入SGMLParser.feed 实现,它不会被BeautifulSoup 覆盖。
  6. 它看到了一个有趣的meta 标签并调用_feed 以这种新编码解析文档。
  7. _feed 试图用self.markup 构造一个UnicodeDammit 对象。
  8. 它爆炸了,因为 self.markupNone,因为它认为它只会在 BeautifulSoup 的构造函数中的那一小段时间内被调用。

故事的寓意是feed 是一种不受支持的向BeautifulSoup 发送输入的方式。您必须一次将所有输入传递给它。

至于为什么BeautifulSoup(open(mypath, "r"))返回None,我不知道;我没有看到在BeautifulSoup 上定义的__new__,所以它似乎必须返回一个BeautifulSoup 对象。

说了这么多,您可能想考虑使用 BeautifulSoup 4 而不是 3。Here’s the porting guide. 为了支持 Python 3,它必须删除对 SGMLParser 的依赖,而我如果在重写的那部分期间您遇到的任何错误得到修复,也不会感到惊讶。

【讨论】:

  • IDK 它是什么,但切换到 BS4 就成功了。谢谢先生,我认为您的回答将有助于其他人在未来谷歌搜索问题。
猜你喜欢
  • 2019-06-30
  • 2011-01-31
  • 2011-05-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多