【问题标题】:BeautifulSoup with XML fails to parse full unicode strings带有 XML 的 BeautifulSoup 无法解析完整的 unicode 字符串
【发布时间】:2015-09-16 13:47:26
【问题描述】:

已编辑。 我正在使用 BeautifulSoup 和 lxml 来解析来自外部源的 XML 文档。奇怪的是,在某些文档上,解析器似乎在文本中间放弃并缩短了文档。

我已将其缩减为一个精确的测试用例:

from bs4 import BeautifulSoup
xml = "<ElementA><ElementB>Before bad character XX\n\x80 BAD\nAfter bad character</ElementB><ElementC>In element C</ElementC></ElementA>"
soup = BeautifulSoup(xml,"xml")
soup

给出不正确的输出:

<?xml version="1.0" encoding="utf-8"?>
<ElementA><ElementB/></ElementA>

但如果我只更改一件事并删除单个字符“X”:

from bs4 import BeautifulSoup
xml = "<ElementA><ElementB>Before bad character X\n\x80 BAD\nAfter bad character</ElementB><ElementC>In element C</ElementC></ElementA>"
soup = BeautifulSoup(xml,"xml")
soup

然后我得到更完整的输出:

<?xml version="1.0" encoding="utf-8"?>
<ElementA><ElementB>Before bad character X
 BAD
After bad character</ElementB><ElementC>In element C</ElementC></ElementA>

发生了什么事?我在 Python 3.4.3、OSX 上使用 BeautifulSoup 4.3.2 和 LXML 3.4.4。

到目前为止,我已经通过在解析之前通过 UnicodeDammit.detwingle() 传递 XML 字符串来解决这个问题,但是如果我能理解发生了什么以及单个附加字符如何具有这样的对文件的破坏性影响。

编辑。 使用 detwingleftfy 之类的工具不再有效。这是一个替代测试用例,具有正确的编码,在我的机器上没有被 bs4 / lxml 正确解析:

xml = "<ElementA><ElementB>Before bad character XX\n• BAD\nAfter bad character</ElementB><ElementC>In element C</ElementC></ElementA>"

出现与上述相同的问题。 谁能解释一下?

【问题讨论】:

    标签: python beautifulsoup lxml python-unicode


    【解决方案1】:

    这可能不是最好的解决方案,但这是我在抓取非 ascii 网站时所做的。而且每次都能完美运行。

    将默认编码更改为与网站相同。在你的情况下utf-8

    import sys
    reload(sys)
    sys.setdefaultencoding('utf-8')
    

    所以要打印/保存或解析您只需执行的任何非 ascii 字符,

    print 'non-ascii character'.encode('utf-8','ignore') # Replace your text or variable instead of 'non-ascii character'
    

    希望有帮助

    【讨论】:

    • 嗨,谢谢。它有点帮助。它去除了坏字符,这样 bs4 / lxml 就不会出错。实际上,通过detwingle()ftfy.fix_encoding() 传递它稍微好一些,因为它们实际上保留了预期的字符而不是剥离它们。我真正关心的是为什么内容首先被截断?这会无声无息地发生,没有任何警告,所以如果它发生在较大文本的末尾附近,我可能会错过它。关于如何在不更改字符串的情况下完全阻止这种情况发生的任何想法?
    • 阿格,说得太早了。 fix_encoding() 没有修复它。即使使用 valid unicode 字符也会出现问题。将上面的示例替换为:xml = "&lt;ElementA&gt;&lt;ElementB&gt;Before bad character XX\n• BAD\nAfter bad character&lt;/ElementB&gt;&lt;ElementC&gt;In element C&lt;/ElementC&gt;&lt;/ElementA&gt; } 要点是合法的:soup 解析仍然很短。这只是我的机器还是其他人可以重新创建它?
    • @cmuk 你把默认编码改成utf-8了吗?
    • 是的,utf-8 已经是我的默认编码(我在 python 3.4 上)。但是,您建议的 encode() 实际上可以解决问题。所以BeautifulSoup(str, 'xml')(作为unicode字符串)不起作用,但BeautfiulSoup(str.encode(),'xml')(作为字节字符串)确实起作用。我不确定为什么这是正确的,但它在超过 9,000 个文档上对我来说非常有效,所以我很高兴。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-08-20
    • 1970-01-01
    • 1970-01-01
    • 2012-10-28
    • 1970-01-01
    • 2011-12-22
    • 1970-01-01
    相关资源
    最近更新 更多