抱歉,我无法提供直接的中文翻译。可能是由于编码问题导致了该错误。请尝试使用其他方法或工具来进行翻译。

524

我正在尝试爬取一个网站,但是它给了我一个错误。

我使用以下代码:

import urllib.request
from bs4 import BeautifulSoup

get = urllib.request.urlopen("https://www.website.com/")
html = get.read()

soup = BeautifulSoup(html)

print(soup)

我遇到了以下错误:

File "C:\Python34\lib\encodings\cp1252.py", line 19, in encode
    return codecs.charmap_encode(input,self.errors,encoding_table)[0]
UnicodeEncodeError: 'charmap' codec can't encode characters in position 70924-70950: character maps to <undefined>

我该怎么做才能解决这个问题?

12个回答

759

当我将爬取的网页内容保存到文件中时,出现了相同的UnicodeEncodeError错误。为了修复它,我替换了这段代码:

with open(fname, "w") as f:
    f.write(html)

随着这个:

with open(fname, "w", encoding="utf-8") as f:
    f.write(html)

如果您需要支持Python 2,则使用以下内容:

import io
with io.open(fname, "w", encoding="utf-8") as f:
    f.write(html)

如果您想使用与UTF-8不同的编码,请为 encoding 指定实际编码。


25
在Mac(Python 3)中,只需打开文件而不需要编码即可完美运行,但在Windows(W10,Python 3)中则不行。必须以encoding="utf-8"参数的方式进行操作。 - xtornasol512
2
OP请求读取文件,而不是写入文件。问题似乎与控制台有关。 - NaturalBornCamper

272

我通过在 soup 中添加 .encode("utf-8") 来解决了这个问题。

这意味着 print(soup) 变成了 print(soup.encode("utf-8"))


7
不要在脚本中硬编码环境(例如控制台)的字符编码,而是直接打印Unicode。详情请参考这里:https://dev59.com/KXVD5IYBdhLWcg3wWaVh#32176732。 - jfs
7
这只是打印 bytes 对象的 repr,如果有大量UTF-8编码文本,它将以一堆 \x 序列的形式打印出来。建议使用 win_unicode_console,正如@J.F.Sebastian所建议的那样。 - Eryk Sun
10
它将输出 b'\x02x\xc2\xa9'(一个字节对象)。 - MilkyWay90

89
在Python 3.7和运行Windows 10中,这个操作是有效的(我不确定它是否适用于其他平台和/或其他版本的Python)替换此行:
with open('filename', 'w') as f:

使用这个:

with open('filename', 'w', encoding='utf-8') as f:

之所以它能够工作,是因为在使用该文件时将编码更改为UTF-8,因此UTF-8中的字符可以转换为文本,而不是在遇到当前编码不支持的UTF-8字符时返回错误。

3
print(soup) 返回 \xd0\xbf\xd0\xbe\xd0\xb6\xd0\xb0\xd0\xbb\xd1\x83\xd0\xb9\xd0\xba\xd1\x81\xd1\x82\xd0\xb0 - Coffee inTime
1
@CoffeeinTime 看起来像是将 UTF-16 错误地转换为某个 8 位编码,或者可能是使用 Python 2。你所展示的字符串已被截断,但似乎以“뿐뻐뛐냐믐菑말”开头(我不懂韩语,所以不知道这是否有意义)。演示:https://ideone.com/092Jnk - tripleee

60
set PYTHONIOENCODING=utf-8
set PYTHONLEGACYWINDOWSSTDIO=utf-8

你可能需要设置第二个环境变量PYTHONLEGACYWINDOWSSTDIO,也可能不需要。

另外,这也可以通过代码完成(尽管似乎建议通过环境变量来完成):

sys.stdin.reconfigure(encoding='utf-8')
sys.stdout.reconfigure(encoding='utf-8')

此外:复现这个错误有些麻烦,所以在这里留下了一些信息,以防您需要在自己的机器上进行复现:


set PYTHONIOENCODING=windows-1252
set PYTHONLEGACYWINDOWSSTDIO=windows-1252

