python3.6 字符编码问题

2018-05-11 00:50:42 +08:00
 Meli55a

准备写个爬虫,监控一个网页,如果有更新就将更新的内容采集并邮件通知我,结果开始就卡住了。。。

问题:月份提取出来中文显示为乱码,如:2018å¹´05期

我看了网页源码,有声明 charset=utf-8, 并且我用的是 python3.6,所以比较纳闷为何为出现乱码,在 Chrome 控制台下测试 xpath 时是没毛病的:

然后各种百度、谷歌的找,大部说到是编码问题,一篇篇的关于编码的文章看得脑壳麻,然后按所说的方法都不能解决,特发贴看有遇到同样问题的朋友没

尝试过的方法:

PS: 打印 requests.get()text 所有中文都显示为乱码

下面为测试的 demo:

import requests
'''
    import re
    import sys
    import io

    sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf8')
'''
from lxml import html

url = 'http://www.wh-ccic.com.cn/node_13613.htm'

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36'
}
base_url = 'http://www.wh-ccic.com.cn'
page = requests.get(url, headers=headers)
tree = html.fromstring(page.text)
print(page.text)
all_a = tree.xpath('.//*[@class="STYLE13"]/a')
for a in all_a:
    # print(a.attrs['href'])
    # href = a.attrs['href']
    # title = a.text.replace(u'\xe5', u' ')
    href = a.attrib['href']
    title = a.text
    if '\\u' in title:
        title = title.encode('utf-8').decode('unicode_escape')
        print(title)
3456 次点击
所在节点    Python
11 条回复
lifeishort
2018-05-11 01:12:22 +08:00
page = requests 后面加一行 page.encoding='utf-8'
fushall
2018-05-11 01:18:39 +08:00
楼上说的对
Sylv
2018-05-11 01:41:14 +08:00
requests 是通过 response 的头部( headers )来检测编码的。
虽然这页面在源码里声明了 charset,但是没在 'Content-Type' header 里声明 charset:
Content-Type: text/html

所以 requests 就使用了默认的编码 'ISO-8859-1':
>>> page.encoding
'ISO-8859-1'

于是就出现乱码问题了。

解决方法是手动设置 requests 解码这个页面使用的编码:
>>> page.encoding = 'utf-8'
>>> tree = html.fromstring(page.text)
>>> title = tree.xpath('.//*[@class="STYLE13"]/a')[0].text
>>> title
'2018 年 05 期'
Sylv
2018-05-11 01:44:51 +08:00
放上 requests 文档中关于编码的说明:

Encodings

When you receive a response, Requests makes a guess at the encoding to use for decoding the response when you access the Response.text attribute. Requests will first check for an encoding in the HTTP header, and if none is present, will use chardet to attempt to guess the encoding.

The only time Requests will not do this is if no explicit charset is present in the HTTP headers and the Content-Type header contains text. In this situation, RFC 2616 specifies that the default charset must be ISO-8859-1. Requests follows the specification in this case. If you require a different encoding, you can manually set the Response.encoding property, or use the raw Response.content.

http://docs.python-requests.org/en/latest/user/advanced/#encodings
sjmcefc2
2018-05-11 02:44:16 +08:00
也是遇到编码问题,至今没搞懂 2 和 3 的差别。只是觉得 2 更好用
Hopetree
2018-05-11 09:40:15 +08:00
1 楼正解
janxin
2018-05-11 09:43:59 +08:00
@sjmcefc2 当然是 2 不好用...不过 lz 的问题主要是 requests 非得按照标准来,不处理非标准情况的一些 corner case (当然基本上都是半瓶水码农的锅)。 https://github.com/requests/requests/issues/1737
yonoho
2018-05-11 10:43:05 +08:00
很多网站都有这个问题,一般国内默认 utf-8 就好。实在拿不准编码的时候也可以通过 page.content.decode($codec) 一个个试
Meli55a
2018-05-11 10:56:05 +08:00
@Sylv 因为获取回来的 text 中的中文已经是乱码,所以也怀疑是 requests 那里有问题,可是不知如何解决,又找不到详细的 api 说明,还尝试过在 get 方法里面加 encoding 参数,结果是没有那个参数,却没想到变通一下多写一句。。。
sjmcefc2
2018-05-11 12:46:53 +08:00
@janxin 2 貌似读进来的都是编码格式的,而 3 貌似是默认 unicode,调用 chardet 就会出错。我的问题更奇葩,就是各种 utf-8,gb2312,gbk 混编,一行内各种编码混杂。。。。始终没有很完美的解决方法
lifeishort
2018-05-11 20:34:17 +08:00
@sjmcefc2 不知道编码的时候试试
resp.encoding=resp.apparent_encoding

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/453930

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX