将python脚本输出输出到文件时出现Unicode错误

将python脚本输出输出到文件时出现Unicode错误,python,unicode,beautifulsoup,Python,Unicode,Beautifulsoup,代码如下: print '"' + title.decode('utf-8', errors='ignore') + '",' \ ' "' + title.decode('utf-8', errors='ignore') + '", ' \ '"' + desc.decode('utf-8', errors='ignore') + '")' 标题和描述由Beautiful Soup 3(p[0].text和p[0].prettify)返回,据我从Beautiful S

代码如下:

print '"' + title.decode('utf-8', errors='ignore') + '",' \
      ' "' + title.decode('utf-8', errors='ignore') + '", ' \
      '"' + desc.decode('utf-8', errors='ignore') + '")'
标题和描述由Beautiful Soup 3(p[0].text和p[0].prettify)返回,据我从Beautiful Soup 3文档中了解到,它们是UTF-8编码的

如果我跑

python.exe script.py > out.txt
我发现以下错误:

Traceback (most recent call last):
  File "script.py", line 70, in <module>
    '"' + desc.decode('utf-8', errors='ignore') + '")'
UnicodeEncodeError: 'ascii' codec can't encode character u'\xf8' in position 264
: ordinal not in range(128)
我没有错。仅当指定了输出文件时才会发生这种情况


如何在输出文件中获得良好的UTF-8数据?

您可以使用编解码器模块将unicode数据写入文件

import codecs
file = codecs.open("out.txt", "w", "utf-8")
file.write(something)

“打印”输出到标准输出,如果您的控制台不支持utf-8,则即使将标准输出传输到文件,也可能导致此类错误。

将文本转换为unicode以进行打印是没有意义的。使用unicode处理数据,将其转换为某种编码进行输出

您的代码所做的是:您使用的是python 2,因此默认的字符串类型(
str
)是bytestring。在您的语句中,您从一些utf编码的字节字符串开始,将它们转换为unicode,并用引号将它们括起来(常规的
str
,强制转换为unicode以便合并为一个字符串)。然后将此unicode字符串传递给
print
,从而将其推送到
sys.stdout
。为此,它需要将其转换为字节。如果您正在向Windows控制台写入数据,它可能会以某种方式进行协商,但是如果您重定向到一个常规的哑文件,它会退回到ascii并发出抱怨,因为没有一种方法可以做到这一点

解决方案:不要给
print
一个unicode字符串。根据您的选择对其进行“编码”:

print "Latin-1:", "unicode über alles!".decode('utf-8').encode('latin-1')
print "Utf-8:", "unicode über alles!".decode('utf-8').encode('utf-8')
print "Windows:", "unicode über alles!".decode('utf-8').encode('cp1252')
当你重定向时,所有这些都应该毫无怨言地工作。它可能不会出现在屏幕上,但是用记事本或其他东西打开输出文件,看看编辑器是否设置为查看格式。(Utf-8是唯一有希望被检测到的。cp1252可能是Windows默认设置)

一旦你记下来,清理你的代码,避免使用打印输出文件。使用
编解码器
模块,用
编解码器打开文件。打开
而不是普通打开


注:如果您正在解码一个
utf-8
字符串,那么到unicode的转换应该不会丢失:您不需要
errors=ignore
标志。当您转换为ascii或Latin-2或其他格式,并且只想删除目标代码页中不存在的字符时,这是合适的

在这种情况下,Windows的行为有点复杂。您应该听取其他建议,在内部使用unicode作为字符串,并在输入过程中进行解码

对于您的问题,在stdout重定向的情况下,您需要打印编码字符串(只有您知道哪种编码!),但在简单屏幕输出的情况下,您必须打印unicode字符串(python或windows控制台处理到正确编码的转换)

我建议您以这种方式构建脚本:

# -*- coding: utf-8 -*- 
import sys, codecs
# set up output encoding
if not sys.stdout.isatty():
    # here you can set encoding for your 'out.txt' file
    sys.stdout = codecs.getwriter('utf8')(sys.stdout)

# next, you will print all strings in unicode
print u"Unicode string ěščřžý"
更新:另请参见其他类似问题:

问题: 如果在Windows上运行:

python.exe script.py
以下条款将生效:

sys.stdout.encoding: utf-8
sys.stdout.isatty(): True
但是,如果你跑步:

python.exe script.py > out.txt
您将有效地实现以下目标:

sys.stdout.encoding: cp1252
sys.stdout.isatty(): False
因此,可能的解决方案(在PYTHON>3.7中):

另见:

多次调用
decode
违反了“不要重复自己”原则。事实上,你根本不应该叫它。只需在标准输出上设置编码,就可以完成了。问题(Python的,不是你的)是Python有一个非常恼人的行为,因为它对待重定向输出的方式与对待未重定向输出的方式不同。现在我并不是在写完美的代码,我只是在尝试各种教程中我能掌握的东西,直到我弄明白什么是有效的(我相信伏都教编码)-那我就把它弄得干干净净。这是我第一天使用Python,到目前为止我还没有印象。Python没有很好的Unicode模型,至少在Python2中是这样。如果可以的话,你应该使用Python3。你更习惯什么语言?您是否考虑过简单地将
PYTHONIOENCODING
环境变量设置为“utf8”并让芯片落在可能的地方?您也不应该通常使用
errors='ignore'
,它隐藏了代码中的错误。主要是Delphi、PHP、Javascript,但也涉及到其他方面。通常我看到过两种处理字符串的模型——它们要么是内部Unicode,在输入/输出时解码/编码,要么是输入中任何内容的字节表示,只有在必要时才转换。Python似乎同时做这两件事,并且根据其他注释,解码是否可能发生取决于各种隐藏的事情。我还没有选择去尝试(多亏了这么多),所以我相信解决方案会出现。有没有编解码器可以输出字节字符串,而不尝试转换它们,比如“raw”或其他什么?@Kaitnieks:这是所有支持的编码的列表,一旦我将字符串转换为Unicode,这些编码实际上都会起作用。我不得不(遗憾地)放弃使用.prettify(),因为它返回字符串而不是Unicode字符串。谢谢。实际上,将字符串编码为utf-8并写入控制台可能会显示出奇怪的效果,但即使将输出重定向到文件,也不会导致错误。只有当你试图写出原始的unicode时,你才会触发python的自动转换,这将在有损转换为ascii时失败。哇,这太糟糕了。您永远不必在[插入许多其他语言]中执行类似的操作。你真的希望人们为每个输出语句调用两个函数吗?真是一场灾难!你太过分了,别再说了。您应该能够在输出上设置编码并忘记它。实际上,您不必这样做。OP把他的unicode处理搞得一团糟。只要对正在发生的事情有一点了解,转换就可以限制在必要的范围内。在Python3中,它在概念上更清楚地描述了正在发生的事情。如果你想在sys.stdout上设置编码,你可以,但那是另一个问题。这是我想的,但我不确定他会在哪里
sys.stdout.encoding: cp1252
sys.stdout.isatty(): False
import sys
if not sys.stdout.isatty():
    sys.stdout.reconfigure(encoding='utf-8')

print '"' + title.decode('utf-8', errors='ignore') + '",' \
      ' "' + title.decode('utf-8', errors='ignore') + '", ' \
      '"' + desc.decode('utf-8', errors='ignore') + '")'