2

我正在编写一个简单的 Python CGI 脚本,它可以抓取网页并在 Web 浏览器中显示 HTML 文件(充当代理)。这是脚本:

#!/usr/bin/env python3.0

import urllib.request

site = "http://reddit.com/"
site = urllib.request.urlopen(site)
site = site.read()
site = site.decode('utf8')

print("Content-type: text/html\n\n")
print(site)

这个脚本在命令行运行时运行良好,但是当它使用网络浏览器查看它时,它会显示一个空白页面。这是我在 Apache 的 error_log 中得到的错误:

Traceback (most recent call last):
  File "/home/public/projects/proxy/script.cgi", line 11, in <module>
    print(site)
  File "/usr/local/lib/python3.0/io.py", line 1491, in write
    b = encoder.encode(s)
  File "/usr/local/lib/python3.0/encodings/ascii.py", line 22, in encode
    return codecs.ascii_encode(input, self.errors)[0]
UnicodeEncodeError: 'ascii' codec can't encode character '\u2019' in position 33777: ordinal not in range(128)
4

3 回答 3

5

当您在命令行打印它时,您将 Unicode 字符串打印到终端。终端具有编码,因此 Python 会将您的 Unicode 字符串编码为该编码。这将正常工作。

当您在 CGI 中使用它时,您最终会打印到没有编码的标准输出。因此,Python 尝试使用 ASCII 对字符串进行编码。这失败了,因为 ASCII 不包含您尝试打印的所有字符,因此您会收到上述错误。

解决此问题的方法是将您的字符串编码为某种编码(为什么不是 UTF8?),并在标题中说明。

所以是这样的:

sys.stdout.buffer.write(b"Content-type: text/html;encoding=UTF-8\n\n") # Not 100% sure about the spelling.
sys.stdout.buffer.write(site.encode('UTF8'))

在 Python 2 下,这也可以:

print("Content-type: text/html;encoding=UTF-8\n\n") # Not 100% sure about the spelling.
print(site.encode('UTF8'))

但在 Python 3 下,编码数据以字节为单位,因此打印效果不佳。

当然,您会注意到您现在首先从 UTF8 解码,然后重新编码。严格来说,你不需要这样做。但是,如果您想在两者之间修改 HTML,这样做实际上可能是个好主意,并将所有修改保留在 Unicode 中。

于 2011-01-05T08:08:20.963 回答
1

您尝试打开的网站可能不是 UTF-8 编码的。尝试传递"iso-8859-1"给解码方法。

于 2011-01-05T08:14:02.340 回答
0

与其纠结于sys.stdout内部结构,更直接的是让 Web 服务器 (1) 将 CGI 环境变量PYTHONIOENCODING(2) 设置为UTF8.

对于 Apache2,您必须启用加载mod_env.so. 在 Debian 安装中,如果您希望保持结构与所有其他模块加载器和配置相同,则相当于在 中创建符号链接/etc/apache2/mods-enabled/etc/apache2/mods-available/env.load并在其中创建配置/etc/apache2/conf-available/env.conf和符号链接。/etc/apache2/conf-enabled

env_mod.conf我创建的文件的内容是:

<IfModule mod_env.c>
  SetEnv PYTHONIOENCODING UTF8
</IfModule>

在我这样做之前,我的脚本在尝试打印包含 Unicode 字符的字符串时报告错误,然后是错误sys.stdout.encoding,并且正确地将所需的 UTF-8 发送到浏览器。"ANSI ...""UTF8"

(1) http://httpd.apache.org/docs/2.2/howto/cgi.html#env

(2) http://docs.python.org/3.3/library/sys.html#sys.stdin

于 2013-07-23T23:34:54.920 回答