【问题标题】:Why is python trying to ASCII encode my unicode string for Mysqldb?为什么 python 试图对 Mysqldb 的 unicode 字符串进行 ASCII 编码?
【发布时间】:2016-10-17 03:19:30
【问题描述】:

是的,又是一个关于 unicode 和 Python 的问题。在你们打开我对 Unicode 的想法之后,我以为我已经阅读了所有内容并采用了良好的编程习惯,但是这个错误又回到了我身上:

'ascii' codec can't encode character u'\xc0' in position 24: ordinal not in range(128)

我在 Python 2.7 中使用了 scrapy,因此来自“外部世界”的内容是使用 xpath 正确解码和处理的网页,正如异常之前来自这些检查的空错误日志所示:

if not isinstance(key, unicode):
    logging.error(u"Key is not unicode: %s" % key)

if not isinstance(value, unicode):
    logging.error(u"value is not unicode: %s" % value)

if not isinstance(item['listingId'], int):
    logging.error(u"item['listingId'] is not an int:%s" % item['listingId'])

但是,当 MySql 事务在下一行发生时:

d = txn.execute("INSERT IGNORE INTO `listingsDetails` VALUE (%s, %s, %s);", (item['listingId'], key, value))

我仍然不时收到此异常。 (1% 的页面) 注意“pipeline.py”第 403 行,它是 MySql INSERT。

2016-10-16 22:22:10 [Listings] ERROR: [Failure instance: Traceback:     <type 'exceptions.UnicodeEncodeError'>: 'ascii' codec can't encode character u'\xc0' in position 24: ordinal not in range(128)
/usr/lib/python2.7/threading.py:801:__bootstrap_inner
/usr/lib/python2.7/threading.py:754:run
/usr/lib/python2.7/dist-packages/twisted/_threads/_threadworker.py:46:work
/usr/lib/python2.7/dist-packages/twisted/_threads/_team.py:190:doWork
--- <exception caught here> ---
/usr/lib/python2.7/dist-packages/twisted/python/threadpool.py:246:inContext
/usr/lib/python2.7/dist-packages/twisted/python/threadpool.py:262:<lambda>
/usr/lib/python2.7/dist-packages/twisted/python/context.py:118:callWithContext
/usr/lib/python2.7/dist-packages/twisted/python/context.py:81:callWithContext
/usr/lib/python2.7/dist-packages/twisted/enterprise/adbapi.py:445:_runInteraction
/home/mrme/git/rep/scrapy_prj/firstproject/firstproject/pipelines.py:403:_do_upsert
/usr/lib/python2.7/dist-packages/MySQLdb/cursors.py:228:execute
/usr/lib/python2.7/dist-packages/MySQLdb/cursors.py:127:_warning_check
/usr/lib/python2.7/logging/__init__.py:1724:_showwarning
/usr/lib/python2.7/warnings.py:50:formatwarning

我已经打开了 MySql 连接:

dbargs = dict(
    host=settings['MYSQL_HOST'],
    db=settings['MYSQL_DBNAME'],
    user=settings['MYSQL_USER'],
    passwd=settings['MYSQL_PASSWD'],
    charset='utf8',
    use_unicode=True
)
dbpool = adbapi.ConnectionPool('MySQLdb', **dbargs)

我还尝试按照 MySql 文档在连接后添加这个:

self.dbpool.runOperation("SET NAMES 'utf8'", )
self.dbpool.runOperation("SET CHARSET 'utf8'",)

并确认我的数据库设置正确:

SHOW VARIABLES WHERE Variable_name LIKE 'character\_set\_%' OR Variable_name;

character_set_client:     utf8mb4
character_set_connection: utf8mb4
character_set_database:   utf8
character_set_filesystem: binary
character_set_results:    utf8mb4
character_set_server:     latin1
character_set_system:     utf8

到底是谁在这里尝试用 Ascii 编码?

欢迎每 2 美分 ;-)

如果有任何帮助,数据库中的所有其他重音字符都可以。只有这个 u'\xc0' = À 有问题。

【问题讨论】:

  • 您在使用from __future__ import unicode_literals 吗?可能是因为查询字符串不是 unicode。
  • 是执行异常还是警告日志记录异常?你能用错误行粘贴整个堆栈跟踪吗?
  • @paul trmbrth 你是对的,这是来自INSERT IGNORE 的关于DUPLICATE ENTRY 的警告记录。抱歉,在我发布我的发现作为答案后,我看到了你的评论。如果您将其发布为答案,我会接受。你知道为什么它会尝试转换回 ASCII 来记录警告吗?
  • 嗯,对不起,不,我不知道为什么。

标签: python-2.7 unicode scrapy mysql-python


【解决方案1】:

如果出现异常,您可以输入以下代码。

varName = ''.join([i if ord(i) < 128 else ' ' for i in strName])

这里,strName 是包含非 ascii 值的字符串

【讨论】:

  • 感谢解决方法,但我需要这些字符,看起来这只会用空格替换有问题的字符。我需要知道谁在 python 和 mysqldb 之间丢球。
  • 我认为是 Python,因为您可以将 Insert Query 存储在变量中并将此变量传递给执行方法。
【解决方案2】:

假设dbpool 是您的连接变量,请尝试以下操作(过大,但看看它是否有效):

dbpool = adbapi.ConnectionPool('MySQLdb', **dbargs)
dbpool.set_character_set('utf8mb4')
dbpool.runOperation('SET NAMES utf8mb4;')
dbpool.runOperation('SET CHARACTER SET utf8mb4;')
dbpool.runOperation('SET character_set_connection=utf8mb4;')

如果这没有帮助,请参阅下文。


旁注

如果你运行:

SHOW VARIABLES WHERE Variable_name LIKE 'character\_set\_%' OR Variable_name LIKE 'collation%';

除了 OP 中的行之外,您还应该获得以下行:

| collation_connection     | utf8mb4_unicode_ci |
| collation_database       | utf8mb4_unicode_ci |
| collation_server         | utf8mb4_unicode_ci |

如果没有,请快速阅读我对问题 Manipulating utf8mb4 data from MySQL with PHP 的回答,然后编辑您的 MySQL 配置。

【讨论】:

  • 试了一下,从 dbpool 对象中得到了一个no function named set_character_set。删除它并得到相同的结果。我终于找到了我的答案并发布了它....
【解决方案3】:

感谢大家的大力投入,但我终于弄清楚了异常的来源。

Python 尝试将 DUPLICATE WARNING 从 Mysql 转换回 ASCII 以进行日志记录,并引发异常尝试将此警告(包含 unicode)输出回标准输出。

INSERT IGNORE 替换为INSERT... ON DUPLICATE UPDATE,此异常将永远消失。

任何人都可以帮助我找到为什么 python 不能像我的 ubuntu 机器上的其他所有内容一样将 utf8 中的这个警告打印回标准输出?

【讨论】:

    猜你喜欢
    • 2023-03-27
    • 2014-04-16
    • 2011-02-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-03
    • 2015-12-17
    相关资源
    最近更新 更多