2

Web ページを取得して HTML ファイルを Web ブラウザに表示する (プロキシのように動作する) 簡単な Python CGI スクリプトを作成しています。スクリプトは次のとおりです。

#!/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)

このスクリプトは、コマンド ラインから実行すると問題なく動作しますが、Web ブラウザーで表示すると、空白のページが表示されます。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で使用すると、エンコーディングのないstdoutに出力されることになります。したがって、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"decode メソッドに渡してみてください。

于 2011-01-05T08:14:02.340 に答える
0

内部と格闘するよりも、Web サーバー (1) で CGI 環境変数(2) を にsys.stdout設定する方がはるかに簡単です。PYTHONIOENCODINGUTF8

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 に答える