我正在尝试抓取一个网站,但它给了我一个错误。
我正在使用以下代码:
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>
我能做些什么来解决这个问题?
将抓取的网络内容保存到文件时,我得到了相同的 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
的实际编码。
我通过将 .encode("utf-8")
添加到 soup
来修复它。
这意味着 print(soup)
变为 print(soup.encode("utf-8"))
。
bytes
对象的 repr,如果有很多 UTF-8 编码的文本,它将打印成乱七八糟的 \x
序列。正如@JFSebastian 建议的那样,我建议使用 win_unicode_console
。
b'\x02x\xc2\xa9'
(一个字节对象)
print(soup.encode("utf-8"))
为我工作,但在此之前我还必须添加 with open("f_name", encoding="utf-8") as f: soup = BeautifulSoup(f, "html.parser")
在 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 字符时返回错误当前编码不支持。
set PYTHONIOENCODING=utf-8
set PYTHONLEGACYWINDOWSSTDIO=utf-8
您可能需要也可能不需要设置第二个环境变量 PYTHONLEGACYWINDOWSSTDIO
。
或者,这可以在代码中完成(尽管似乎建议通过 env vars 来完成):
sys.stdin.reconfigure(encoding='utf-8')
sys.stdout.reconfigure(encoding='utf-8')
另外:重现这个错误有点痛苦,所以也把它留在这里,以防您需要在您的机器上重现它:
set PYTHONIOENCODING=windows-1252
set PYTHONLEGACYWINDOWSSTDIO=windows-1252
sys.stdin.reconfigure
在 Python 3.9.0 上无效,它会抛出 AttributeError: 'StdInputFile' object has no attribute 'reconfigure'
sys.stdin.reconfigure(encoding='utf-8') sys.stdout.reconfigure(encoding='utf-8')
在保存 get 请求的响应时,在窗口 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)
当我使用 open 命令添加 encoding="utf-8" 时,它以正确的响应保存了文件
with open ('NiftyList.txt', 'w', encoding="utf-8") as f:
f.write(resp.text)
即使我在尝试打印、读/写或打开它时也遇到了同样的编码问题。正如上面提到的其他人所提到的,如果您尝试打印它,添加 .encoding="utf-8" 会有所帮助。
汤.编码(“utf-8”)
如果您尝试打开抓取的数据并将其写入文件,请使用 (......,encoding="utf-8") 打开文件
使用 open(filename_csv , 'w', newline='',encoding="utf-8") 作为 csv_file:
对于仍然收到此错误的用户,将 encode("utf-8")
添加到 soup
也将解决此问题。
soup = BeautifulSoup(html_doc, 'html.parser').encode("utf-8")
print(soup)
soup
不再是 BeautifulSoup
对象,因此无法对其进行操作或搜索
这个问题有多个方面。基本问题是您要输出到哪个字符集。您可能还必须弄清楚输入字符集。
打印(使用 print
或 write
)到具有显式 encoding="..."
的文件会将 Python 的内部 Unicode 表示转换为该编码。如果输出包含该编码不支持的字符,您将获得 UnicodeEncodeError
。例如,您不能在编码为 "cp1252"
的文件中写入俄语、中文、印度语、希伯来语、阿拉伯语、表情符号或......除了一组 200 多个受限的西方字符之外的任何内容,因为这个受限的 8 位字符set 无法表示这些字符。
基本上任何 8 位字符集都会出现同样的问题,包括几乎所有的旧版 Windows 代码页(437、850、1250、1251 等),尽管其中一些支持一些额外的脚本,而不是英语(例如,1251 支持西里尔文,因此您可以编写俄语、乌克兰语、塞尔维亚语、保加利亚语等)。 8 位编码最多只有 256 个字符代码,无法表示不在其中的字符。
也许现在是阅读 Joel Spolsky 的The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)的好时机
在终端无法打印 Unicode 的平台上(现在只有 Windows,但如果您喜欢逆向计算,这个问题在上个千年的其他平台上也很普遍)尝试 print
Unicode 字符串也可以产生这个错误,或输出 mojibake。如果您看到类似 Héllö
而不是 Héllö
的内容,这就是您的问题。
简而言之,那么,您需要知道:
您抓取的页面的字符集是什么,或者您收到的数据是什么?是否正确刮擦?发起者是否正确识别了其编码,或者您是否能够以其他方式获得此信息(或猜测)?一些网站错误地声明了与页面实际包含的字符集不同的字符集,一些网站错误地配置了 Web 服务器和后端数据库之间的连接。有关一些解决方案的更详细示例,请参见例如使用正确的字符编码(python 请求 + beautifulsoup)刮擦。
你想写什么字符集?如果打印到屏幕上,您的终端配置是否正确,您的 Python 解释器是否配置相同?或许也可以看看 How to display utf-8 in windows console
如果您在这里,这些问题之一的答案可能不是“UTF-8”。这也越来越成为网页的流行编码,尽管以前的标准是 ISO-8859-1(又名 Latin-1)和最近的 Windows 代码页 1252。
展望未来,除了一些边缘用例之外,您基本上希望所有文本数据都是 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ö
。
如果字符数据的编码未知,则没有简单的方法可以自动建立它。如果您知道文本应该代表什么,您也许可以推断出来,但这通常是一个手动过程,涉及一些猜测。 (像 chardet
和 ftfy
这样的自动工具可以提供帮助,但有时它们也会出错。)
要确定您正在查看的编码,如果您可以识别字符中未正确显示的各个字节,这将很有帮助。例如,如果您正在查看 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 工具需要它来正确识别编码。
这里的几个较早的答案建议盲目地应用一些编码,但希望这可以帮助您了解这通常不是正确的方法,以及如何确定要使用哪种编码。
如果您使用的是 windows 尝试传递 encoding='latin1', encoding='iso-8859-1' 或 encoding='cp1252' 示例:
csv_data = pd.read_csv(csvpath,encoding='iso-8859-1')
print(print(soup.encode('iso-8859-1')))
io
包装器对于 Python 2 是必需的,其中常规open
函数不允许您指定encoding
。