【问题标题】:Python unicode behaviour in Google App EngineGoogle App Engine 中的 Python unicode 行为
【发布时间】:2012-03-20 18:50:59
【问题描述】:

我完全被 gae 搞糊涂了。我有一个脚本,它执行一个发布请求(使用来自 Google App Engine api 的 urlfetch)作为响应,我们得到一个 cp1251 编码的 html 页面。

然后我使用 .decode('cp1251') 对其进行解码并使用 lxml 进行解析。

我的代码在我的本地机器上运行良好:

import re
import leaf #simple wrapper for lxml
weekdaysD={u'понедельник':1, u'вторник':2, u'среда':3, u'четверг':4, u'пятница':5, u'суббота':6}
document = leaf.parse(leaf.strip_symbols(leaf.strip_accents(html_in_cp1251.decode('cp1251'))))
table=document.get('table')
trs=table('tr') #leaf syntax
for tr in trs:
    tds=tr.xpath('td')
    for td in tds:
        if td.colspan=='3':
            curweek=re.findall('\w+(?=\-)', td.text)[0]               
            curday=weekdaysD[td.text.split(u',')[0]]

但是当我将它部署到 gae 时,我得到:

curday=weekdaysD[td.text.split(u',')[0]]
KeyError: u'\xd0\xb2\xd1\x82\xd0\xbe\xd1\x80\xd0\xbd\xd0\xb8\xd0\xba'

那里的非 unicode 字符怎么样?为什么本地一切正常? 我已经尝试了在我的代码中放置的所有解码\编码变体 - 没有任何帮助。 我现在被困了几天。

UPD:,如果我在 GAE 上添加到我的脚本:

print type(weekdaysD.keys()[0]), type(td.text.split(u',')[0]) 

它以“unicode”的形式返回。所以,我相信 html 被正确解码。会不会是 GAE 上的 lxml ?

【问题讨论】:

  • 看起来您以某种方式将页面获取为 UTF-8 而不是 CP1251。它可能正在嗅探用户代理,尽管我从未见过网站这样做来确定它使用的编码。
  • 不,使用 .decode('utf-8') 代替:UnicodeDecodeError: 'utf8' codec can't decode byte 0xc1 in position 286: invalid start byte
  • 好吧,如果你得到一个错误的字符串并执行s.encode('latin1').decode('utf-8'),你会得到一个正确的字符串。所以有些东西编码错误 - 它可能是 lxml。
  • 您的文件是否以 PEP 263 源编码标记开头?我猜您的本地安装假定使用 cp1251 编码,而 App Engine 假定使用 ASCII。
  • 源代码本身是 UTF-8 格式,我有:# -- coding: UTF-8 -- set。 AS of s.encode('latin1').decode('utf-8') - 这可能是一种解决方法 - 至少我在那个地方不再遇到同样的错误。但我还有一些 - 会检查我能做什么。

标签: python google-app-engine unicode cp1251


【解决方案1】:

您在错误消息中收到的字符串的类型具有 unicode,但内容实际上是 вторник 的 UTF-8 编码的字节。如果您向我们展示执行 urlfetch 调用的代码,将会很有帮助,因为您展示的代码没有任何问题。

【讨论】:

  • 这里是 urlfetch 代码:def get_schedule_week(self, message, data): result = urlfetch.fetch(url=url, payload=data, method=urlfetch.POST, headers={'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'User-Agent':'Mozilla/5.0 (Windows NT 6.1; rv:11.0) Gecko/20100101 Firefox/11.0'}) if result.status_code == 200: return result.content 返回的响应是问题中描述的 html_in_cp1251
  • 你能帮我一个忙并在 dev_appserver 和生产中的某个地方记录 result.content.__class__ 吗?我很好奇它是否可能是 dev_appserver 中的 str 但生产中的 unicode 。您可能想要记录的另一件事是 repr(result.content) - 在这两种情况下它应该是相同的。但也许那是一个太长的字符串;也许是 repr(result.content[:500]) ?
  • 对不起,我花了这么长时间。这是本地输出(一切正常):result.content.__class__: <type 'str'>repr(result.content): '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\r\n<html xmlns="http://www.w3.org/1999/xhtml">\r\n<head>\r\n\t<meta http-equiv="Content-Type" content="text/html; charset=windows-1251"/>\r\n\t<meta name="keywords" content="\xc1\xc3\xdd\xd3, \xf2\xf0\xe5\xed\xe8\xed\xe3, \xf4\xe0\xea\xf3\xeb\xfc\xf2\xe5\xf2, \xf1\xf2\xf3\xe4\xe5\xed\xf2, \xfd\xea\xee\xed\xee\xec\xe8\xf7\xe5\xf1\xea\xe8\xe9
  • 这里是 App Engine 的一种形式(完全相同):result.content.__class__: <type 'str'>repr(result.content): '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\r\n<html xmlns="http://www.w3.org/1999/xhtml">\r\n<head>\r\n\t<meta http-equiv="Content-Type" content="text/html; charset=windows-1251"/>\r\n\t<meta name="keywords" content="\xc1\xc3\xdd\xd3, \xf2\xf0\xe5\xed\xe8\xed\xe3, \xf4\xe0\xea\xf3\xeb\xfc\xf2\xe5\xf2, \xf1\xf2\xf3\xe4\xe5\xed\xf2, \xfd\xea\xee\xed\xee\xec\xe8\xf7\xe5\xf1\xea\xe8\xe9
  • 那会是lxml的问题吗?我看不出它不起作用的任何其他原因。
【解决方案2】:

好吧,添加 .encode('latin1').decode('utf-8', 'ignore') 的解决方法就成功了。我希望我能解释为什么它会这样。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-03-10
    • 1970-01-01
    • 2011-05-16
    • 1970-01-01
    • 2018-06-23
    • 1970-01-01
    • 2023-04-04
    • 2012-11-17
    相关资源
    最近更新 更多