Python 为什么这段代码不适用于所有URL?

Python 为什么这段代码不适用于所有URL?,python,python-3.x,unicode,urllib,Python,Python 3.x,Unicode,Urllib,我对python非常陌生,正在玩一些代码。实际上,我正在尝试解析html网页,并从解析的文档中提取一些信息: from urllib import request from bs4 import BeautifulSoup #some code here... link = str(input("Enter URL: ")) sock = request.urlopen(link) pageText = sock.read() sock.close() #some code here...

我对python非常陌生,正在玩一些代码。实际上,我正在尝试解析html网页,并从解析的文档中提取一些信息:

from urllib import request
from bs4 import BeautifulSoup

#some code here...

link = str(input("Enter URL: "))
sock = request.urlopen(link)
pageText = sock.read()
sock.close()

#some code here...

file = open("C:/test.txt", 'w')
file.write(pageText.decode("utf-8"))

#some code here...
我在file.write行中发现了这个错误,我在互联网上搜索到的结果仍然没有关于如何修复这个错误的线索

错误:

Traceback (most recent call last):
  File "C:/Users/Monster/PycharmProjects/TestPro_1/Testfile.py", line 16, in <module>
    file.write(pageText.decode("utf-8"))
  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 413334-413340: character maps to <undefined>

我的代码适用于一些网站,如www.google.com或www.flipkart.com,并给出了一些URL(如www.facebook.com和www.youtube.com)的错误。我认为它不适用于www.facebook.com和youtube.com的一个可能原因是,它们是用PHP或其他语言开发的,而不是HTML网页。这是否正确?

问题是,您试图使用cp1252编码写入文本文件,但您的数据包含cp1252中不存在的字符

在Python中,该函数对文本文件采用可选的编码参数。正如文档所说,如果您没有指定任何内容:

无论locale.getpreferredencoding返回什么,默认编码都依赖于平台

在Windows上,该函数返回的首选编码将是您为系统设置的默认编码。在美国版本的Windows上,如果未更改设置,则预配置的默认值为代码页1252,这是Microsoft对IBM对拉丁语-1的变体。它只能处理256个不同的字符,与Unicode中的前256个字符几乎相同,但不完全相同。如果您有任何其他字符,您将得到一个错误

这在某些页面上有效,但在其他页面上无效的原因是,某些页面除了适合每个字符集的普通英文字符外,没有其他字符

如果确实要保存UTF-8文本文件,则必须明确执行以下操作:

f = open('C:/test.txt', 'w', encoding='utf-8')
f.write(pageText.decode('utf-8'))
如果您想保存cp1252文本文件,或者不管您的系统默认编码是什么,如果有人在Mac上运行您的脚本,或者在日文Windows框上运行基于Shift JIS的cp932,跳过、替换或转义不适合cp1252的字符,您也可以这样做:

f = open('C:/test.txt', 'w', errors='replace')
f.write(pageText.decode('utf-8'))
当然,如果您想要cp1252,无论系统设置为什么,都可以这样说:

f = open('C:/test.txt', 'w', encoding='cp1252', errors='replace')
f.write(pageText.decode('utf-8'))
如果要保存原始字节而不担心它们是什么,请以二进制模式打开文件,首先不要解码字节:

f = open('C:/test.txt', 'wb')
f.write(pageText)
当然,如果在cp1252或Shift JIS等文本编辑器中打开该文件,它将看起来像mojibake…但这不再是程序的错误:

然而,这里还有一个问题。您假设每个网页都是UTF-8。那不是真的。事实上,HTML5之前的网页在默认情况下是拉丁语-1,但它们可以在标题或元标记中指定不同的编码,或者,对于XHTML,在顶级XML标记中指定不同的编码。特别是,请在Facebook页面上尝试以下操作:

>>> print(sock.getheader('Content-Type'))
'text/html; charset=utf-8'
这就是为什么你知道它是UTF-8


对于HTML5,它是。理想情况下,您会希望使用一个为您提供此功能的库。由于您已经在使用BeautifulSoup,在许多常见情况下,它的Unicode、dammit都可以很好地工作,而且对于HTML5之前的版本也可以很好地工作,但是标准正确的实现更好。

您能举一个真实的例子吗?那个openC:/test.txt显然甚至不会编译。@abarnert真正的例子?问题中提到的所有代码都在编译,没有任何错误,test.txt实际上在我的桌面上。我想代码实际上来自一本名为Dive into python的书/博客。我在使用python 3.4,我也在使用3.4。openC:/test.txt不可能不给您一个语法错误。即使使用file=openC:/test.txt,这仍然不起作用;它会给你一个不支持的操作:不可写,因为你不能在默认的读模式下打开一个文件,然后再写入它。如果这段代码中没有更多的错误,但在真正的代码中没有,我也不会感到惊讶。这就是为什么我们需要真正的代码:a,而不仅仅是一个近似值。@EdwardMckinzie:你可以编辑这个问题,以获得一个真实的例子,更清楚地了解你想要什么,以及到底出了什么问题。这可能会让您获得更好的答案和一些向上投票,而不是向下投票、关闭投票,并尝试回答您可能不需要回答的问题。为了避免给人留下这样的印象,open在Windows上总是使用cp1252,您可以重复几次,使用当前区域设置编码cp1252将文本保存到文件中。名义上,它是redandant,从上下文中应该是清楚的,但在这种情况下它可能是有教育意义的。顺便说一句,我不知道html5的默认字符编码是什么。如果没有明确设置内容类型,@J.F.Sebastian:谢谢。现在怎么样?我还认为值得指出的是,有一些编码是常见的,既不是类似拉丁语的,也不是基于Unicode的,所以我以cp932为例。@J.F.Sebastian:第二种……很好;我将再次编辑。