网络爬虫(也叫网页蜘蛛、网络机器人)是一种自动化程序 ,核心目标是按照既定规则,从互联网上抓取并解析网页数据。小到搜索引擎的海量数据索引,大到电商平台的商品信息采集,都依赖爬虫技术实现。
其工作流程可以拆解为 5 个核心步骤,从 "发起请求" 到 "数据存储" 形成完整闭环,下面逐一详细讲解。
一、核心工作流程
1. 种子 URL 准备(爬虫的起点)
爬虫的一切工作都从 种子 URL 开始,这是人工或程序预先设定的初始网页地址。
- 来源 :可以是单个 URL(如
https://www.example.com),也可以是一批 URL 列表(如搜索引擎的待爬取站点清单); - 作用:爬虫从种子 URL 出发,先抓取这个页面,再从页面中发现新的 URL,不断扩展爬取范围(类似 "滚雪球")。
示例 :要爬取某电商的手机商品数据,种子 URL 可以设为 https://www.shop.com/mobile(手机分类页)。
2. 发送 HTTP 请求(获取网页原始数据)
这一步是爬虫与目标网站的核心交互环节,本质是模拟浏览器的行为,向目标服务器发送请求,获取网页内容。
(1)核心原理
- 爬虫通过编程语言的网络库(如 Python 的
requests、urllib)构建 HTTP 请求,携带必要的请求头(User-Agent、Referer等); - 服务器接收请求后,验证请求合法性(如是否为正常浏览器请求),返回对应的HTML 网页源码(这是最常见的目标数据,也可能是 JSON、XML 等格式)。
(2)关键细节:模拟浏览器,避免被识别
服务器会通过请求头判断访问者身份,若直接发送请求,很容易被判定为爬虫而被拦截。因此爬虫需要伪装成普通浏览器:
python
# Python 模拟浏览器请求示例
import requests
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
"Referer": "https://www.shop.com/" # 模拟从首页跳转
}
response = requests.get(url="https://www.shop.com/mobile", headers=headers)
html = response.text # 获取网页HTML源码
User-Agent:核心标识,告诉服务器 "我是 Chrome 浏览器";Referer:告诉服务器 "我是从哪个页面跳过来的",增加请求的真实性。
(3)请求类型
- GET 请求:最常用,用于获取网页内容(如商品列表、文章详情);
- POST 请求:用于需要提交数据的场景(如爬取需要登录的页面,需携带账号密码参数)。
3. 解析网页内容(提取目标数据)
服务器返回的 HTML 源码是杂乱的字符串 ,包含大量无关标签(如<div>、<style>),爬虫需要通过解析,提取出有价值的数据(如商品名称、价格、链接)。
解析方式分为 3 类,从易到难、从简单到复杂依次为:
| 解析方式 | 核心原理 | 适用场景 | 优缺点 |
|---|---|---|---|
| 正则表达式 | 通过匹配字符串的特定模式(如\d+\.\d+匹配价格)提取数据 |
简单场景(如提取单个字段) | 优点:灵活;缺点:复杂网页易出错,维护成本高 |
| XPath | 基于 XML/HTML 的树形结构,通过路径表达式定位元素(如//div[@class="price"]/text()) |
结构化网页 | 优点:语法简洁,定位精准;缺点:依赖网页结构 |
| CSS 选择器 | 模拟 CSS 选择元素的方式(如div.price),通过库(如 Python 的BeautifulSoup)提取数据 |
大多数网页 | 优点:语法通俗易懂,兼容性好;缺点:复杂嵌套需多层匹配 |
实际示例(Python + BeautifulSoup 解析商品数据)
假设网页中商品价格的 HTML 结构如下:
html
<div class="product-item">
<h3 class="name">小米14 Pro</h3>
<span class="price">4999元</span>
<a href="/mobile/1001" class="link">查看详情</a>
</div>
爬虫解析代码:
python
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, "html.parser") # 初始化解析器
# 提取所有商品项
products = soup.find_all("div", class_="product-item")
for p in products:
name = p.find("h3", class_="name").text # 商品名称
price = p.find("span", class_="price").text # 商品价格
link = p.find("a", class_="link")["href"] # 商品链接
print(f"名称:{name},价格:{price},链接:{link}")
解析结果:
名称:小米14 Pro,价格:4999元,链接:/mobile/1001
补充:解析动态渲染的网页
很多现代网页(如 Vue、React 开发的页面)使用 JavaScript 动态渲染数据 ------ 直接爬取的 HTML 源码中没有目标数据(只有 JS 代码)。此时需要使用 无头浏览器(如 Selenium、Playwright)模拟浏览器加载页面,等待 JS 执行完成后再解析:
python
from selenium import webdriver
from selenium.webdriver.common.by import By
# 初始化无头Chrome浏览器
options = webdriver.ChromeOptions()
options.add_argument("--headless=new") # 无界面模式
driver = webdriver.Chrome(options=options)
driver.get("https://www.shop.com/mobile")
# 等待页面加载完成,提取价格
price = driver.find_element(By.CLASS_NAME, "price").text
print(price)
driver.quit()
4. URL 去重与调度(避免重复爬取,提高效率)
爬虫从已爬页面中解析出大量新 URL,若直接全部爬取,会出现 重复爬取 (同一 URL 多次请求)和 无效爬取(如爬取无关页面)的问题,因此需要两个核心机制:
(1)URL 去重
通过去重容器存储已爬取或待爬取的 URL,确保每个 URL 只被处理一次。常见的去重方案:
- 内存集合(Set) :适合小型爬虫,将 URL 存入
set,利用集合 "元素唯一" 的特性去重; - 布隆过滤器(Bloom Filter):适合海量 URL 场景(如搜索引擎爬虫),占用内存小,查询效率高,允许极小的误判率;
- 数据库存储:将 URL 存入 MySQL、Redis 等数据库,通过主键或索引去重。
(2)URL 调度
爬虫的任务队列 会管理待爬取的 URL,调度器按照一定规则(如广度优先、深度优先)决定下一个要爬取的 URL:
- 广度优先(BFS):先爬取当前页面的所有子 URL,再爬取子 URL 的子 URL------ 适合爬取全站数据(如电商分类页→商品列表页→商品详情页);
- 深度优先(DFS):先爬取一个 URL 的所有层级页面,再返回爬取下一个 URL------ 适合爬取特定深度的页面(如只爬取商品详情页)。
5. 数据存储(持久化爬取结果)
解析出的目标数据需要持久化存储,方便后续分析、使用。常见的存储方式分为 3 类:
| 存储方式 | 适用场景 | 优缺点 |
|---|---|---|
| 文本文件(TXT/CSV/JSON) | 小型数据、临时存储 | 优点:操作简单,无需数据库;缺点:不支持复杂查询 |
| 关系型数据库(MySQL/PostgreSQL) | 结构化数据、需要复杂查询 | 优点:支持 SQL 查询,数据完整性高;缺点:配置稍复杂 |
| 非关系型数据库(MongoDB/Redis) | 非结构化 / 半结构化数据、高并发写入 | 优点:写入速度快,适合海量数据;缺点:查询功能不如关系型数据库 |
示例:将商品数据存入 CSV 文件
python
import csv
# 写入CSV文件
with open("products.csv", "w", encoding="utf-8", newline="") as f:
writer = csv.writer(f)
writer.writerow(["商品名称", "价格", "链接"]) # 表头
for p in products:
name = p.find("h3", class_="name").text
price = p.find("span", class_="price").text
link = p.find("a", class_="link")["href"]
writer.writerow([name, price, link])
二、爬虫的关键策略(反反爬 + 效率优化)
目标网站会通过各种手段反爬(如限制访问频率、验证人机身份),因此爬虫需要针对性优化,实现 "友好爬取"。
1. 控制爬取频率
- 设置请求间隔 :在两次请求之间加入延迟(如
time.sleep(1)),避免短时间内大量请求压垮服务器; - 模拟随机间隔 :使用随机延迟(如
time.sleep(random.uniform(1, 3))),更接近人类浏览行为。
2. 使用代理 IP 池
网站会通过IP 地址识别爬虫(单个 IP 频繁请求会被封禁)。爬虫可以搭建代理 IP 池,每次请求切换不同的 IP:
python
proxies = {
"http": "http://123.123.123.123:8080",
"https": "https://123.123.123.123:8080"
}
response = requests.get(url, headers=headers, proxies=proxies)
3. 处理 Cookie 和登录验证
部分页面需要登录后才能访问,爬虫可以通过以下方式处理:
- 手动登录后,复制浏览器的 Cookie 到请求头;
- 使用 Selenium 模拟登录流程,保存登录状态的 Cookie。
4. 遵守 robots 协议
robots.txt是网站根目录下的一个文本文件,用于告知爬虫哪些页面可以爬取,哪些禁止爬取 (如搜索引擎爬虫会遵守,恶意爬虫可能忽略)。例如,https://www.example.com/robots.txt 的内容可能为:
User-agent: * # 所有爬虫
Disallow: /admin/ # 禁止爬取/admin目录
Allow: /public/ # 允许爬取/public目录
三、爬虫的分类(按应用场景)
根据爬取范围和目标的不同,爬虫可分为 3 类:
- 通用爬虫:如百度、谷歌的搜索引擎爬虫,目标是爬取整个互联网的网页,建立索引库,为搜索功能提供数据;
- 聚焦爬虫:针对特定领域或主题的爬虫(如爬取电商平台的手机数据、新闻网站的科技新闻),只爬取与主题相关的页面;
- 增量爬虫 :只爬取新增或更新的网页,而非重复爬取所有页面,常用于数据实时更新的场景(如股票价格、新闻资讯)。