V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
lovebeyondalways
V2EX  ›  Python

求助:被 python 的编码搞疯了

  •  
  •   lovebeyondalways ·
    piaokorg · 2016-06-04 11:15:44 +08:00 · 9482 次点击
    这是一个创建于 2885 天前的主题,其中的信息可能已经有所发展或是发生改变。

    小弟用的是 python3.5 ,听说 python3 解决了编码问题
    然而
    import urllib.request
    html = urllib.request.urlopen('http://www.baidu.com').read().decode('utf-8')
    print(html)

    结果:
    Traceback (most recent call last):
    File ".\Desktop\work\wearther.py", line 3, in <module>
    print(html)
    UnicodeEncodeError: 'gbk' codec can't encode character '\xbb' in position 25395: illegal multibyte sequence

    这样也不行.decode('utf-8').encode('utf-8')
    所以新手求助啊

    45 条回复    2016-06-07 11:36:45 +08:00
    276562578
        1
    276562578  
       2016-06-04 11:19:46 +08:00
    先看看是什么格式的编码,用 chardet 库,然后再 de 和 en
    GPU
        2
    GPU  
       2016-06-04 11:24:33 +08:00
    不是应该用 requests 吗?

    腰不酸腿不疼
    SuperMild
        3
    SuperMild  
       2016-06-04 11:24:34 +08:00
    可能是 Windows 的坑
    janxin
        4
    janxin  
       2016-06-04 11:28:59 +08:00
    试了一下没有问题啊,你这是 Windows 的坑吧
    a412739861
        5
    a412739861  
       2016-06-04 11:29:56 +08:00
    我用 requests 似乎需要设置这个的,直接能够打开 gbk 的。
    只是在 post 数据的时候,要 encode 成对应的编码,这个地方要自己写。
    lovebeyondalways
        6
    lovebeyondalways  
    OP
       2016-06-04 11:29:59 +08:00
    @janxin 我靠 windows 这坑怎么跳过
    Sylv
        7
    Sylv  
       2016-06-04 11:29:59 +08:00 via iPhone   ❤️ 1
    Python 3 的字符串已经是 unicode 了,你为什么还要 decode ?
    基础知识:
    unicode.encode(encoding) -> bytes
    bytes.decode(encoding) -> unicode
    unicode.decode(encoding) -> unicode.encode(defaultencoding).decode(encoding) -> unicode

    Python 3 是解决了部分 Python 2 的编码坑,但并不代表不再需要掌握基础的编码知识了。
    uniquecolesmith
        8
    uniquecolesmith  
       2016-06-04 11:42:19 +08:00   ❤️ 3
    你对编码的理解反了, unicode 是字符集,是规范,而 utf-8 是 unicode 的一种实现。或者你可以理解为 unicode 是非可视编码,而 utf-8 是可视编码,所以应该是个 encode('utf-8')才可行
    annielong
        9
    annielong  
       2016-06-04 11:43:00 +08:00
    大坑, windows+中文,回回都要被编码坑一下,
    uniquecolesmith
        10
    uniquecolesmith  
       2016-06-04 11:47:42 +08:00   ❤️ 1
    补充 没记错的话, windows 下应该 urllib.request.urlopen('http://www.baidu.com').read().encode('cp936')或者其他
    xiandao7997
        11
    xiandao7997  
       2016-06-04 11:51:04 +08:00
    @lovebeyondalways 在 iV2 结果基本上就是劝你换 mac :)
    以前也遇到这个坑,跟别人回复的一样,数据获取到了用 chardet 先检测一下编码,然后再 decode/encode, win 命令行里输出的话 utf8 貌似是不行的,只可以用 unicode/gb2312/gbk/cp936 ,记不清了,你可以再试试~
    congeec
        12
    congeec  
       2016-06-04 12:02:28 +08:00
    不是 Python 坑你,是 Terminal 坑你。你的代码我在 OS X 下执行就没问题。 Windows ,如果我没记错的话,用 UCS-2/GBK 处理中文。你的 Terminal (应该是 cmd.exe 吧)有没有用 UTF-8 ?
    Delbert
        13
    Delbert  
       2016-06-04 12:09:35 +08:00 via Android
    win 的 cmd 是 cp936 , unicode 是 65001(印象中是这个)
    YuJianrong
        14
    YuJianrong  
       2016-06-04 12:10:42 +08:00 via iPad   ❤️ 3
    这个原因很容易理解吧?主要有两点
    1. GBK 没有完全覆盖 unicode ,有些 unicode 字符无法编码成 GBK
    2. windows 版本的 print 在中文 windows 环境下输出需要编译成环境编码也就是 cp936 , python 视 cp936 等同 GBK (这也没错)

    所以其实是 print 的锅,你不如把字符串编码成 utf8 存文件来看好了,不要 print 。
    21grams
        15
    21grams  
       2016-06-04 12:15:05 +08:00
    我用的还是 2.7 , 更痛苦,尤其在 windows 下,简直噩梦。
    cosven
        16
    cosven  
       2016-06-04 12:44:03 +08:00   ❤️ 1
    @YuJianrong 正解

    看它报错的位置嘛,说的是第三行,而不是第二行的 decode 有错,而楼上许多人都在分析 decode('utf-8') 这句有错。显然没有抓住问题关键。

    windows cmd 下 print 会把字符串转换成 gbk 编码来输出,所以才会有 LZ 现在遇到的问题。

    >>> html.encode('gbk') # 说明 html 这个字符串中有些字符不能编码成 gbk
    UnicodeEncodeError: 'gbk' codec can't encode character '\xbb' in position 25395: illegal multibyte sequence

    *****所以, LZ 的问题,并不是单纯的不能输出中文的问题*****

    解决办法
    1. 如 YuJianrong 所说:把它输出到文件是一种办法
    2. 参考这篇博客,貌似可以输出到 cmd: http://blog.csdn.net/jim7424994/article/details/22675759

    ---------题外话(关于 cmd python3 输出中文)-------------------
    参考 http://www.crifan.com/python_3_x_auto_handle_string_encode_and_decode_to_and_from_unicode_then_output_to_cmd/ 这篇博客,对 windows 下 python3 输出中文的一些情况作了测试。

    ----------------------------------------------------------------------------

    @Sylv urlopen('http://www.baidu.com').read() 之后的对象是 bytes ,不是字符串
    @uniquecolesmith bytes 对象应该 decode 成 utf-8 ,而不是 encode
    walleL
        17
    walleL  
       2016-06-04 13:25:02 +08:00
    做了一些测试,我来整理一下吧(我用的 python2.7)

    1. content = urllib.request.urlopen('http://www.baidu.com').read() # 得到 bytes
    2. text = content.decode('utf8') # 得到 unicode(这里已确定 content 为 utf8 编码)
    3. print(text) # print 时 python 会根据当前 sys.stdout 的编码对 text 进行 encode, win 下 stdout 的编码是 gbk ,而有些 unicode 无法编码为 gbk ,所以报错

    解决方案:
    1. @cosven 的回复中提到的博客里的方法:改 sys.stdout 的编码
    2. 先 encode 为 gbk ,并指定 errors='replace' (当遇到不可编码字符时使用 ? 替换), 然后 print:
    print(text.encode('gbk', errors='replace')) #不推荐,无法解码的字符可能就成 ? 了
    3. 结合 1,2: print(text.encode('gp18030'))
    lovebeyondalways
        18
    lovebeyondalways  
    OP
       2016-06-04 13:25:47 +08:00
    @cosven
    @YuJianrong 感谢 确实是 print 的问题
    cosven
        19
    cosven  
       2016-06-04 13:27:21 +08:00
    事后又仔细阅读了 http://blog.csdn.net/jim7424994/article/details/22675759 这篇博文,它使用 GB18030 编码可以成功输出。

    所以我猜(手上并没有 windows ): print(html.encode('gb18030')) 应该是可以正常输出的

    参考: gbk 编码都多种: GB2312, GB18030, GBK https://www.zhihu.com/question/19677619
    daimoon
        20
    daimoon  
       2016-06-04 14:11:28 +08:00
    简单的办法,把 python 安装目录中的 site.py 里面的 del sys.setdefaultencoding ,替换为 sys.setdefaultencoding("utf-8").
    以后就没问题了。
    hard2reg
        21
    hard2reg  
       2016-06-04 14:34:13 +08:00
    请用 requests
    hard2reg
        22
    hard2reg  
       2016-06-04 14:37:43 +08:00
    你抓 QQ 空间更恶心,有些 emoji 表情也会导致错误。。。
    ayaseangle
        23
    ayaseangle  
       2016-06-04 14:40:04 +08:00
    这是 cmd 的坑。。。
    dofine
        24
    dofine  
       2016-06-04 15:09:12 +08:00
    print 和 cmd 都很坑~~
    vinceguo
        25
    vinceguo  
       2016-06-04 15:33:47 +08:00 via Android
    别改 defaultencoding 。
    here you go: bit.ly/unipain
    YUX
        26
    YUX  
       2016-06-04 16:00:09 +08:00
    import sys
    import io
    sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')

    在 python3 前面加上这三行就没有编码问题了
    ioven
        27
    ioven  
       2016-06-04 18:13:46 +08:00
    win 的坑,而非 py 坑
    个人解决方法,使用 conemu[https://conemu.github.io],开启 unicode 支持,运行 lz 代码无压力
    weizhixiang
        29
    weizhixiang  
       2016-06-04 21:25:31 +08:00 via Android
    win 的坑,首行加入#ciding=utf-8
    weizhixiang
        30
    weizhixiang  
       2016-06-04 21:26:06 +08:00 via Android
    @weizhixiang coding
    noe132
        31
    noe132  
       2016-06-05 00:39:33 +08:00
    最新版本 Sublime 的 built in 的 python 的 build system 是这样写的
    {
    "shell_cmd": "python -u \"$file\"",
    "file_regex": "^[ ]*File \"(...*?)\", line ([0-9]*)",
    "selector": "source.python",

    "env": {"PYTHONIOENCODING": "utf-8"},

    "variants":
    [
    {
    "name": "Syntax Check",
    "shell_cmd": "python -m py_compile \"${file}\"",
    }
    ]
    }


    其中有个
    "env": {"PYTHONIOENCODING": "utf-8"},
    添加一个这个环境变量
    好像这样就不会出现 unicode 错误了
    youtoshell
        32
    youtoshell  
       2016-06-05 01:24:12 +08:00 via Android   ❤️ 1
    reload(sys)
    sys.setdefaultencoding('utf-8')
    Ciruelas
        33
    Ciruelas  
       2016-06-05 05:03:07 +08:00 via iPhone
    不知道你解决这个问题了没有,我前两天刚好碰到类似的问题。报这个错是因为控制台使用的是 gbk 编码,要么把控制台改成 utf8 编码,要么把输出内容 decode 以后再 encode 成 gbk
    binux
        34
    binux  
       2016-06-05 05:18:49 +08:00   ❤️ 2
    python 编码其实并不是坑, python2 也不是,只是觉得坑的人不理解编码是什么东西。 encode , decode 乱用,没有依据地胡乱指定编码。
    9hills
        35
    9hills  
       2016-06-05 08:35:35 +08:00
    同意 ls ,反对 reload(sys)

    Python 的编码并不难理解,你只要理解 Unicode , GBK , UTF-8 , encode , decode 的含义即可。如果你使用 Windows ,需要知道 windows 的代码页是什么, CP936 是啥
    lovebeyondalways
        36
    lovebeyondalways  
    OP
       2016-06-05 08:58:23 +08:00 via Android
    @9hills 我靠…一大早又有那么多 v 友帮忙,非常感谢,我把 cmd 改成 utf-8 可以运行,现在在补充 Unicode 知识
    kysida
        37
    kysida  
       2016-06-05 10:29:23 +08:00
    一般这种问题是编码问题,这类问题可以直接尝试着使用 utf-8 , unicode 确实很重要
    imn1
        38
    imn1  
       2016-06-05 10:33:27 +08:00
    看上去像是 win
    win 首先要明白一个问题: cmd 默认编码不是 utf-8 ,无论怎么改只要 py 和 cmd 编码不同,输出就一定会出错
    wwqgtxx
        39
    wwqgtxx  
       2016-06-05 10:58:33 +08:00
    win 下这样输出也能搞定所有问题
    print (((str(input))).encode('gbk', 'ignore').decode('gbk') )
    knarfeh
        40
    knarfeh  
       2016-06-05 14:45:35 +08:00
    授人以鱼不如授人以渔:
    &feature=youtu.be
    est
        41
    est  
       2016-06-05 15:02:29 +08:00   ❤️ 1
    py 没有编码问题。是各种环境自己把编码问题搞乱了。
    Arnie97
        42
    Arnie97  
       2016-06-06 10:00:07 +08:00 via Android
    @weizhixiang 根本不对,这句话是指定 py2 源码文件的编码,对于 py3 是废话,因为 py3 要求源码必须是 utf8 。
    dreamtrail
        43
    dreamtrail  
       2016-06-06 10:19:45 +08:00
    python 的编码很简单了,你要碰到 perl 的,那是真的会疯
    brucedone
        44
    brucedone  
       2016-06-06 12:41:48 +08:00
    很多人刚开始学 py2 的时候,一定会被编码搞的很疯,但凡肯花点时间了解编码和解码原理的话,都可以很轻松走进 python 的大门
    kaneg
        45
    kaneg  
       2016-06-07 11:36:45 +08:00
    编码问题不是单靠语言就能解决的, Java 设计之初就支持 unicode , 但是在 Java 中处理中文的坑,相信很多人肯定都踩过。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   954 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 104ms · UTC 20:12 · PVG 04:12 · LAX 13:12 · JFK 16:12
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.