【问题标题】:How to fix UnicodeDecodeError: 'ascii' codec can't decode byte?如何修复 UnicodeDecodeError:“ascii”编解码器无法解码字节?
【发布时间】:2017-10-05 15:23:37
【问题描述】:
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc2 in position 0: ordinal not in range(128)

这是我在尝试清理我使用 spaCy 从 html 页面中提取的名称列表时遇到的错误。

我的代码:

import urllib
import requests
from bs4 import BeautifulSoup
import spacy
from spacy.en import English
from __future__ import unicode_literals
nlp_toolkit = English()
nlp = spacy.load('en')

def get_text(url):
    r = requests.get(url)
    soup = BeautifulSoup(r.content, "lxml")

    # delete unwanted tags:
    for s in soup(['figure', 'script', 'style']):
        s.decompose()

    # use separator to separate paragraphs and subtitles!
    article_soup = [s.get_text(separator="\n", strip=True) for s in soup.find_all( 'div', {'class': 'story-body__inner'})]

    text = ''.join(article_soup)
    return text

# using spacy
def get_names(all_tags):
    names=[]
    for ent in all_tags.ents:
        if ent.label_=="PERSON":
            names.append(str(ent))
    return names

def cleaning_names(names):
    new_names = [s.strip("'s") for s in names] # remove 's' from names
    myset = list(set(new_names)) #remove duplicates
    return myset

def main():
    url = "http://www.bbc.co.uk/news/uk-politics-39784164"
    text=get_text(url)
    text=u"{}".format(text)
    all_tags = nlp(text)
    names = get_person(all_tags)
    print "names:"
    print names
    mynewlist = cleaning_names(names)
    print mynewlist

if __name__ == '__main__':
    main()

对于这个特定的 URL,我会得到包含 £ 或 $ 等字符的名称列表:

['尼克克莱格','英国脱欧','\xc2\xa3590亿','特蕾莎梅','英国脱欧', “英国脱欧”、“克莱格先生”、“克莱格先生”、“克莱格先生”、“英国退欧”、“克莱格先生”、 '特蕾莎梅']

然后报错:

Traceback (most recent call last) <ipython-input-19-8582e806c94a> in <module>()
     47 
     48 if __name__ == '__main__':
---> 49     main()

<ipython-input-19-8582e806c94a> in main()
     43     print "names:"
     44     print names
---> 45     mynewlist = cleaning_names(names)
     46     print mynewlist
     47 

<ipython-input-19-8582e806c94a> in cleaning_names(names)
     31 
     32 def cleaning_names(names):
---> 33     new_names = [s.strip("'s") for s in names] # remove 's' from names
     34     myset = list(set(new_names)) #remove duplicates
     35     return myset

UnicodeDecodeError: 'ascii' codec can't decode byte 0xc2 in position 0: ordinal not in range(128)

我尝试了不同的方法来修复 unicode(包括sys.setdefaultencoding('utf8')),但没有任何效果。我希望有人以前遇到过同样的问题,并且能够提出修复建议。谢谢!

【问题讨论】:

  • 清理你的回溯。不可读。
  • 不确定错误发生在哪里,并且由于库而不会重现。如果您手动修复名称列表是否有效?
  • 您是否检查了右侧显示的相关问题?
  • 我检查了相关问题,但找不到适合我的案例的解决方案。我还尝试在将名称列表传递给清理函数之前对其进行操作,但再次对其进行解码和编码并没有帮助。
  • 将此text=u"{}".format(text) 改为使用decode(...)

标签: python-2.7 unicode beautifulsoup spacy


【解决方案1】:

当您使用'ascii' 编解码器出现解码错误时,这通常表明在需要 Unicode 字符串的上下文中使用了字节字符串(在 Python 2 中,Python 3 根本不允许)。

由于您已导入 from __future__ import unicode_literals,字符串 "'s" 是 Unicode。这意味着您尝试strip 的字符串也必须是Unicode 字符串。修复它,您将不会再收到错误。

【讨论】:

  • 这正是我想要解决的问题。
  • @aviss 你有一个答案,自从被删除后,它告诉你如何修复它。我对requestsBeautifulSoup 了解不多,无法详细说明。
【解决方案2】:

正如@MarkRansom 评论的那样,忽略非 ascii 字符会反噬你。

先看看

另外,请注意这是一个反模式:Why should we NOT use sys.setdefaultencoding("utf-8") in a py script?

最简单的解决方案是只使用 Python3,这样会减轻一些痛苦

>>> import requests
>>> from bs4 import BeautifulSoup
>>> import spacy
>>> nlp = spacy.load('en')

>>> url = "http://www.bbc.co.uk/news/uk-politics-39784164"
>>> html = requests.get(url).content
>>> bsoup = BeautifulSoup(html, 'html.parser')
>>> text = '\n'.join(p.text for d in bsoup.find_all( 'div', {'class': 'story-body__inner'}) for p in d.find_all('p') if p.text.strip())

>>> import spacy
>>> nlp = spacy.load('en')
>>> doc = nlp(text)
>>> names = [ent for ent in doc.ents if ent.ent_type_ == 'PERSON']

【讨论】:

    【解决方案3】:

    我终于修复了我的代码。我很惊讶它看起来如此简单,但我花了很长时间才到达那里,而且我看到很多人对同样的问题感到困惑,所以我决定发布我的答案。

    在传递名称以进行进一步清理之前添加这个小函数解决了我的问题。

    def decode(names):        
        decodednames = []
        for name in names:
            decodednames.append(unicode(name, errors='ignore'))
        return decodednames
    

    SpaCy 仍然认为 590 亿英镑是一个人,但我没关系,我可以稍后在我的代码中处理这个问题。

    工作代码:

    import urllib
    import requests
    from bs4 import BeautifulSoup
    import spacy
    from spacy.en import English
    from __future__ import unicode_literals
    nlp_toolkit = English()
    nlp = spacy.load('en')
    
    def get_text(url):
        r = requests.get(url)
        soup = BeautifulSoup(r.content, "lxml")
    
        # delete unwanted tags:
        for s in soup(['figure', 'script', 'style']):
            s.decompose()
    
        # use separator to separate paragraphs and subtitles!
        article_soup = [s.get_text(separator="\n", strip=True) for s in soup.find_all( 'div', {'class': 'story-body__inner'})]
    
        text = ''.join(article_soup)
        return text
    
    # using spacy
    def get_names(all_tags):
        names=[]
        for ent in all_tags.ents:
            if ent.label_=="PERSON":
                names.append(str(ent))
        return names
    
    def decode(names):        
        decodednames = []
        for name in names:
            decodednames.append(unicode(name, errors='ignore'))
        return decodednames
    
    def cleaning_names(names):
        new_names = [s.strip("'s") for s in names] # remove 's' from names
        myset = list(set(new_names)) #remove duplicates
        return myset
    
    def main():
        url = "http://www.bbc.co.uk/news/uk-politics-39784164"
        text=get_text(url)
        text=u"{}".format(text)
        all_tags = nlp(text)
        names = get_person(all_tags)
        print "names:"
        print names
        decodednames = decode(names)
        mynewlist = cleaning_names(decodednames)
        print mynewlist
    
    if __name__ == '__main__':
        main()
    

    这给了我这个没有错误:

    名字:['Nick Clegg', 'Brexit', '\xc2\xa359bn', 'Theresa May', “脱欧”、“脱欧”、“克莱格先生”、“克莱格先生”、“克莱格先生”、“脱欧”、“先生 Clegg', 'Theresa May'] [u'Mr Clegg', u'Brexit', u'Nick Clegg', 你'590亿',你'特蕾莎梅']

    【讨论】:

    • 当然,您可以简单地忽略所有非 ASCII 字符,这很简单。不过,它可能稍后会回来咬你。进行转换的正确方法是让库为您完成,因为它们知道适当的编码而您不知道。
    猜你喜欢
    • 2014-02-03
    • 1970-01-01
    • 1970-01-01
    • 2013-08-20
    • 2014-04-09
    • 2018-08-02
    • 2013-09-23
    • 2013-06-17
    相关资源
    最近更新 更多