urllib2、Google App Engine 与 Unicode 问题

2 投票
1 回答
691 浏览
提问于 2025-04-16 07:40

大家好,我正在学习谷歌应用引擎,所以遇到了一些问题...

我现在的困境是这样的。我有一个数据库,

class Website(db.Model):
    web_address = db.StringProperty()
    company_name = db.StringProperty()
    content = db.TextProperty()
    div_section = db.StringProperty()
    local_links = db.StringProperty()
    absolute_links = db.BooleanProperty()
    date_updated = db.DateTimeProperty()

我遇到的问题是关于内容属性的。

我使用 db.TextProperty() 是因为我需要存储网页的内容,而这些内容超过了500个字节。

我遇到的问题是 urllib2.readlines() 返回的是 Unicode 格式。当我把它放进 TextProperty() 时,它却转换成了 ASCII 格式。有些字符的编码值大于128,这就导致了一个 UnicodeDecodeError 的错误。

有没有简单的方法可以绕过这个问题?大部分情况下,我对那些字符并不在意...

我的错误信息是:

追踪记录(最近的调用在最前面):
文件 "/base/python_runtime/python_lib/versions/1/google/appengine/ext/webapp/init.py",第 511 行,在 call 中 handler.get(*groups) 文件 "/base/data/home/apps/game-job-finder/1.346504560470727679/main.py",第 61 行,在 get 中 x.content = website_data_joined 文件 "/base/python_runtime/python_lib/versions/1/google/appengine/ext/db/init.py",第 542 行,在 set 中 value = self.validate(value) 文件 "/base/python_runtime/python_lib/versions/1/google/appengine/ext/db/init.py",第 2407 行,在 validate 中 value = self.data_type(value) 文件 "/base/python_runtime/python_lib/versions/1/google/appengine/api/datastore_types.py",第 1006 行,在 new 中 return super(Text, cls).new(cls, arg, encoding) UnicodeDecodeError: 'ascii' 编解码器无法解码字节 0xc2 在位置 2124:序号不在范围内(128)

1 个回答

1

看起来从 readlines 返回的内容不是 Unicode 字符串,而是字节字符串(也就是 str 类型的实例,可能包含非 ASCII 字符)。这些字节是从 HTTP 响应体中收到的原始数据,具体表示什么字符串取决于使用的编码方式。在把它们当作文本使用之前,需要先进行“解码”(字节和字符是不同的)。

如果编码是 UTF-8,这段代码应该能正常工作:

f = urllib2.open('http://www.google.com')
website = Website()
website.content = db.Text(f.read(), encoding = 'utf-8-sig')    # 'sig' deals with BOM if present

需要注意的是,实际的编码方式在不同的网站上是不同的(有时候甚至同一个网站的不同页面也会不一样)。使用的编码应该在 HTTP 响应的 Content-Type 头中包含(可以参考 这个问题了解如何获取),但如果没有,可能会在 HTML 的头部的 meta 标签中找到(这种情况下提取起来就复杂得多):

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

还有一些网站根本不指定编码,或者指定了错误的编码。

如果你真的只关心 ASCII 字符,可以直接忽略其他字符,这样就可以了:

f = urllib2.open('http://www.google.com')
website = Website()
content = unicode(f.read(), errors = 'ignore')    # Ignore characters that cause errors
website.content = db.Text(content)    # Don't need to specify an encoding since content is already a unicode string

撰写回答