从0到1的爬虫教程

网络爬虫
Author

Tom

Published

January 8, 2021

这篇文章既是面向像我这种经管类非科班同学的爬虫教程,也是我自己对于爬虫学习的一个总结。

1 爬虫基础

一般来说,网络爬虫就是模拟客户端向服务器端发送网络请求,接收请求响应,对响应内容进行自动解析从而获取目标信息的程序。这里的客户端主要是指浏览器。因此,为了理解爬虫的工作原理,我们有必要了解浏览器的工作原理。

1.1 在浏览器的地址栏中输入 URL 并回车之后发生了什么?

URL(Uniform Resource Locator,统一资源定位符)一般称为网页地址,即网络上某个资源的地址,比如 ”http://archive.ics.uci.edu/ml/index.php“,这是 UCI 机器学习数据集的网页地址。在浏览器的地址栏中输入这个地址并回车,我们会见到如下页面:

figure-1

此时,我们获取了服务器端发送过来的数据。我们可以看一看这些数据,鼠标右键选择检查,进入开发者工具,点击 index.php,我们可以看到,这个数据是一个 document 类型的文件。点击 Preview,我们可以看到这个文件就是页面所展示的内容。

figure-2

简单来说,浏览器就是这样一个程序,帮我们向服务器端发送请求,获取响应,然后将响应内容进行解析和渲染,最终呈现给我们的就是如上图所示的页面。你可以将浏览器理解为一个邮差,他帮我们送信,同时也送回回信。

以上只是一个简化的表达,那么具体来说浏览器做了哪些工作呢?

  • URL 解析:当我们在地址栏中输入一个 URL 并回车,浏览器首先判断我们输入的是一个合法的 URL 还是一个待搜索的关键词。如果是搜索内容,浏览器会使用默认的搜索引擎,合成带有搜索内容的 URL;如果是请求的 URL,则根据规则判断 URL 是否完整,不完整则根据规则合成完整的 URL
  • DNS 查询:其次,浏览器会根据 URL 地址查找对应的 IP 地址。前面提到过,URL 地址是网络上资源存在的地址,对于我们人类来说比较好记忆,但是对于计算机来说并不好处理,计算机更擅长处理数字,因此便有了 IP 地址。IP(Internet Protocol)地址指明了发送方的地址,是网络上的一个虚拟地址。有了地址,浏览器便可以发送请求。
  • TCP 连接:客户端与服务器要相互通信,双方就要基于相同的方法和规则,我们将这种规则称为协议。比如两个人要打电话通信,我们规定都使用中文作为沟通语言,这就是一种协议。浏览器在于服务器进行通信时,为了确保数据可以准确的进行传送,采用了 TCP 协议。TCP 协议要求客户端在与服务器通信之前需要先建立 TCP 连接,你可以理解为两个人要通信前需要先连一条电话线。关于这部分内容,大家可以参考《图解 HTTP》。
  • 发出请求:通过前面的步骤,我们已经得到服务器的地址,同时建立了 TCP 连接,下面浏览器就会开始构造 HTTP 报文,发送 HTTP 请求。其中,报文包括:
    • 请求报头(Request Header):请求方法、目标地址、遵循的协议等等
    • 请求主体
  • 接受响应:服务器接收到浏览器发出的请求,会返回相应的响应资源。浏览器接收到响应资源后,会对资源进行分析。首先查看 Response Header,根据不同的状态码做不同的事。如果响应资源进行了压缩(比如 gzip),还需要进行解压。然后,对响应资源做缓存。接下来,根据响应资源里的 MIME(Multipurpose Internet Mail Extensions,媒体类型)类型去解析响应内容。
  • 渲染页面:浏览器自动发送请求获取嵌入在 HTML 中的资源(图片、音频、视频、CSS、JS 等等)

参考资料

  • 《图解 HTTP》
  • https://juejin.cn/post/6844903922084085773
  • https://zhuanlan.zhihu.com/p/133906695
  • https://juejin.cn/post/6975307495808237604

1.2 HTTP 协议

http 与 https 区别

HTTPS 比 HTTP 更安全,但是性能更低。HTTP,超文本传输协议,默认端口是80。超文本:指不仅限于文本,还包括图片、音频、视频等文件。传输协议:使用共同约定的固定格式来传递转换成字符串的超文本内容。

HTTPS:HTTP + SSL(安全套接字层),即带有安全套接字层的超文本传输协议,默认端口号443。SSL 对传输的内容进行加密

请求头

  • Content-Type
  • Host(主机和端口号)
  • Connection(链接类型)
  • Upgrade-Insecure-Requests(升级为 HTTPS 请求)
  • User-Agent(用户代理:提供系统信息与浏览器信息)
  • Referer(页面跳转处,防盗链)
  • Cookie(状态保持)
  • Authorization(用于表示 HTTP 协议中需要认证资源的认证信息)

响应头

  • Set-Cookie

常见的响应状态码

  • 200:成功
  • 302:跳转,新的 URL 在响应的 Location 头中给出
  • 303:浏览器对于 POST 的响应重定向至新的 URL
  • 307:浏览器对于 GET 的响应重定向至新的 URL
  • 403:资源不可用;服务器理解客户的请求,但拒绝处理它(没有权限)
  • 404:找不到该页面
  • 500:服务器内部错误
  • 503:服务器由于维护或者负载过重未能应答,在响应中可能会携带 Retry-After 响应头;有可能是因为爬虫频繁地访问,使服务器忽视爬虫请求,最终返回 503 响应状态码

一切的状态码都不可行,一切都以是否从抓包得到的响应中获取到的数据为准

Network 中抓包得到的源码才是判断依据,Elements 中是浏览器渲染之后的源码,不能作为判断标准

2 一个简单的爬虫

前面我们已经提到爬虫就是通过模拟浏览器,发送请求,接收响应数据。那么如何向目标服务器发送请求呢?Python 的第三方库 Requests 为我们提供了良好的接口。下面的代码是向百度发送一个 Get 请求:

figure-3

首先我们导入 requests 库,然后调用 get 方法发送请求,最后打印出字符串类型的响应内容(print(res.text))。这里我们可以观察到打印出的内容里面还有乱码。这是因为在网络中传输的字符串都是 bytes 类型的,而 res.text 是 requests 模块按照 chardet 模块推测出来的字符集进行解码的结果。我们可以打印出推测出来的字符集,如下图:

figure-4

如上图所示,推测出来的字符集为“ISO-8859-1”。我们可以鼠标右键,选择检查,打开开发者工具,点击 Elements,键盘按下 Ctrl + f 搜索 charset,参考该字符集进行手动编码,如下图:

figure-5

如上图所示,我们可以使用 utf8 字符集进行手动编码,如下图:

figure-6

除了使用 res.text 并进行手动编码,我们也可以先获取 bytes 类型的数据再进行手动解码(decode),如下图:

figure-7

3. 爬虫深入

3.1 抓包分析