一篇文章打通 Python 爬虫核心知识:从 HTTP 协议、requests 请求、XPath/BS4 解析、JS 动态数据、反爬绕过,到多线程并发、代理池、限速限流,最后完成一个可直接商用的全站图片爬取实战项目。
适合读者:掌握 Python 基础,零基础想学爬虫、需要做数据采集、项目实战的开发者
环境版本:Python3.8+,全平台通用
预计阅读时间:40~60 分钟
写在前面
很多初学者学爬虫,只会复制粘贴 requests.get,遇到 乱码、403 拦截、JS 渲染、频率限制、封IP 就彻底束手无策。
其实爬虫的核心逻辑非常简单,只有三件事:
1. 模拟浏览器发送网络请求,拿到服务器返回数据;
2. 精准解析页面/接口数据,筛选出自己需要的内容;
3. 规避网站反爬策略,稳定、批量、长期采集数据。
本文不会只教“跑通代码”,而是带你从原理到实战完整吃透:
• HTTP/HTTPS 请求到底发生了什么
• 静态页面与动态 JS 页面的本质区别
• 为什么别人爬虫秒封,你的爬虫稳定运行
• headers、cookie、限速、代理的真正作用
• 单线程、多线程爬虫适用场景与性能差异
• 从零开发一个健壮、可扩展、可直接运行的全站爬虫项目
一、先建立爬虫完整知识地图
1. 爬虫的运行模型
爬虫本质就是一个自动化客户端,和浏览器行为完全一致:
爬虫客户端 ——请求——> 网站服务端
爬虫客户端 <——响应—— 网站服务端
浏览器会做的事:发请求、加载资源、渲染页面、保存 Cookie。
爬虫做的事:模拟请求、获取数据、解析内容、持久化保存。
2. 爬虫两大核心场景
静态页面爬虫:数据直接写在 HTML 源码中,requests 直接可抓
动态 JS 爬虫:页面空白,数据通过 Ajax/fetch 接口异步加载,需要抓接口或渲染页面
3. 爬虫必备核心组件
• 请求库:requests(静态)、selenium/playwright(动态)
• 解析库:BeautifulSoup、lxml-XPath、json
• 并发工具:线程池、异步 aiohttp
• 反爬组件:请求头、Cookie、延时、代理 IP、随机 UA
• 存储组件:文件、JSON、CSV、数据库
二、爬虫基础:HTTP 协议核心必懂知识点
1. 常用请求方式
GET:获取数据,参数拼接在 URL 中,无请求体
POST:提交数据,参数放在请求体,常用于登录、提交表单、接口查询
2. 常见状态码
• 200:请求成功
• 301/302:永久/临时重定向
• 403:权限不足、被反爬拦截
• 404:页面不存在
• 500:服务器报错
3. 请求头 Headers(反爬核心)
网站通过 Headers 判断访问者是不是真实浏览器。裸请求 99% 会被拦截。
最核心三个参数:
• User-Agent:标识浏览器身份
• Referer:标识来源页面
• Cookie:用户登录态、身份凭证
三、第一个爬虫:零基础入门 GET/POST 请求
先安装必备库:
pip install requests beautifulsoup4 lxml
1. 基础 GET 请求(带请求头、防拦截)
新建 spider_get_demo.py
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" } def main(): url = "https://httpbin.org/get" resp = requests.get(url, headers=HEADERS, timeout=10) # 状态码判断 if resp.status_code == 200: print("请求成功!") print(resp.text) else: print("请求失败,状态码:", resp.status_code) if __name__ == "__main__": main()
2. 基础 POST 请求(传参)
新建spider_post_demo.py
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" } def main(): url = "https://httpbin.org/post" data = { "username": "test_user", "password": "123456" } resp = requests.post(url, json=data, headers=HEADERS, timeout=10) print(resp.json()) if __name__ == "__main__": main()
3. 关键知识点:超时与异常捕获
爬虫必须加异常捕获,否则网络波动、超时、服务器报错会直接终止程序。
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" } def safe_request(url): try: resp = requests.get(url, headers=HEADERS, timeout=8) resp.encoding = resp.apparent_encoding # 自动处理乱码 return resp except requests.exceptions.Timeout: print("请求超时") except requests.exceptions.ConnectionError: print("网络连接失败") except Exception as e: print("未知错误:", e) return None
四、数据解析:BS4 + XPath 两大核心技能
发请求只是第一步,精准提取数据才是爬虫核心。
1. BeautifulSoup 解析 HTML
from bs4 import BeautifulSoup 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" } url = "https://httpbin.org/html" resp = requests.get(url, headers=HEADERS) soup = BeautifulSoup(resp.text, "lxml") # 提取标题 title = soup.title.string print("页面标题:", title) # 查找所有 p 标签 p_list = soup.find_all("p") for p in p_list: print(p.get_text(strip=True))
2. XPath 精准解析(更适合复杂页面)
XPath 定位更快、更精准,企业爬虫首选。
from lxml import etree 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" } url = "https://httpbin.org/html" resp = requests.get(url, headers=HEADERS) tree = etree.HTML(resp.text) # XPath 提取文本 text_list = tree.xpath("//p/text()") for text in text_list: print(text.strip())
五、爬虫最容易踩的 6 个坑(新手必看)
1. 不加 User-Agent,直接裸请求
大部分网站直接拦截空 UA 请求,必须模拟浏览器。
2. 不做延时,高频请求直接封 IP
循环爬取不加 time.sleep(),几秒就触发反爬。
3. 页面乱码不处理
统一使用 resp.encoding = resp.apparent_encoding 自动适配编码。
4. 不捕获异常,程序极易崩溃
网络波动、404、超时都会导致程序终止,必须 try-except。
5. 分不清静态页面和动态页面
源码看不到数据 = JS 动态渲染,requests 无法直接抓取,需要抓接口或无头浏览器。
6. 一次性爬取大量数据不做分批保存
内存溢出、数据丢失,必须边爬边存。
六、进阶优化:延时、随机 UA、请求稳定性
1. 随机请求头 + 延时休眠
import time import random import requests UA_LIST = [ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/118.0.0.0 Safari/537.36", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Chrome/119.0.0.0 Safari/537.36", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Firefox/119.0 Gecko/20100101 Firefox/119.0" ] def get_random_headers(): return { "User-Agent": random.choice(UA_LIST) } # 随机延时 0.5~1.5 秒 time.sleep(random.uniform(0.5, 1.5))
七、并发爬虫:多线程大幅提升爬取速度
单线程爬虫速度极慢,IO 密集型的爬虫最适合多线程并发。
使用线程池,可控并发,不会炸机、不会封IP。
import time import random import requests from concurrent.futures import ThreadPoolExecutor UA_LIST = [ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/118.0.0.0 Safari/537.36", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Chrome/119.0.0.0 Safari/537.36" ] def spider_task(url): headers = {"User-Agent": random.choice(UA_LIST)} try: resp = requests.get(url, headers=headers, timeout=8) print(f"成功抓取:{url} 状态码:{resp.status_code}") except Exception as e: print(f"抓取失败 {url}:{e}") def main(): url_list = [ "https://httpbin.org/get?p=1", "https://httpbin.org/get?p=2", "https://httpbin.org/get?p=3", "https://httpbin.org/get?p=4", ] # 最大并发 5 with ThreadPoolExecutor(max_workers=5) as pool: pool.map(spider_task, url_list) if __name__ == "__main__": main()
八、综合实战:可直接运行的全站图片爬虫项目
整合请求、解析、并发、延时、异常处理、文件保存,完成工业级简易图片爬虫。
功能:自动抓取页面所有图片链接,批量下载,本地保存,自动去重。
import os import time import random import requests from lxml import etree from concurrent.futures import ThreadPoolExecutor # 配置 SAVE_DIR = "spider_images" MAX_WORKERS = 8 UA_LIST = [ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0 Safari/537.36" ] # 创建保存文件夹 if not os.path.exists(SAVE_DIR): os.makedirs(SAVE_DIR) def get_headers(): return {"User-Agent": random.choice(UA_LIST)} # 下载单张图片 def download_img(src): time.sleep(random.uniform(0.3, 0.8)) try: resp = requests.get(src, headers=get_headers(), timeout=10) if resp.status_code == 200: # 提取文件名 filename = src.split("/")[-1] path = os.path.join(SAVE_DIR, filename) with open(path, "wb") as f: f.write(resp.content) print("下载成功:", filename) except Exception as e: print("图片下载失败:", src, e) # 抓取页面所有图片 def crawl_img_urls(url): try: resp = requests.get(url, headers=get_headers(), timeout=10) tree = etree.HTML(resp.text) img_src_list = tree.xpath("//img/@src") # 简单过滤有效链接 valid_list = [src for src in img_src_list if src.startswith("http")] return valid_list except Exception as e: print("页面抓取失败:", e) return [] def main(): target_url = "https://httpbin.org/html" img_list = crawl_img_urls(target_url) print(f"共获取图片数量:{len(img_list)}") # 并发下载 with ThreadPoolExecutor(max_workers=MAX_WORKERS) as pool: pool.map(download_img, img_list) print("全部下载完成!") if __name__ == "__main__": main()
九、爬虫进阶方向总结
学完本文基础实战后,你可以继续进阶:
1. 动态爬虫:Selenium / Playwright 渲染 JS 页面
2. 接口抓包:Fiddler/Charles 抓取 Ajax 加密接口
3. 代理池搭建:解决 IP 封禁问题
4. 异步爬虫:aiohttp 极致提速
5. 数据持久化:CSV/MySQL/MongoDB 批量存储
6. 加密参数破解:Header、Token、Sign 加密逆向
写在最后
爬虫不是“黑科技”,本质就是模拟人工访问、自动化数据采集。
从最基础的 requests 请求、页面解析,到异常处理、延时防爬、多线程并发,再到完整实战项目,本文已经覆盖了 Python 爬虫 入门到进阶 80% 的核心能力。
掌握这套体系,你可以独立完成:素材采集、数据分析、行业数据抓取、个人项目数据集制作等各类需求。