1
这太完美了;我在Windows系统上使用Python调试器(pdb)查看使用utf-8编码且包含大量表情符号的源代码时遇到了此错误。每次执行“list”命令以查看我的位置时,“charmap”错误都会出现。设置这两个环境变量使我的调试变得非常顺畅。 - nutjob
5
Python 3.9.0版本中,sys.stdin.reconfigure命令无效。执行该命令会抛出AttributeError: 'StdInputFile' object has no attribute 'reconfigure'异常。 - Suncatcher
8
在Windows 10上,使用GIT BASH设置上述环境变量并没有生效,但是在实际的Python代码文件中设置这两行是可以生效的: sys.stdin.reconfigure(encoding='utf-8') sys.stdout.reconfigure(encoding='utf-8') - Henrik Carlström
@Suncatcher 尝试在另一个集成开发环境中运行这个Python脚本。 - Petr L.
@PetrL. 为什么我需要使用IDE呢?所有有效的Python命令都应该可以在Python Shell中解释,否则它们就是无效的。 - Suncatcher
显示剩余2条评论

21

在保存get请求的响应时,在Windows 10上的Python 3.7上出现了相同的错误。从URL接收到的响应编码为UTF-8,因此建议检查编码,以便可以传递相同的编码,避免这种琐碎的问题,因为它确实会在生产中浪费很多时间。

import requests
resp = requests.get('https://en.wikipedia.org/wiki/NIFTY_50')
print(resp.encoding)
with open ('NiftyList.txt', 'w') as f:
    f.write(resp.text)

当我在打开命令中添加了 encoding="utf-8" 后,它用正确的响应保存了文件

with open ('NiftyList.txt', 'w', encoding="utf-8") as f:
    f.write(resp.text)

14

我曾经也遇到过同样的问题:在打印、读写和打开文件时出现编码问题。如其他人所述,添加.encoding="utf-8"可以解决打印问题。

soup.encode("utf-8")

如果您要打开抓取的数据并将其写入文件,则使用 (......,encoding="utf-8") 打开文件。

with open(filename_csv , 'w', newline='',encoding="utf-8") as csv_file:


5
对于那些仍然遇到这个错误的人,将soup添加encode("utf-8")也可以解决这个问题。
soup = BeautifulSoup(html_doc, 'html.parser').encode("utf-8")
print(soup)

12
这样做后,“soup”不再是一个“BeautifulSoup”对象,因此无法进行操作或搜索。 - NaturalBornCamper
1
这个问题已经被OP自己的答案和Pardhu Gopalam的回答充分解决了。 - Karl Knechtel

5
这个问题有多个方面。根本问题是你想要输出到哪个字符集。你可能还需要确定输入字符集。
使用明确的 encoding="..." 将 Python 的内部 Unicode 表示转换为该编码,可以通过 printwrite 将其打印到文件中。如果输出包含不受该编码支持的字符,则会出现 UnicodeEncodeError。例如,如果编码为 "cp1252",则无法将俄语、中文、印度语、希伯来语、阿拉伯语或表情符号等除了一组约200个西方字符以外的任何内容写入文件,因为这种限制的8位字符集没有办法表示这些字符。
基本上,任何8位字符集都会出现相同的问题,包括几乎所有旧版 Windows 代码页(437、850、1250、1251等等),尽管其中一些支持英语之外的一些其他脚本(1251支持西里尔语,因此您可以写俄语、乌克兰语、塞尔维亚语、保加利亚语等)。8位编码只有最多256个字符代码,没有办法表示不在其中的字符。

也许现在是阅读Joel Spolsky的《绝对必要:关于Unicode和字符集,每个软件开发者都必须知道的最低限度(别找借口了!)》的好时机。

在终端无法打印Unicode的平台上(现在只有Windows存在这个问题,虽然如果你喜欢复古计算机,在上个世纪的其他平台上也存在这个问题),尝试print Unicode字符串也会产生错误,或输出乱码。如果你看到的是Héllö而不是Héllö,那么这就是你的问题。

