答疑·限时优惠

如果,你想让我看见你的疑问并且百分之百的回答。可以加入我的知识星球。
AI悦创·进化岛
AI悦创·进化岛

你好,我是悦创。

回顾一下爬虫的小基础小知识点。

1. Python 爬虫基础

1.1 Web 基础概念

  • 写爬虫必须弄懂的问题:
    • 从输入网址到看到网页,都发生了什么?
    • 这个问题是个经典问题,如果你去面试一些公司的时候涉及到一些网站开发也好,爬虫也好,反正跟网络相关的他肯定都会问这个问题。弄清这个过程是至关重要的。
  • URL 的概念
    • 统一资源定位符:Uniform Resource Locator
    • 这个也是需要我们搞清楚的,我们了解的。因为,我们一般需要抓取网页之后又要再次的解析网站,然后解析内部的 url 并进行请求,了解 url 的组成部分也是非常重要的。
    • 组成:
    from urllib.parse import urlparse
    
    url = 'https://www.google.com/search?q=url'
    
    result = urlparse(url)
    
    print(result)
    
    # 输出:
    ParseResult(scheme='https', netloc='www.google.com', path='/search', params='', query='q=url', fragment='')
    
  • 推荐使用 Ipython:
    • image-20200622172403174

    • **IPython ** 是一种基于 Python 的交互式解释器。相较于本地的 Python Shell,IPython 提供了更为强大的编辑和交互功能;

    • IPython 拥有一套复杂的并行和分配计算结构。IPython 使得各种并行应用能够交互式的被开发、执行、调试和监控。因此IPython 中的 “I” 代表“交互”;

    • 按 Tab 键也可以获取提示;

    • 我们也可以使用它在对应的函数后面添加 ? (添加问号)我们可以看见这个 API 的 Document string;

    • 这就很方便我了解一个函数或者模块的使用;
  • 我们都知道,一般在我们使用某些网站的时候,比如:百度的时候,我们使用 text 返回的数据是乱码的,那这其实是由于 requests 造成的,你们可以理解成是 Bug 吧,我们可以使用 reqeusts 请求我的博客:https://www.aiyc.top 和百度:https://www.baidu.com 我们分别看看两个所得到的编码。

    • 我们可以观察输出结果可知,这个编码并没有统一,那也就是说,这个编码是 reqeusts 自行判断得出的。UTF-8 大家都非常熟悉,这里就不赘述了。而 ISO-8859-1 一般只针对英文部分的编码,而我们的百度首页上是有中文汉字的。而当我们用英文的编码去解码中文的时候,就会出现像这里的乱码。这个乱码其实是 requests 对中文的一个错误判断。

    • 乱码出现的本质是编码解码的不一致造成的。

  • 那我们该如何解决这个乱码问题呢?

    • 我们在解决之前,我们需要了解的是, requests 中的 encoding 是怎么来的!
  • 第一步:requests 会去读 Http 标头中,头里面有可能声明了我们内容的编码如果它在头部找到了就把它赋给 encoding;

  • 第二步:如果头部没有的话,将使用 chardet 尝试猜测编码。就会去判断 requests 的二进制的编码(r2.content),实际的操作如下:

由上面的代码,我们检测出来的是 utf-8 的,那很有可能是第一步识别的 Http 标头中的编码。 所以,他就误认为是这样的编码。

收到响应时,请求会猜测访问Response.text 属性时用于解码响应的编码 。请求将首先检查HTTP标头中的编码,如果不存在,则将使用 chardet 尝试猜测编码。

唯一的一次请求不会做到这一点,如果没有明确的字符集是存在于HTTP头,并Content-Type 头中包含 text。在这种情况下, RFC 2616 指定默认字符集必须为 ISO-8859-1。在这种情况下,请求遵循规范。如果需要其他编码,则可以手动设置 Response.encoding 属性,或使用raw Response.content

  • 所以,这样的情况下,我们就可以如下编码操作:r2.content.decode('utf-8')

这样我们得到的就不是乱码的了。 所以,在我们之后写爬虫抓去包含中文的网站,尽量不要直接 r.text 这个变量,因为它有可能把这个编码理解错,输出得到这种乱码来。

我们要的就是先使用 chardet 这个库来进行检测编码,然后我们再手动解码。

实际操作:

# 方法一:推荐
import requests
import chardet

