网站上看到了大量好看的图片再也不用右键另存为了
针对人群:
- 对 python 感兴趣的零基础的童靴
- 有一定基础想深入了解 python 的童靴
涉及知识:
- 网络爬虫的本质
- http 协议
- requests 库
收获:
认识网络爬虫的本质,掌握爬虫的基本开发流程,了解互联网数据传输的基本原理。
理论知识
理论指导实践,知其然要知其所以然,我们先来学习必备的理论知识。
什么是爬虫
网络爬虫也叫网络蜘蛛,它特指一类自动批量下载网络资源的程序,这是一个比较口语化的定义。 更加专业和全面的定义是:网络爬虫是伪装成客户端与服务端进行数据交互的程序。
口语化的定义相信大家都能理解,不能理解的童靴请自觉面壁!
但是后面的客户端,服务端肯定有童靴不理解了,这就涉及下一个概念了。
应用架构
商业应用推动了互联网的飞速发展,目前几乎所有的商业应用都是基于互联网的,它们一般采用 c/s 架构,b/s 架构或 m/s 架构。
- c/s 即 client server 客户端 服务端
- b/s 即 browser server 浏览器 服务端
- m/s 即 mobile server 移动端 服务端
安装在用户电脑中的程序叫客户端,例如 LOL,例如 QQ,例如腾讯课堂等。
为客户端提供服务支持的,运行在服务厂商服务器中的程序叫服务端。
A 用户在 QQ 中给 B 用户发送一条信息的过程是:
A 发送的信息首先发送到服务器,服务器再将这个信息发送给 B 接收。
特别的,当客户端是浏览器时,我们单独作为一种架构叫做 b/s 架构,例如各种网站;
当客户端是移动端上的 APP 时,我们单独作为一种架构叫做 m/s 架构,例如各种手机 APP。
所以:本质上 b/s,m/s 也是 c/s 的一种!
那客户端和服务端是如何进行通信的呢?(网络通信涉及物理层和应用层,我们这里讨论应用层!)
不同的客户端和不同服务端进行数据交互,为了统一大家制定了各种传输协议。
最开始每个团队设计的客户端和服务端之间的数据方式都不一样,为了提高开发效率和资源利用大家统一制定了各种应用传输协议。
例如:
- http 超文本传输协议
- ftp 文件传输协议
- smtp 电子邮件传输协议
因为大多数爬虫都是爬取的网页中的信息,所以我们今天主要了解 HTTP 协议。
HTTP 协议
http 协议有厚厚一本书,今天我们讲主要流程,感兴趣的童靴听完课后就可以去收集资料钻研啦。
一个基于 http 协议的数据传输分为 2 个部分,请求和响应。
客户端向服务端发送一个 http 请求,服务端收到这个请求后根据请求进行处理,然后将结果以 http 响应的形式返回给客户端。
http 请求
一个完整的 HTTP 请求报文包含:请求行,请求头,空行和请求数据。
下图给出了请求报文的一般格式。
# 例如请求百度首页的请求报文
b'GET / HTTP/1.0\r\nHost:www.baidu.com\r\n\r\n'
请求方法
根据 http 标准,http 请求可以使用多种请求方法。
1.0 定义了三种请求方法:GET,POST 和 HEAD 方法
1.1 新增了五种请求方法:OPTIONS,PUT,DELETE,TRACE 和 CONNECT 方法。
最常用的请求方法是 get 和 post。
- get
简单来说,GET 方法一般用来获取数据,或者将一些简短的数据放到 URL 参数中传递到服务器。比 POST 更加高效和方便。
- post
由于 GET 方法最多在 url 中携带 1024 字节数据,且将数据放到 URL 中传递太不安全,数据量大时 URL 也会变得冗长。所以传递数据量大或者安全性要求高的数据的时候,最好使用 POST 方法来传递数据。
请求头
请求行下方则是请求报头,每个报头的形式如下:
报头名 + : + 值
常见请求头和作用如下:
名称 | 作用 |
---|---|
Host | 指定的请求资源的域名(主机和端口号)。HTTP 请求必须包含 HOST,否则系统会以 400 状态码返回。 |
User-Agant | 简称 UA,内容包含发出请求的用户信息,通常 UA 包含浏览者的信息,主要是浏览器的名称版本和所用的操作系统。这个 UA 头不仅仅是使用浏览器才存在,只要使用了基于 HTTP 协议的客户端软件都会发送,无论是手机端还是 PDA 等,这个 UA 头是辨别客户端所用设备的重要依据。 |
Accept | 告诉服务器客户端可以接受那些类型的信息。 |
Cookie | Cookie 信息。 |
Cache-Control | 指定请求和响应遵循的缓存机制。在请求消息或响应消息中设置 Cache-Control 并不会修改另一个消息消息处理过程中的缓存处理过程。请求时的缓存指令包括 no-cache、no-store、man-age、max-stake、min-fresh、only-if-cached;响应消息中的指令包括 public、privete、no-cache、no-store、no-transform、must-revalidate、proxy-revalidate、max-age。 |
Referer | 页面跳转处,表明产生请求的网页来自于哪个 URL,用户是从该 Referer 页面访问到当前请求的页面。这个属性可以用来跟踪 Web 请求来自哪个页面,是从什么网站来的。 |
Content-Type | 来表示具体请求中的媒体类型信息,例如 text/html 代表 HTML 格式,image/gif 代表 GIF 图片,application/json 代表 JSON 类型 |
Content-Length | 内容长度。 |
Content-Range | 响应的资源范围。可以在每次请求中标记请求的资源范围,在连接断开重连时,客户端只请求该资源未下载的部分,而不是重新请求整个资源,实现断点续传。迅雷就是基于这个原,使用多线程分段读取网络上的资源,最后再合并。 |
Accept-Encoding | 指定所能接收的编码方式,通常服务器会对页面进行 GZIP 压缩后再输出以减少流量,一般浏览器均支持对这种压缩后的数据进行处理,但对于我们来说,如果不想接收到这些看似乱码的数据,可以指定不接收任何服务器端压缩处理,要求其原样返回。 |
Accept-Language | 指浏览器可以接受的语言种类 en、en-us 指英语 zh、zh-cn 指中文。 |
Connection | 客户端与服务器链接类型,keep-alive:保持链接,close:关闭链接。 |
请求数据
请求数据通常是使用 POST 方法进行发送的,GET 方法是没有请求数据的。
请求数据跟上面的消息报头由一个空行隔开。
讲到这里,我们可以看出所谓的协议就是数据的统一组织格式。
http 响应
一个完整的 HTTP 响应报文也由四个部分组成,分别是:状态行,消息报头,空行和响应正文。
响应状态码
当客户端向服务端发起一次请求后,服务端在返回的响应头中会包含一个 HTTP 状态码。
HTTP 的状态码是由三位数字来表示的,由第一位数字来表示状态码的类型,一般来说有五种类型:
分类 | 分类描述 |
1** | 信息,服务器收到请求,需要请求者继续执行操作 |
2** | 成功,操作被成功接收并处理 |
3** | 重定向,需要进一步的操作以完成请求 |
4** | 客户端错误,请求包含语法错误或无法完成请求 |
5** | 服务器错误,服务器在处理请求的过程中发生了错误 |
响应报头
状态行下方的就是响应报头。常见响应报头如下:
报头 | 功能描述 |
Allow | 服务器支持哪些请求方法(如 GET、POST 等)。 |
Date | 表示消息发送的时间,时间的描述格式由 rfc822 定义。例如,Date:Mon,31Dec200104:25:57GMT。Date 描述的时间表示世界标准时,换算成本地时间,需要知道用户所在的时区。 |
Set-Cookie | 非常重要的 header, 用于把 cookie 发送到客户端浏览器,每一个写入 cookie 都会生成一个 Set-Cookie。 |
Expires | 指定 Response 的过期时间 ,从而不再缓存它,重新从服务器获取,会更新缓存。过期之前使用本地缓存。降低服务器负载,缩短加载时间。 |
Content-Type | Web 服务器告诉客户端自己响应的对象的类型和字符集。 |
Content-Encoding | 文档的编码(Encode)方法。只有在解码之后才可以得到 Content-Type 头指定的内容类型。利用 gzip 压缩文档能够显著地减少 HTML 文档的下载时间。 |
Content-Length | 指明实体正文的长度,以字节方式存储的十进制数字来表示。 |
Location | 用于重定向一个新的位置,包含新的 URL 地址。表示客户应当到哪里去提取文档。 |
Refresh | 表示浏览器应该在多少时间之后刷新文档,以秒计。 |
可以把一个 http 事务比作通过暗号打电话,客户端向服务端打电话接通后客户端先说话,服务端根据客户端的暗号选择回复内容。
http 协议有一些特点:
- HTTP 是无连接的:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。
- HTTP 是媒体独立的:这意味着,只要客户端和服务器知道如何处理的数据内容,任何类型的数据都可以通过 HTTP 发送。客户端以及服务器指定使用适合的 MIME-type 内容类型。
- HTTP 是无状态:HTTP 协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。
浏览器的工作原理
讲完 HTTP 协议之后,我们首先来简单了解一下浏览器的工作原理。
浏览器访问一个页面的流程如下:
- 在地址栏中键入网页的网址
- 浏览器会向这个网址所指向的服务器发起一个 http 请求
- 浏览器接受服务器返回的 http 响应
- 浏览器从上往下解析渲染响应回来的 HTML 文档
- 在解析渲染的过程中碰到其他资源浏览器继续向服务器发送请求
- 直到当前页面的所有资源全部下载回来
为了便于零基础的童靴理解,我简化了部分步骤
从这些流程中我们可以总结如下几点:
- 浏览器打开一个页面时所有的数据都是从服务下载回来的
- 浏览器打开一个页面第一个 http 请求下载的是网页的 HTML 文档
- 浏览器打开一个页面一般会发送多个 http 请求
网络资源
能够通过互联获取的网页,图片,视频,音频,其他文件等信息的集合。
爬虫的目标就是网络资源。网络那么大,怎么定位网络资源呢?如何用浏览器打开淘宝首页,下载某个文件?
url
URL(Uniform Resource Locator),中文叫统一资源定位符。是用来标识某一处网络资源的地址。
也即是我们常说的网址。以下面这个 URL 为例,介绍下普通 URL 的各部分组成:
现在基础知识我们已经学完了,可以开始进行实践了。
爬虫实践
开发流程
网络爬虫的本质就是模拟客户端发送请求,一个爬虫的基本开发流程包含五步:
- 明确目标数据
- 分析数据的请求流程
- 模拟发送请求
- 解析数据
- 数据持久化
1. 明确目标数据
我们要下载的是百度图片首页中的图片
网页中的图片是浏览器通过 http 请求下载回来的。
浏览器会先下载图片的 url,再通过 url 下载图片。
所以我们只要找到图片 url 的 http 请求即可。
一般情况下,页面中的图片 url 就包含在页面的 HTML 文档中,使用谷歌浏览器开发者调试工具获取图片的 url
然后右键查看网页源文件可以查看当前页面的 HTML 文档
ctrl+f 调出搜索框,把前面找到的图片的 url 粘贴进来,果然发现了 url 就在 HTML 中
为了稳妥可以多找几张图片的 url 测试。发现页面中的前 30 张图片的 url 都在 HTML 文档中。
2.分析数据请求流程
分析请求流程的目的找到目标资源的 http 请求,根据前面学习的 HTTP 协议知识,分析请求流程的具体信息是:
- 请求方法
- url
- 请求头
- 请求数据
1.1 工具
在 HTTP 协议中信息以二进制的形式进行传输的,我们需要借助工具来分析 HTTP 请求。常用工具有,谷歌浏览器和 fiddler。
1.1.1 fiddler
fiddler 的使用和安装相对复杂,谷歌浏览器可以满足大部分的请求流程分析,这里主要介绍谷歌浏览器。
1.1.2 谷歌浏览器
谷歌浏览器提供了开发者调试工具,能够对浏览器的 HTTP 请求进行监控,按功能键 F12
即可打开工具界面,功能窗口如下:
点击某个具体的请求后
我们这个案例中的请求就是网页的请求
- 1.请求方法: get
- 2.url:https://image.baidu.com/search/index?tn=baiduimage&ct=201326592&lm=-1&cl=2&ie=gb18030&word=%CD%BC%C6%AC&fr=ala&ala=1&alatpl=adress&pos=0&hs=2&xthttps=000000
- 3.请求头:当前可以忽略
- 4.请求数据:无
3. 发送请求
分析清楚目标资源的请求过程后,就需要通过代码模拟发送请求。
通过 socket 发送 HTTP 请求
from socket import socket
# 创建客户端
client = socket()
# 连接百度服务器 域名 端口
client.connect(('www.baidu.com', 80))
# 构造http请求报文
data = b'GET / HTTP/1.0\r\nHost: www.baidu.com\r\n\r\n'
# 发送报文
client.send(data)
res = b''
# 接收响应数据
temp = client.recv(1024)
print('*' * 100)
while temp:
res += temp
temp = client.recv(1024)
print(res)
工具库
上面我们通过使用 socket 实现了一个非常简单的请求的发送,可以看到代码比较复杂,如果需要传递更多信息,处理起来会更繁琐,费时费力。python 提供了很多的库,将发送 HTTP 请求的细节进行了封装,只需要进行简单的调用就可以实现各种 http 请求的发送,常用的库有:
- urllib urllib 是一个用来处理网络请求的 python 标准库
- urllib3 urllib3 是一个基于 python3 的功能强大,友好的 http 客户端。越来越多的 python 应用开始采用 urllib3.它提供了很多 python 标准库里没有的重要功能。
- requests 牛逼
使用 requests 发送请求
import requests
res = requests.get('http://www.baidu.com') # 发送请求,并接收响应
print(res.content) # 输出响应数据
4.解析数据
响应正文及响应数据一般分为两大类,文本数据和二进制数据。
其中文本数据又分为 HTML 和 JSON(注:主要指爬虫目标数据,js,CSS 等也属于文本数据)。
二进制数据主要指各种音频,视频,其他文件等。
对于二进制数据一般不需要特殊处理。
HTML 解析
今天的案例数据包含在 HTML 文档中,所以需要解析 HTML
解析 HTML 的常用方法有两种:
- 正在表达式
- HTML 解析库
5.数据持久化
爬虫爬取到的数据需要存储起来,对于少量的数据,生成相应的文件,例如 Excel,cvs 等。
对于图片,视频等二进制文件也是以文件的形式保存。
如果要保存大量的文本信息,例如商品信息,订单信息等,就需要存储到数据库中。
代码
import re
import requests
# 1. 明确目标数据
'''
浏览器先下载图片的url再下载图片
有30张图片在百度图片搜索页面的html文档中
'''
# 2. 分析目标http请求
'''
浏览器打开一个网页时第一次请求回来的数据就是网页的html,一般是get请求
浏览器地址栏中的url就是这个html的url
url = https://image.baidu.com/search/index?tn=baiduimage&ct=201326592&lm=-1&cl=2&\
ie=gb18030&word=%CD%BC%C6%AC&fr=ala&ala=1&alatpl=adress&pos=0&hs=2&xthttps=111111
'''
# 3. 模拟发送http请求,下载html
url = 'https://image.baidu.com/search/index?tn=baiduimage&ct=201326592&lm=-1&cl=2&\
ie=gb18030&word=%CD%BC%C6%AC&fr=ala&ala=1&alatpl=adress&pos=0&hs=2&xthttps=111111'
response = requests.get(url)
# 4. 解析数据,解析页面中的图片urls
html = response.text
img_urls = re.findall('"thumbURL":"(.*?)"', html)
# 5. 数据持久化,下载图片并保存
for index, img_url in enumerate(img_urls):
img_res = requests.get(img_url)
with open('{}.jpg'.format(index), 'wb') as f:
f.write(img_res.content)
print(index, img_url)
本文由柠檬班心蓝老师原创,转载需注明出处!
想了解更多咨询的同学扫描下方二维码,可以加Q群领取学习资料:753665853 备注:CSDN