再也不用担心网页编码的坑了!
大家爬取网页的时候,应该都遇到过这种情况
当我打印网页源代码的时候
发现 全部是乱码的
那这个时候应该怎么办呢?
requests是如何判断编码
首先,response.content返回的内容 是二进制内容
response.text 则是根据设置的encoding来解码
# Try charset from content-type
content = None
encoding = self.encoding
if not self.content:
return str('')
# Fallback to auto-detected encoding.
if self.encoding is None:
encoding = self.apparent_encoding
# Decode unicode from given encoding.
try:
content = str(self.content, encoding, errors='replace')
except (LookupError, TypeError):
我们可以看到 ,当encoding为None的时候,
编码是通过chardet.detect来获取的,
def apparent_encoding(self):
"""The apparent encoding, provided by the chardet library."""
return chardet.detect(self.content)['encoding']
那么chardet.detect 又是干嘛的呢?
简单的讲,就是根据给定的字节,来返回他的编码
至于他是如何实现的,欢迎去看源代码。。。
上面说到了当encoding为None的时候,requests是如何设置encoding的
那么encoding 默认编码是啥呢?继续查看源代码
我们在adapters.py 里面找到了~
response.encoding = get_encoding_from_headers(response.headers)
def get_encoding_from_headers(headers):
"""Returns encodings from given HTTP Header Dict.
:param headers: dictionary to extract encoding from.
:rtype: str
"""
content_type = headers.get('content-type')
if not content_type:
return None
content_type, params = cgi.parse_header(content_type)
if 'charset' in params:
return params['charset'].strip("'"")
if 'text' in content_type:
return 'ISO-8859-1'
简单讲就是 如何返回头里面没有content_type,则encoding为None
如果charset在参数里面的话,则使用charset设置的值(看下图,github返回的)
如果text在参数里面的话,则使用ISO-8859-1
然后你打印下 你乱码网页的encoding,发现,还真是ISO-8859-1
你会很奇怪,为啥当content-type为text/html的时候,编码为iso-8859-1呢?
现在常见的编码不是utf8么,requests怎么这么傻*呢...
然后发现是rfc2016的规定。。。
rfc2016的链接在 https://www.ietf.org/rfc/rfc2616.txt
感兴趣的同学可以自行查阅...
最后总结
当返回头没有content_type 的时候,encoding使用chardet.detect 猜测出来的编码(一般都是很准的)
当返回头里面有content_type 的时候,如果有charset=xxx,则encoding的编码为chatset的值。如果只是text/html,则编码为ISO-8859-1
那么当你发现response.text返回乱码的时候,怎么办呢。。。
只要先设置编码为None...
再打印.text就可以了..
response.encoding = None
response.text
本来呢,本篇文章到此结束了。。。但是呢。。。
科普个小知识
有几种方法可以知道网页的编码呢?
- 我们上面讲过的 response.headers中的content_type
- 通过chardet.detect猜测出来(上面讲过的)
- 网页源代码中的 meta(且有charset的值)如下面的,则表示网页编码为gb2312(不过呢,有时候并不是很准,这个是前端瞎xx写的,这时候就可以用chardet.detect来猜测了...)
方法3的代码如何写呢(如下)
def get_encodings_from_content(content):
"""Returns encodings from given content string.
:param content: bytestring to extract encodings from.
"""
warnings.warn((
'In requests 3.0, get_encodings_from_content will be removed. For '
'more information, please see the discussion on issue #2266. (This'
' warning should only appear once.)'),
DeprecationWarning)
charset_re = re.compile(r'<meta.*?charset=["']*(.+?)["'>]', flags=re.I)
pragma_re = re.compile(r'<meta.*?content=["']*;?charset=(.+?)["'>]', flags=re.I)
xml_re = re.compile(r'^<?xml.*?encoding=["']*(.+?)["'>]')
return (charset_re.findall(content) +
pragma_re.findall(content) +
xml_re.findall(content))
你会看到requests3.0版本的时候,这个方法会去掉,这又是为什么呢。。。
截图自己看把,地址在https://github.com/requests/requests/issues/2266
完...
- 机器学习(二)深度学习实战-使用Kera预测人物年龄问题描述引入所需要模块加载数据集创建模型编译模型优化optimize1 使用卷积神经网络optimize2 增加神经网络的层数输出结果结果
- 异步加载的基本逻辑与浏览器抓包一般流程
- 左手用R右手Python系列之——表格数据抓取之道
- XML/HTML/JSON——数据抓取过程中不得不知的几个概念
- R语言网络数据抓取的又一个难题,终于攻破了!
- R语言数据清洗实战——高效list解析方案
- 左手用R右手Python系列——循环中的错误异常规避
- SpringBoot2.x开发案例之整合Quartz任务管理系统
- 给出一组非负整数,重新排序组成最大的数
- [机智的机器在学习] TensorFlow实现Kmeans聚类
- [机智的机器在学习] 利用TensorFlow实现多元线性回归分类器
- [数据结构和算法]《算法导论》动态规划笔记(1)
- [数据结构和算法]《算法导论》动态规划笔记(2)
- [算法与数据结构] 《算法导论》堆排序笔记
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 面向切片编程(AOP)应用的一些实际例子
- 计数计量单位KMGTPEZY【计算机】【天文】
- 不用临时的变量 优雅、高效的交换两个数方法
- SAP offline OData插件的JavaScript代码是如何调用到Android平台的Java代码的
- 一个占据SAP BSP应用占据存储空间的小工具
- 基于Golang的逃逸分析(Language Mechanics On Escape Analysis)
- SAP数据库表DDLOG的设计原理
- SAP UI5框架Component.js里extend函数的实现原理
- 冒泡排序的终极改进优化
- alpine安装sshd/ssh server
- 使用jstack检测Java应用的死锁(deadlock)状态
- 使用xdebug对php做性能分析调优
- 使用SAP Analytics Path Framework通过图表和表格方式展示CDS view数据
- ELK学习笔记之Docker Container exited with code 137
- 用这10个小技巧加速Python编程