【问题标题】:Python Unicode hell: Decode and Encode not workingPython Unicode 地狱:解码和编码不起作用
【发布时间】:2016-03-31 14:53:45
【问题描述】:

我正在尝试从网上抓取一篇文章并将其写入数据库。

如果我这样做

article = article.decode('utf-8')

我明白了:

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

如果我这样做

article = article.encode('utf-8')

我明白了:

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

如果我这样做

article = article.encode('utf-8').decode()

或者这个

article = article.decode().encode('utf-8')

我还是明白了

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

问题:

对于解决此问题的任何帮助将不胜感激!

编辑:Stackoverflow 推荐了一篇文章,上面说 do .encode('utf-8') ,这不起作用,错误仍然存​​在。

【问题讨论】:

  • 你能升级到 Python 3.x 吗? article的类型是什么?
  • 我可能会升级到 3.x,需要弄清楚如何(我不是一个新手,但几乎是)......这篇文章是一篇关于电子音乐的博客文章,一个提示和技巧贴。
  • 我下载了python3,并将shebang #!/usr/bin/python3添加到我的脚本中,并继续得到错误UnicodeDecodeError:'ascii'编解码器无法解码位置5409的字节0xc4:序数不在范围内(128)
  • 您不能只是开始到处乱扔encodedecode 并期望一切正常 - 您需要了解您在做什么。首先,并非所有网页都具有相同的编码,因此您必须处理它,除非您使用的包已经将页面解码为 Unicode 字符串。你需要知道你从什么开始,你需要以什么结束!
  • 你不能只在任意 Python 对象上调用 .encode()/.decode() 并希望它能正常工作。您的问题至少缺少type(article)。提供minimal but complete code example that shows your issue 和相应的完整回溯(按原样复制粘贴)。

标签: python python-2.7 unicode encoding


【解决方案1】:

如果您知道自己在做什么,Unicode 并不痛苦。

如果我们尝试更系统的方法,并假设我们继续使用 Python 2.x,我们必须了解我们从网络等获取的所有内容都由字节组成,因此是 str

str 上,我们只能调用.decode(),在unicode 对象上,我们只能调用.encode()。 (这并不完全正确,但如果我们不遵循这一点,我们就会失去对内部解码/编码的控制,而这恰好可以弥补这种不匹配。)

例子:如果你这样做了

article = article.encode('utf-8')

你会得到一个UnicodeDecodeError,上面写着'ascii' codec can't decode byte 0xc4 in position 5409: ordinal not in range(128)

我们看到虽然我们调用了.encode(),但首先发生了decode 错误。这是因为对 .decode('ascii') 的隐式调用失败了,因为 str 中有非 ASCII 字节。

但是,我不明白为什么

article = article.decode('utf-8')

给出一个

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

因为这里根本不使用ascii 编解码器。也许您可以编辑您的问题并在此.decode() 调用之前添加print repr(article) 之前 的输出,以便我们可以尝试复制它。

【讨论】:

  • 我的猜测是 article 已经是一个 Unicode 对象,这将给出该异常。任何人都在猜测 OP 如何获得 Unicode。让我们希望散弹枪现在被收起来;)
  • @AlastairMcCormack 好吧,如果它是一个 Unicode 对象,它会给出一个 encode 错误。无论如何,你的猜测是对的。这就是为什么我要求那个对象的 repr;一旦我们拥有它,我们就会知道更多。
【解决方案2】:

在问题的字里行间和OP自己的答案之间阅读,看起来原始网页的编码没有得到处理。

网页需要正确解码。这可以通过检查Content-type: 标头或使用为您完成的HTTP 库来实现。 Requests 模块为您执行此操作并返回一个 decoded Unicode 对象。然后可以将此对象传递给 TextWrappers(通过io.open())以写入文件、数据库处理程序或 BeautifulSoup 进行解析。事实上,BeautifulSoup 应该只传递 Unicode 字符串。

使用请求的示例:

response = requests.get(url)

# A decoded Unicode object
response_body_unicode = response.text

soup = BeautifulSoup(response_body_unicode)

【讨论】:

  • 无需使用requests 来解码html页面。 BeautifulSoup handles it (better) already.
  • 是的,除了在我的小测试中至少 iso-8895-15 编码的文件,BS 将它与 windows-1252 混淆了。但是,我猜 BeautifulSoup 更有可能猜测正确的编码,而不是 HTTP 服务器报告的 Content-type 正确。
  • 没有灵丹妙药:服务器可能对编码撒谎,内容可能从使用不同编码的不同来源提取数据,smart quotes case was common。当response.encoding != soup.original_encoding依赖于应用程序时如何处理。
【解决方案3】:

看起来解决方法是将其添加到代码中

html = unicode(html, errors='ignore')

所以获取文章的完整代码如下所示

def getArticle(url):
    br = mechanize.Browser()
    br.set_handle_robots(False)
    br.addheaders = [("User-agent","Mozilla/5.0")] #our identity in the web
    html = br.open(url).read()

    html = unicode(html, errors='ignore')

    readable_article = Document(html).summary()
    readable_title = Document(html).short_title()

    soup = BeautifulSoup(readable_article)

    soup_title = BeautifulSoup(readable_title)

    final_article = soup.text
    final_title = soup_title.text

    links = soup.findAll('img', src=True)

    return html, final_article, final_title, links

【讨论】:

  • 这肯定会起作用,并且可能用空格或“?”替换大多数(如果不是全部)非 ascii 字符。 - 这里只是一个旁注。如果没关系,请忽略它。
  • @Shirkrin 鉴于没有其他工作,不确定我还有其他选择...
  • 同意。还有一件事——如果您尝试将此 u'äöü' 作为文本插入数据库中会发生什么? (如果不是输入的 html 可能是数据库试图强制转换为 ascii)
【解决方案4】:

尝试改用 utf 16。当发生上述情况时,这往往有助于解决我的问题。

     .decode('utf-16')

【讨论】:

  • 这只是猜测。当然,这只有在变量确实具有这种格式时才有效。
猜你喜欢
  • 2019-12-19
  • 2012-04-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多