url = 'https://www.baidu.com'
resopnse = requests.get(url)
# print(resopnse.text)
Capture_the_coding = chardet.detect(resopnse.content)['encoding']
# print(Capture_the_coding)
print(resopnse.content.decode(Capture_the_coding))
# 方法二:
import requests

url = 'https://www.baidu.com'
resopnse = requests.get(url)
resopnse.encoding = 'utf-8'
print(resopnse.text)
# 方法三:
import requests

url = 'https://www.baidu.com'
resopnse = requests.get(url)
resopnse.encoding = resopnse.apparent_encoding
print(resopnse.text)
# 方法四:
import requests

url = 'https://www.baidu.com'
resopnse = requests.get(url)
# print(resopnse.content.decode('utf8'))
print(resopnse.text.encode('utf8'))

这里还是要再说一下这个 chardet 这个库,它还是有些小问题的。

我们知道中文的编码有很多种( utf-8、gbk、gb2312、gb18030 等这种)为什么要说这个呢?

gb2312 < gbk < gb19030

  • gb2312:它的汉字只有六千多个,所以我们好多网站都不包含在 gb2312 里面;
  • gb:差不多有两万多个汉字了 ;
  • gb18030:这里的数字就会更多一些;

那么 chardet 问题在哪呢?

这里 chardet.detect() 在 detect 的时候,detect 出来的时候,如果目标包含中文,如果是 gbk 的它返回的有可能是 gb2312 。所以,大家要认清它的关系。这样就导致了编解码的不一致,造成乱码。

所以,我给大家介绍另外一个库,所以我们还有个变通的方法。

这里,我们先用代码演示一下,看是不是会出现我上面 所说的问题:

import chardet
str1 = '跟悦创学编程'
str2 = '科技健康'
result = chardet.detect(str1.encode('gbk'))
result2 = chardet.detect(str2.encode('gbk'))
print(result)
print(result2)

运行结果:

{'encoding': 'TIS-620', 'confidence': 0.2248882575226022, 'language': 'Thai'}
{'encoding': 'ISO-8859-1', 'confidence': 0.73, 'language': ''}

这就表明它不是非常准确的,所以我们需要用到这个库:cchardet,直接使用如下命令安装即可:

pip3 install cchardet

image-20200706151418411

安装之后,我们继续运行上面的代码,看运行结果如何:

import cchardet
str1 = '跟悦创学编程'
str2 = '科技健康'
result = cchardet.detect(str1.encode('gbk'))
result2 = cchardet.detect(str2.encode('gbk'))
print(result)
print(result2)

运行结果:

{'encoding': None, 'confidence': None}
{'encoding': 'WINDOWS-1252', 'confidence': 0.5}

我们可以看到,这运行的不是非常的准确,所以我个人推测这个和我们的一个字数有可能有关,我们可以多输入几个汉字,然后再次运行观察:

import cchardet
str1 = '跟悦创学编程,轻松又快乐!'
str2 = '科技健康每日运动'
result = cchardet.detect(str1.encode('gbk'))
result2 = cchardet.detect(str2.encode('gbk'))
print(result)
print(result2)

运行结果:

{'encoding': 'GB18030', 'confidence': 0.9259259700775146}
{'encoding': 'GB18030', 'confidence': 0.9900000095367432}

从结果可以看出,更加的准确了,我们再回到原来的上面的 chardet 的库,来运行试一试:

import chardet
str1 = '跟悦创学编程,轻松又快乐!'
str2 = '科技健康每日运动'
result = chardet.detect(str1.encode('gbk'))
result2 = chardet.detect(str2.encode('gbk'))
print(result)
print(result2)

运行结果:

{'encoding': 'GB2312', 'confidence': 0.9259259259259258, 'language': 'Chinese'}
{'encoding': 'GB2312', 'confidence': 0.99, 'language': 'Chinese'}

这回就出现了我上面所说的问题了,也就是我编码的是 gbk ,然后 chardet 返回的是 gb2312 的,这个时候我们用 gb2312 去解码就有可能出现乱码或者出错(假设)。

所以,最终建议使用 cchardet 这样在中文方面就不会出现太大的问题:

import requests
import cchardet

url = 'https://www.baidu.com'
resopnse = requests.get(url)
#print(resopnse.text)
Capture_the_coding = cchardet.detect(resopnse.content)['encoding']
#print(Capture_the_coding)
print(resopnse.content.decode(Capture_the_coding))
AI悦创·创造不同!
AI悦创 » Requests出现乱码,一次解决!

Leave a Reply