Python 爬虫项目:基础反爬绕过实战
前言随着网络站点防护体系逐步完善绝大多数网站都会部署基础反爬机制通过识别请求特征、访问行为区分正常浏览器用户与爬虫程序。未经反爬处理的爬虫极易出现请求拦截、页面返回空白、验证码弹窗、IP 封禁等问题导致采集任务中断。基础反爬是爬虫开发中最先接触、也是出现频率最高的防护手段主要针对客户端标识、访问频率、请求格式、会话状态等维度做校验。本文结合工程实战场景系统性讲解主流基础反爬类型、识别特征、绕过思路与代码实现依托前文已封装的请求、解析、循环爬虫模块做改造升级形成一套通用、可复用的反爬解决方案。本文使用的技术库官方链接 Python 官方下载地址、requests 库官方文档、BeautifulSoup4 官方文档、time 标准库文档、random 标准库文档全文从反爬原理入手逐个拆解UA 校验、访问频率限制、Cookie 校验、Referer 校验、简单验证码五大基础反爬场景搭配完整代码、调试技巧、优劣分析与落地建议兼顾零基础上手与项目工程化使用。一、基础反爬整体认知与分类1.1 反爬核心原理网站服务端接收请求后会提取请求头、请求间隔、IP 地址、会话信息等数据与正常用户访问行为做比对。当请求特征偏离正常浏览行为时判定为爬虫并执行拦截策略常见拦截动作返回错误页面、返回空白数据、弹出验证码、临时限制访问、永久封禁 IP。基础反爬仅做规则匹配不涉及设备指纹、行为轨迹、加密参数等高阶防护绕过难度低、方案通用是爬虫必备基础能力。1.2 主流基础反爬分类表格反爬类型识别依据典型现象核心绕过思路User-Agent 校验检测请求头中的客户端标识直接返回 403、空白页面、提示禁止访问伪造浏览器 UA补齐完整请求头访问频率限制统计单 IP 单位时间请求次数短时可访问连续请求后拦截随机延时、模拟人工浏览节奏Referer 校验检测请求来源页面地址图片、内容加载失败页面残缺伪造来源链接 Referer 字段Cookie 会话校验检测登录态、会话 Cookie游客权限受限无法查看完整内容携带有效 Cookie、维持会话图形验证码人机身份校验访问指定页面弹出验证码手动输入识别、简易第三方识别接口1.3 前置公共模块复用沿用前文通用工具函数后续所有反爬改造均基于以下基础代码不再重复编写底层逻辑python运行import requests import time import random from bs4 import BeautifulSoup import chardet import re import html # 编码转换 def decode_response(resp) - str: raw_bytes resp.content detect_res chardet.detect(raw_bytes) encode detect_res.get(encoding, utf-8) try: return raw_bytes.decode(encode) except UnicodeDecodeError: return raw_bytes.decode(utf-8, errorsignore) # 文本清洗 def clean_text(text: str) - str: text html.unescape(text) text re.sub(r[\n\r\t], , text) text re.sub(r[ ], , text) return text.strip()二、场景一User-Agent 反爬绕过2.1 反爬原理User-Agent简称 UA是请求头核心字段用于标识客户端类型、浏览器版本、操作系统等信息。Pythonrequests库默认 UA 为python-requests/xxx服务器识别到该标识后直接判定为爬虫并拒绝访问返回403 Forbidden。2.2 识别方式爬虫直接请求返回 403、空白 HTML、提示 “禁止机器人访问”浏览器正常访问页面内容加载正常。2.3 解决方案伪造浏览器 UA2.3.1 单 UA 固定配置基础方案抓取主流浏览器真实 UA写入请求头模拟正常客户端访问python运行def get_page_with_ua(url: str, timeout: int 10): # 伪造Chrome浏览器UA及完整请求头 headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36, Accept: text/html,application/xhtmlxml,application/xml;q0.9,image/webp,*/*;q0.8, Accept-Language: zh-CN,zh;q0.9 } try: resp requests.get(url, headersheaders, timeouttimeout) resp.raise_for_status() return resp, 请求成功 except Exception as e: return None, f请求失败{str(e)} # 测试调用 if __name__ __main__: test_url https://www.example.com res, msg get_page_with_ua(test_url) if res: print(decode_response(res)[:500])2.3.2 UA 池随机切换进阶方案单一 UA 长时间高频访问仍有被识别风险搭建UA 池每次请求随机选取 UA模拟多设备访问python运行# 主流浏览器UA池 UA_LIST [ Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/124.0.0.0 Safari/537.36, Mozilla/5.0 (Windows NT 10.0; Win64; x64) Firefox/125.0 Safari/537.36, Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Chrome/124.0.0.0 Safari/537.36, Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 Safari/605.1.15 ] def get_page_random_ua(url: str, timeout: int 10): # 随机选取UA headers {User-Agent: random.choice(UA_LIST)} try: resp requests.get(url, headersheaders, timeouttimeout) resp.raise_for_status() return resp, 请求成功 except Exception as e: return None, str(e) # 循环爬虫中使用每次请求自动切换UA for i in range(5): resp, _ get_page_random_ua(https://www.example.com) print(f第{i1}次请求状态{resp.status_code if resp else 失败}) time.sleep(1)2.4 方案优劣与使用建议固定 UA代码简单适合小型站点、低频采集任务UA 池随机切换伪装效果更强适合多页循环爬虫、长时间运行任务补充技巧优先使用 Chrome、Firefox 主流浏览器 UA避免小众客户端标识。三、场景二访问频率限制反爬绕过3.1 反爬原理服务器监控单 IP 的请求频次短时间内大量连续请求判定为爬虫行为。限制策略分为临时拦截几分钟几小时、永久封禁 IP 两种。该反爬不校验请求头单纯依靠访问行为判断。3.2 识别方式初始请求正常连续访问数个页面后突然返回空白、403、访问受限提示。3.3 解决方案随机延时休眠人工浏览页面存在自然停顿爬虫需要模拟该行为在两次请求之间添加随机时间间隔避免固定周期请求。3.3.1 基础固定延时适用于防护较弱的站点设置固定休眠时长python运行def crawl_simple_delay(url_list: list, delay: float 2): for url in url_list: resp, _ get_page_with_ua(url) if resp: print(f成功采集{url}) # 固定延时 time.sleep(delay) # 调用示例 urls [https://www.example.com/1, https://www.example.com/2, https://www.example.com/3] crawl_simple_delay(urls)3.3.2 随机区间延时推荐使用random.uniform()生成区间随机秒数模拟人工不规则停顿伪装效果最优python运行def crawl_random_delay(url_list: list, min_sleep: float 1, max_sleep: float 3): for url in url_list: resp, _ get_page_with_ua(url) if resp: print(f成功采集{url}) # 随机延时1 ~ 3 秒 sleep_time random.uniform(min_sleep, max_sleep) time.sleep(sleep_time) print(f本次休眠{sleep_time:.2f} 秒) # 调用示例 crawl_random_delay(urls)3.4 进阶组合UA 随机延时工业级爬虫标配组合同时规避 UA 校验与频率限制两大基础反爬python运行def crawl_base_anti_spider(url_list: list): UA_LIST [ Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/124.0.0.0 Safari/537.36, Mozilla/5.0 (Windows NT 10.0; Win64; x64) Firefox/125.0 Safari/537.36 ] for url in url_list: headers {User-Agent: random.choice(UA_LIST)} resp requests.get(url, headersheaders, timeout10) print(f页面状态码{resp.status_code}) # 随机延时 time.sleep(random.uniform(1.2, 2.8)) # 综合使用 target_urls [fhttps://www.example.com/list?page{i} for i in range(1, 6)] crawl_base_anti_spider(target_urls)3.5 使用建议普通站点随机延时 1~3 秒中等防护站点随机延时 3~5 秒高防护站点延长至 5~8 秒降低整体爬取速度换取稳定性。四、场景三Referer 反爬绕过4.1 反爬原理Referer记录当前请求的来源页面地址。正常用户点击链接跳转时浏览器会自动携带上一级页面 URL爬虫直接发起请求无来源地址服务器以此识别并拦截图片、静态资源、正文内容。4.2 识别方式页面文字可加载但图片、视频、部分内容显示加载失败、裂图。4.3 解决方案伪造 Referer 请求头根据站点规则填入网站首页、列表页等合法来源地址python运行def get_page_with_referer(url: str): headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/124.0.0.0 Safari/537.36, # 伪造来源页面目标网站首页 Referer: https://www.example.com } resp requests.get(url, headersheaders, timeout10) return resp # 测试访问内容页 content_url https://www.example.com/article/1001 res get_page_with_referer(content_url) html decode_response(res) print(html[:600])4.4 动态 Referer 适配多级跳转场景下Referer 需要跟随上一页地址动态变化适配分页爬虫python运行def crawl_dynamic_referer(page_url_list: list): # 初始来源为网站首页 referer https://www.example.com for url in page_url_list: headers { User-Agent: random.choice(UA_LIST), Referer: referer } resp requests.get(url, headersheaders) print(f采集完成{url}) # 更新下一次请求的来源为当前页面 referer url time.sleep(random.uniform(1, 2))五、场景四Cookie 会话反爬绕过5.1 反爬原理部分网站区分游客权限与登录用户权限游客只能查看部分内容完整数据、分页内容需要登录。服务器通过Cookie识别登录会话爬虫未携带有效 Cookie 时权限受限。分为两种类型临时会话 Cookie、登录态 Cookie。5.2 方案一携带临时会话 Cookie使用requests.Session()创建会话对象自动保存、传递 Cookie模拟浏览器会话状态python运行def crawl_with_session(url_list: list): # 创建会话自动管理Cookie session requests.Session() headers {User-Agent: Mozilla/5.0 Chrome/124.0.0.0 Safari/537.36} # 先访问首页获取服务器下发的临时Cookie session.get(https://www.example.com, headersheaders) # 后续请求自动携带Cookie for url in url_list: resp session.get(url, headersheaders) print(f状态码{resp.status_code}) time.sleep(random.uniform(1.5, 3)) # 调用 page_urls [fhttps://www.example.com/list?page{p} for p in range(1, 4)] crawl_with_session(page_urls)5.3 方案二手动填入登录 Cookie需要登录才能访问的站点手动从浏览器提取登录后的完整 Cookie写入请求头浏览器登录目标网站F12 开发者工具 → 网络 → 刷新页面复制请求头中的 Cookie将 Cookie 字符串配置到代码中。python运行def get_page_with_login_cookie(url: str): headers { User-Agent: Mozilla/5.0 Chrome/124.0.0.0 Safari/537.36, # 手动粘贴浏览器登录后的Cookie Cookie: xxx_sessionabc123; tokenxyz789; user_id10086 } resp requests.get(url, headersheaders, timeout10) return resp5.4 关键说明Session会话适合短期采集Cookie 过期后失效手动 Cookie 有效期由网站规则决定定期重新抓取替换即可禁止共享登录 Cookie遵守网站用户协议。六、场景五简单图形验证码绕过6.1 反爬原理当 IP 访问频次过高、请求行为异常时网站弹出简单图形验证码要求人工验证后才能继续访问阻断自动化爬虫。此类验证码字符清晰、无扭曲、无干扰线属于最基础的人机校验。6.2 方案一手动输入验证码临时方案适用于少量任务、测试场景程序暂停运行人工查看图片并输入验证码python运行def crawl_with_verify_code(page_url: str): session requests.Session() headers {User-Agent: random.choice(UA_LIST)} # 访问页面触发验证码 resp session.get(page_url, headersheaders) if 验证码 in resp.text: print(页面弹出验证码请手动完成验证后回车继续...) input() # 程序阻塞等待人工操作 # 重新请求页面 resp session.get(page_url, headersheaders) print(decode_response(resp)[:500])6.3 方案二本地简易识别入门针对纯数字、纯字母简单验证码可结合开源识别库做自动识别本文仅做思路演示复杂验证码不适用。6.4 避坑建议基础图形验证码仅作为临时防护大规模采集不建议硬解。最优方案降低爬取速度、增加延时从源头避免触发验证码。七、综合实战全基础反爬整合爬虫整合 UA 池、随机延时、Referer、Session 会话四大核心绕过方案打造通用型基础反爬爬虫可直接用于绝大多数中小型网站python运行import requests import random import time from bs4 import BeautifulSoup # UA池 UA_POOL [ Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/124.0.0.0 Safari/537.36, Mozilla/5.0 (Windows NT 10.0; Win64; x64) Firefox/125.0 Safari/537.36, Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Safari/605.1.15 ] # 综合反爬爬虫主函数 def full_base_anti_crawler(base_domain: str, page_list: list): # 创建会话自动管理Cookie session requests.Session() # 初始化来源页 referer_url base_domain # 预热会话获取初始Cookie init_headers { User-Agent: random.choice(UA_POOL), Referer: referer_url } session.get(base_domain, headersinit_headers, timeout10) all_data [] for idx, url in enumerate(page_list, 1): print(f正在采集第 {idx} 页{url}) # 动态请求头 headers { User-Agent: random.choice(UA_POOL), Referer: referer_url } try: resp session.get(url, headersheaders, timeout10) resp.raise_for_status() html decode_response(resp) soup BeautifulSoup(html, html.parser) # 自定义数据解析逻辑 title soup.find(h1).get_text(stripTrue) if soup.find(h1) else 无标题 all_data.append({url: url, title: title}) # 更新下一页Referer referer_url url except Exception as e: print(f第 {idx} 页采集失败{str(e)}) # 随机延时 1~4 秒 time.sleep(random.uniform(1, 4)) return all_data # 测试运行 if __name__ __main__: domain https://www.example.com pages [f{domain}/list?page{i} for i in range(1, 6)] result full_base_anti_crawler(domain, pages) for item in result: print(item)八、排查思路与通用优化准则8.1 反爬问题排查步骤优先检查状态码403 → UA/Referer 缺失429 / 频繁拦截 → 访问频率过高页面内容残缺 → 补充 Referer 头有权限限制 → 使用 Session 或手动配置登录 Cookie弹出验证码 → 加大随机延时降低爬取速率。8.2 通用优化准则最小请求原则非必要不高频请求延时设置宁长勿短请求头完整化除 UA、Referer 外补齐 Accept、Accept-Language 等字段高度模拟浏览器会话复用连续分页爬虫统一使用Session对象保持会话一致性定期更新 UA长期运行爬虫定期扩充 UA 池避免单一标识被标记。8.3 边界提醒本文讲解的均为基础反爬绕过方案仅适用于常规中小型网站。遇到参数加密、设备指纹、行为轨迹校验、滑块验证码等高阶反爬需要使用代理 IP、无头浏览器、验证码平台等进阶方案。