简而言之,你需要知道:

  • 您爬取的页面或接收到的数据使用的是什么字符集?是否正确爬取?原始网站是否正确识别其编码,或者您能否以其他方式获取此信息(或猜测)?有些网站错误地声明了与页面实际包含的不同的字符集,有些网站在Web服务器和后端数据库之间的连接配置不正确。详见使用正确的字符编码进行抓取(Python requests + BeautifulSoup)等更详细的示例及解决方案。

  • 您想要写入的字符集是什么?如果打印到屏幕上,您的终端是否正确配置,并且您的Python解释器是否配置相同? 也许还可以参考如何在Windows控制台中显示UTF-8

如果您在这里,可能其中一个问题的答案不是“UTF-8”。尽管先前的标准是ISO-8859-1(又称为Latin-1),最近的Windows代码页1252,但这越来越成为Web页面的主流编码。

前进时,基本上希望所有文本数据都是Unicode,除了一些边缘用例。通常,这意味着使用UTF-8,但在Windows上(或者如果需要Java兼容性),UTF-16也可能有用,尽管有点繁琐。 (还有几种其他Unicode序列化格式,在特定情况下可能有用。UTF-32在技术上很简单,但占用更多内存;UTF-7在一些网络协议中使用,其中需要传输7位ASCII。) 也许还可以参见https://utf8everywhere.org/ 当然,如果要将内容打印到文件中,您还需要使用能够正确显示它的工具来检查该文件。一个常见的错误是使用仅显示当前选定系统编码或试图猜测编码但猜错的工具打开文件。再次查看使用Windows代码页1252查看UTF-8文本的常见症状会导致例如Héllö显示为Héllö
如果字符数据的编码未知,则没有简单的方法可以自动确定它。如果您知道文本应该表示什么,您可能可以推断出来,但这通常是一个需要一些猜测的手动过程。(像 chardetftfy 这样的自动工具可以帮助,但它们有时也会出错。)
为了确定你正在查看的编码方式,如果你能够识别一个字符中的单个字节,但该字符未正确显示,则会很有帮助。例如,如果你正在查看H\x8ell\x9a,但期望它表示Héllö,则可以在翻译表中查找这些字节。我已经发布了这样一张表格https://tripleee.github.io/8bit,在这个例子中,它可能是旧版Mac 8位字符集之一;有了更多数据点,也许你可以将其缩小到其中之一(如果不能,实际上任何一个都可以,因为你关心的所有代码点都映射到相同的Unicode字符)。
大多数平台上的Python 3默认使用UTF-8进行所有输入和输出,但在Windows上,情况通常不是这样。它将默认使用系统的默认编码方式(在某些Microsoft文档中仍被误导性地称为“ANSI代码页”),这取决于许多因素。在西方系统上,开箱即用的默认编码方式通常是Windows代码页1252。(早期的Python版本有稍微不同的期望,在Python 2中,内部字符串表示不是Unicode。)
如果你在Windows上编写UTF-8文本文件,可能需要指定 encoding="utf-8-sig",这会在文件开头添加BOM序列。严格来说这不是必要或正确的,但某些Windows工具需要它才能正确识别编码。
这里的一些早期答案建议盲目应用某些编码,但希望这可以帮助你理解这通常不是正确的方法,并了解如何找出而不是猜测要使用哪种编码。

也许还可以参考 https://meta.stackoverflow.com/questions/379403/problematic-questions-about-decoding-errors - tripleee

4
从Python 3.7开始,将环境变量PYTHONUTF8设置为1。
以下脚本还包括其他有用的变量,可以设置系统环境变量。
setx /m PYTHONUTF8 1
setx PATHEXT "%PATHEXT%;.PY" ; In CMD, Python file can be executed without extesnion.
setx /m PY_PYTHON 3.10 ; To set default python version for py

Source


2
代码片段似乎是为 Windows 设计的。对于使用 Bourne 家族 shell 的 Unix 系统,请尝试 export PYTHONUTF8=1(虽然这种类型的 hack 在 Windows 上可能是实际上必要的)。 - tripleee

2
我遇到了同样的错误,所以我使用(encoding="utf-8")来解决它。 通常当我们在文本数据中包含一些未被识别的符号或模式时,我们的编码器就无法理解。
with open("text.txt", "w", encoding='utf-8') as f:
     f.write(data)

这将解决你的问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接