Python3使用Requests抓取网页乱码问题
博客专区 > amita 的博客 > 博客详情
Python3使用Requests抓取网页乱码问题
amita 发表于9个月前
Python3使用Requests抓取网页乱码问题
  • 发表于 9个月前
  • 阅读 101
  • 收藏 0
  • 点赞 0
  • 评论 0

新睿云服务器60天免费使用,快来体验!>>>   

1. 问题1

import requests
r = requests.get(url)
print r.text

结果乱码!

分析

with open('a.html', 'wb') as f:
    f.write(r.content)

用编辑器打开一看,非文本。用命令 file a.html 一看,识别为 gzip 格式。原来返回数据经过了 gzip 压缩。
难道要自己判断格式并解压缩?
搜了下,发现 requests 支持 gzip 自动解压,这里为何不行?难道网站返回的编码有误?

print(response.headers['content-encoding'])

返回的确实是“gzip”,怎么没有自动解压?
经过坑die的探索,终于发现response.headers['content-encoding']的值其实是“gzip ”,右边多了几个空格!导致无法识别。
这个锅谁来背?request 库还是网站??

解决方案

1. Request header 里移除 ”Accept-Encoding”:”gzip, deflate”

这样能直接得到明文数据,缺点:流量会增加很多,网站不一定支持。

2. 自己动手,解压缩,解码,得到可读文本

这也是本文使用的方案

2. 问题2

print(response.encoding)

发现网页编码是 'ISO-8859-1',这是神马?
《HTTP权威指南》第16章国际化里提到,如果HTTP响应中Content-Type字段没有指定charset,则默认页面是'ISO-8859-1'编码。这处理英文页面当然没有问题,但是中文页面就会有乱码了!

分析

1. print(r.apparent_encoding)  
2. get_encodings_from_content(r.content)
  1. 据说使用了一个叫chardet的用于探测字符集的第三方库,解析会比较慢。没装,结果是 None
  2. 网上很多答案如此,应该是 python2 的,因为 3 里的 r.content 是 bytes 类型,应改为get_encodings_from_content(r.text),前提是 gzip 已经解压了

3. 源码

代码如下, 基于Python 3.5

# 猜测网页编码  
def guess_response_encoding(response):
    if response.encoding == 'ISO-8859-1':
        if response.content[:2] == b"\x1f\x8b":  # gzip header
            content = gzip.decompress(response.content)
            content = str(content, response.encoding)
        else:
            content = response.text
        encoding = get_encodings_from_content(content)
        if encoding: 
            response.encoding = encoding[0]
        elif response.apparent_encoding: 
            response.encoding = response.apparent_encoding
    print("guess encoding: ", response.encoding)
  • 打赏
  • 点赞
  • 收藏
  • 分享
共有 人打赏支持
粉丝 5
博文 10
码字总数 5638
×
amita
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: