被python爬虫的数据类型和编码坑了无数次!

一、前言

Python爬虫新手不可逃避又很烦人的事:响应数据的类型和编码问题!

  • 数据类型又出错了?

  • 数据编码又不对了?

  • 怎么全都是乱码?

被python爬虫的数据类型和编码坑了无数次!

我也不例外,已经被python爬虫的数据类型和编码坑了无数次!但每次都是得过且过,解决完又不总结原因,下次遇到还得调试。这一次决定痛定思痛,一锅端了这个烦人的知识盲区!

想学会如何正确处理响应数据的不同类型和编码,得先摸清楚响应数据的类型和编码的原理。

二、响应数据的类型

在讲数据类型之前,先举个例子:你在网上购物,商品在商家发货前,商品会放在包装盒里,包装盒会放在包装袋里,包装袋会放在快递盒里。经过快递员送达到你手上后,你会先拆快递盒拿出包装袋,再拆包装袋拿出包装盒,最后拆包装盒拿出商品。

被python爬虫的数据类型和编码坑了无数次!

其实数据在网络中传输,就好像你网购的商品一样。在服务器发出之前,先将数据进行JSON格式编码,然后进行字符编码,最后进行压缩。终端接收到数据后,先进行解压,然后进行字符解码,最后进行JSON格式解码。

被python爬虫的数据类型和编码坑了无数次!

终端接收到的数据就是原始流式数据,原始流式数据被解压后就是字节类型数据,字节类型数据再被字符解码后则是文本类型数据,文本类型数据最后被JSON格式解码得到JSON格式数据。

这所说的原始流式、字节类型、文本类型和JSON格式就是响应数据的4种类型。

三、响应数据的编码

这里说的数据编码指的是字符编码,编码问题主要出现在获取文本类型数据过程中,编码的原理之前也已经写过,这里就不重复了,大家可以参考以前的两篇文章:

四、Requests获取不同类型和编码的数据

(一)获取原始流式的响应数据

先在请求中设置参数stream=Ture,然后通过访问Response.raw即可获取到原始的响应数据。代码如下:

>>> r = requests.get('https://api.github.com/events', stream=True)
>>> r.raw
<urllib3.response.HTTPResponse object at 0x101194810>
>>> r.raw.read(10)
b'x1fx8bx08x00x00x00x00x00x00x03'

(二)获取字节类型的响应数据

通过Response.content可以获取到字节类型的响应数据,并且会自动解压gzip、deflate、br格式的压缩数据(解压br格式的数据需要先安装像brotli或者brotlicffi库)。代码如下:

>>> r.content
b'[{"repository":{"open_issues":0,"url":"https://github.com/...

你可以将字节类型的响应数据保存成一张图片,实现图片下载,代码如下:

>>> from PIL import Image
>>> from io import BytesIO
>>> i = Image.open(BytesIO(r.content))

你可以将字节类型的响应数据保存成一个文件,实现流媒体下载,代码如下:

with open(filename, 'wb') as fd:
for chunk in r.iter_content(chunk_size=128):
fd.write(chunk)

Response.iter_content是对Response.content的遍历,其中chunk_size可以自由调整为一个适合的数字。

参考案例:一个妹子套图python爬虫(完整源码)

(三)获取文本类型的响应数据

通过Response.text可以获取到文本类型(字符串类型)的响应数据,并且会自动解压(gzip、deflate、br格式)和解码(ASCII、GBK、UTF-8编码)数据。代码如下:

>>> import requests
>>> r = requests.get('https://api.github.com/events')
>>> r.text
'[{"repository":{"open_issues":0,"url":"https://github.com/...

Requests库是根据HTTP协议头来判断响应数据的编码,然后在你访问Response.text时进行解码。因此,你可以通过Response.encoding查看并改变编码。

>>> r.encoding
'utf-8'
>>> r.encoding = 'ISO-8859-1'

例如,HTML和XML的编码可以在数据主体中确定,你可以先使用Response.content查找正确的编码,然后再通过Response.encoding进行设置。

参考案例:Python爬虫|4399最新小游戏

(四)获取JSON格式的响应数据

Requests库有内置的JSON解码器,通过Response.json()可以获取响应数据并解码成JSON数据。

>>> import requests
>>> r = requests.get('https://api.github.com/events')
>>> r.json()
[{'repository': {'open_issues'0'url''https://github.com/...
  • 如果JSON解码失败,Response.json()将引发requests.exceptions.JSONDecodeError异常。(如:204响应、响应包含无效的JSON数据)

  • 如果JSON解码成功,也不代表请求成功,因为有的服务器即使请求失败也会返回一个JSON对象。(如:500响应)

只有Response.raise_for_status()或者Response.status_code才能确定请求是否成功!

参考案例:Python威武!比亚迪官网全系车型

五、最后总结

  • 原始流式:极少会用到;

  • 字节类型:使用Response.content,可用来获取图片、音频、视频等非文本类数据;

  • 文本类型:使用Response.text,可用来获取字符串文本类数据(可使用r.encoding设置编码);

  • JSON格式:使用Response.json(),可用来获取JSON数据。

原文始发于微信公众号(愤怒的it男):被python爬虫的数据类型和编码坑了无数次!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/249183.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!