HTTP 协议与爬虫基础
一、爬虫的基本概念
网络爬虫(又称网页蜘蛛、网络机器人)是模拟浏览器发送网络请求、接收响应,并按照一定规则自动抓取互联网信息的程序。原则上,浏览器(客户端)能做的事,爬虫都能做。
1. 数据的来源与用途
获取数据的常见途径:
- 向第三方数据公司购买(如企查查)
- 从免费数据网站下载(如国家统计局)
- 通过爬虫采集(最高效的途径)
- 人工收集(问卷、录入)
爬取到的数据通常用于:
- 网页 / App 的聚合展示(如今日热榜这类聚合站点)
- 数据分析与机器学习训练
2. 爬虫的分类
- 通用爬虫:如搜索引擎的爬虫,抓取全网页面建立索引
- 聚焦爬虫:针对特定网站、特定数据进行的定向采集
3. 爬虫的工作流程
获取资源地址(URL) → 发送请求获取响应 → 提取数据 → 保存数据
↑___________________________________|
(解析出新的 URL 继续爬取)- 获取资源地址:拿到准确的数据接口或页面 URL;
- 发送请求:获取网页源代码或接口 JSON;
- 提取信息:用正则、XPath、BeautifulSoup 等解析出目标字段;
- 保存数据:存为 TXT / JSON / CSV,或写入 MySQL、MongoDB 等数据库。
二、HTTP 基础
1. URL 的组成
https://www.baidu.com/s?wd=python#flg
协议 域名 资源路径 查询参数 锚点- 协议:
http(默认端口 80)或https(HTTP + SSL/TLS,默认端口 443) - 域名:也可以直接写 IP;
域名:端口用冒号分隔 - 查询参数:
?之后、#之前的key=value部分 - 锚点:
#之后,用于页面内定位,不会发送给服务器
2. HTTP 协议的发展
| 版本 | 年代 | 核心变化 |
|---|---|---|
| HTTP/0.9 | 1991 | 只有 GET 方法,无请求头、无状态码 |
| HTTP/1.0 | 1996 | 引入 POST/HEAD、状态码、请求头与更多内容类型 |
| HTTP/1.1 | 1997 | 第一个标准版:持久连接、分块传输、缓存控制、虚拟主机 |
| HTTP/2 | 2015 | 二进制分帧、多路复用、头部压缩、服务器推送 |
| HTTP/3 | 2021 | 基于 QUIC(UDP),解决队头阻塞,内置 TLS 1.3 |
3. 浏览器渲染与爬虫的关系
浏览器拿到第一个 HTML 响应后,会继续加载其中的 CSS、JS、图片和 Ajax 接口,逐步渲染出最终页面——这个过程叫渲染。以一个典型的评论列表为例:
- 浏览器请求
https://example.com/article/1,服务器返回 HTML 骨架(此时评论区域是空的); - HTML 里的
<script>被执行,页面中的 JS 向https://api.example.com/comments?page=1发起 Ajax 请求; - 接口返回 JSON(评论数据),JS 把它拼成一个个
<div>插进页面; - 你在页面上「看到」了评论——但它们来自第 2 步的接口,而不是第 1 步的 HTML。
而爬虫只请求 URL 并获取对应的响应:如果只请求第 1 步的 HTML,拿到的源码里根本没有评论。浏览器里看到的页面和爬虫拿到的源码经常不一样,所以做爬虫必须先在 Network 面板里找到真正装着数据的那个请求(往往是接口返回的 JSON),以它为准来提取数据。
三、HTTP 请求与响应
1. 请求的四个部分
- 请求方法:
GET(获取页面)、POST(提交表单/上传数据)、PUT、DELETE、HEAD、OPTIONS等 - 请求 URL:唯一确定请求的资源
- 请求头:常用的有:
| 请求头 | 作用 |
|---|---|
User-Agent | 浏览器标识,爬虫最基本的伪装 |
Referer | 来源页面,常用于防盗链 |
Cookie | 维持登录态、通过部分反爬校验 |
Accept / Accept-Encoding | 可接受的内容类型与编码 |
X-Requested-With: XMLHttpRequest | 标识 Ajax 异步请求 |
- 请求体:POST 请求携带的表单或 JSON 数据,GET 请求一般为空
2. 响应的三个部分
- 状态码:判断请求是否成功的第一依据
| 状态码 | 含义 | 爬虫中的典型场景 |
|---|---|---|
| 200 | 成功 | 正常返回数据 |
| 301 / 302 | 永久 / 临时重定向 | requests 默认自动跟随 |
| 304 | 未修改 | 命中缓存 |
| 403 | 禁止访问 | 常见于 UA / Referer / Cookie 校验失败 |
| 404 | 未找到 | URL 拼接错误 |
| 412 | 前置条件失败 | 瑞数等 Cookie 反爬的典型特征 |
| 429 | 请求过多 | 触发频率限制 |
| 500 / 502 / 504 | 服务器错误 | 服务端异常或被反爬拦截 |
- 响应头:
Content-Type(数据类型)、Set-Cookie(设置 Cookie)、Server等 - 响应体:最重要的部分——请求什么,响应体里装的就是什么:请求网页装的是 HTML 源码,请求接口装的是 JSON 字符串,请求图片装的是二进制数据。爬虫后续的所有解析工作(提取、存储)都围绕响应体展开。
四、会话与 Cookie
HTTP 是无状态协议——每个请求都是独立的,服务器天生无法记住"上一次请求是谁发的"。打个比方:奶茶店每次接单都把你当陌生顾客,你出示一次会员卡(Cookie),店员才认得你,而且每次下单都得再出示一次。Cookie 就是解决这个问题的机制:
- Cookie:网站为辨别用户身份而存储在浏览器本地的数据,每次请求自动携带
- 常见属性:
Name/Value、Expires(过期时间)、Path、Domain、HttpOnly(禁止 JS 读取)、Secure(仅 HTTPS 传输) - Session:会话数据保存在服务端,浏览器只保存对应的 Session ID
爬虫中带上 Cookie 的利弊:
- ✅ 能访问登录后的页面、通过部分反爬校验
- ❌ 一套 Cookie 对应一个用户身份,请求过频繁更容易被识别——解决办法是多账号轮换
五、浏览器开发者工具
先解释一下抓包这个词:浏览器与服务器之间的每一笔请求和响应,都会完整地经过你的电脑。抓包工具(DevTools 的 Network 面板、后面章节的 Charles 等)就像在通信线路上装了一个「监听器」,把这些来来往往的数据包原样记录下来供你查看。做爬虫的第一步永远是抓包——先搞清楚「数据到底在哪个请求里、请求带了哪些参数」,再动手写代码。
以 Chrome 为例(F12 或右键「检查」打开),爬虫最常用的面板:
- 元素(Elements):查看渲染后的 DOM 树,适合分析页面结构
- 网络(Network):抓包核心面板,按时间列出所有请求;点击某条请求可查看:
- 标头(Headers):URL、方法、状态码、请求头与响应头
- 载荷(Payload):查询参数与 POST 请求体
- 预览 / 响应(Preview / Response):响应体内容,判断数据是 HTML 还是 JSON
- 启动器(Initiator):请求由哪段代码发起,逆向时用来追调用栈
- 控制台(Console):执行 JS 片段、Hook 代码
- 源代码(Sources):断点调试 JS(Web 逆向的主要战场)
- 应用(Application):查看 / 删除 Cookie、LocalStorage
抓包小技巧
网络面板的过滤器支持按域名、类型(Fetch/XHR)过滤;勾选 Preserve log 可以在页面跳转后保留请求记录;Disable cache 避免缓存干扰分析。
六、用 Socket 发送 HTTP 请求
requests 之前,可以先用最原始的 Socket 感受一下 HTTP 协议本身就是一段文本:
import socket
import re
url = 'http://image11.m1905.cn/uploadfile/2021/0922/thumb_0_647_500_20210922030733993182.jpg'
# 1. 创建 TCP 套接字并连接服务器(80 端口)
client = socket.socket()
client.connect(('image11.m1905.cn', 80))
# 2. 手工构造 HTTP 请求报文(\r\n 分隔,空行结束)
http_req = (
'GET ' + url + ' HTTP/1.0\r\n'
'Host: image11.m1905.cn\r\n'
'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) '
'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36\r\n\r\n'
)
client.send(http_req.encode())
# 3. 循环接收响应
result = b''
data = client.recv(1024)
while data:
result += data
data = client.recv(1024)
# 4. 用 \r\n\r\n 分隔响应头与响应体,把图片存下来
image = re.findall(b'\r\n\r\n(.*)', result, re.S)[0]
with open('image.jpg', 'wb') as f:
f.write(image)注意:HTTP/1.1 默认开启长连接(Connection: keep-alive),recv 会一直等待;若不希望保持连接,可在请求头加 Connection: close,或像上面一样使用 HTTP/1.0。
七、小结
- 爬虫 = 模拟浏览器发请求 + 解析响应 + 存储数据,一切以 URL 对应的响应为准
- 请求方法、请求头(UA / Referer / Cookie)、状态码是日常抓包分析的三要素
- 浏览器渲染后的页面 ≠ 源码,动态数据要去 Network 面板找接口
- 下一章开始用 requests 把上面的流程代码化