写好 README 和注释:让你的爬虫代码不再是一次性的
2026/7/9 11:43:11
网站开发
很多开发者写爬虫时都有过类似经历花半天时间调通请求、破解反爬、写完解析逻辑跑通导出数据后就把代码丢在一边。等到几个月后目标网站改版、需要新增字段或者换环境重跑时打开项目却一脸茫然 —— 入口文件是哪个配置里的加密参数是干嘛的这段奇奇怪怪的兼容逻辑当初是为了绕开什么坑最终只能推倒重写代码彻底沦为 “一次性脚本”。爬虫项目天然依赖外部网站结构、反爬策略和运行环境可维护性本就弱于普通业务代码。而一份规范的 README 和高质量的代码注释正是破解 “一次性爬虫” 的核心手段。前期花 10% 的时间做好文档后期能节省 90% 的维护成本。一、为什么爬虫代码特别容易变成 “一次性资产”相比常规后端或前端项目爬虫的可维护性天生更差核心有三点原因强外部依赖爬取逻辑完全绑定目标网站的 DOM 结构、接口参数和反爬规则网站一次改版就能让整套解析逻辑失效没有文档的话连改哪里都找不到。环境碎片化从请求库、解析库到浏览器驱动、验证码识别工具、代理服务依赖零散且版本敏感换台机器经常报一堆错却没人知道该装什么版本。重实现轻规范多数爬虫以 “跑通拿到数据” 为目标开发时优先堆功能注释和文档全靠 “脑子记”但爬虫里的反爬 trick、参数加密、异常兼容都是强经验属性时间一长必然遗忘。本质上缺少标准化文档的爬虫不是可复用的项目只是一次性的临时脚本。二、一份合格的爬虫 README该写些什么README 是项目的 “使用说明书”对爬虫项目而言它的核心目标是让一个完全没接触过这个项目的人照着文档就能把项目跑起来、改得动、出了问题能排查。一份完整的爬虫 README建议包含以下 8 个模块1. 项目概述与适用范围开门见山说明项目价值和边界避免后续维护者搞错用途。明确爬取的目标站点、数据类型商品信息、新闻、评论等和业务用途注明适配的页面版本 / 上线时间提醒 “目标网站改版后可能失效”说明不支持的场景比如 “仅适配 PC 端网页不包含 APP 接口”2. 环境与依赖说明这是爬虫项目最容易踩坑的部分必须写细。运行环境要求Python 版本、操作系统兼容性、是否需要图形界面Selenium 类爬虫第三方依赖列出核心库及推荐版本同时提供requirements.txt注明 “建议使用虚拟环境安装”特殊依赖说明ChromeDriver/GeckoDriver 的对应版本、OCR 工具、验证码识别服务、代理客户端等非 pip 安装的依赖权限要求是否需要配置 Hosts、是否需要企业内网环境等3. 快速开始从 0 到运行的完整步骤给出可直接复制执行的命令降低上手门槛。安装依赖的完整命令配置文件的复制与修改步骤比如复制config.example.py为config.py启动命令与入口文件附带最简运行示例首次运行的预期输出说明怎么判断跑成功了4. 配置项详解爬虫的可配置项非常多只放代码里别人根本不知道每个参数是干嘛的。请求配置并发数、请求间隔、超时重试次数、UA 轮换规则、请求头默认值身份配置Cookie/Token 的获取方式、有效期、更新入口账号密码的配置位置代理配置代理池地址、代理格式、失败重试策略、是否支持断点续爬存储配置输出文件路径 / 格式、数据库连接信息、数据表字段说明5. 爬取逻辑与数据说明让维护者不用读完整套代码也能知道数据是怎么来的。整体爬取流程例如 “分类列表页→商品详情页→评论分页→数据清洗→写入 MySQL”核心字段说明列出主要输出字段的含义、来源页面、是否做了清洗转换爬取量级与耗时参考比如 “全量爬取约 10 万条数据单 IP 耗时约 8 小时”6. 反爬与异常处理说明爬虫里最有价值的经验往往都在反爬和异常处理里。已适配的反爬措施UA 轮换、IP 代理池、滑块验证绕过、请求签名生成、无头浏览器指纹伪装等常见异常触发场景IP 封禁、验证码弹出、页面结构变化、接口限流降级与兜底逻辑比如 “详情页请求失败 3 次后跳过记录到失败日志”断点续爬的实现方式是否支持中断后从上次位置继续7. 维护记录与已知问题让后续维护者知道项目的迭代历史和遗留坑点。版本更新日志每次改版对应的修改点、适配的网站版本已知问题比如 “部分冷门分类页结构不一致暂未适配”待优化项后续可以改进的方向8. 常见问题FAQ把踩过的坑沉淀下来避免后人重复踩。运行报错的高频排查步骤爬取数据为空的定位方法触发反爬后的应急处理方案三、代码注释写在点子上而非写满屏好的注释不是越多越好而是在关键位置说清 “为什么这么写”。爬虫代码有大量业务特有的逻辑和踩坑经验这些才是注释的核心价值。3.1 三层注释体系覆盖不同粒度1. 文件级头部注释每个爬虫脚本的开头都应该有一段总览注释说明这个文件的核心作用。python运行# -*- coding: utf-8 -*- 商品详情页爬虫脚本 功能根据商品ID列表批量爬取商品基础信息与价格数据 创建时间2026-01-15 最后更新2026-05-20 适配页面xxx商城PC端商品详情页 v202604版 依赖requests 2.31.0, lxml 4.9.3 注意商品价格接口需携带sign签名签名规则见函数get_request_sign 2. 函数 / 类级注释Docstring核心函数必须写清功能、入参、返回值和注意事项推荐遵循 Google 风格或 NumPy 风格。python运行def parse_goods_detail(html_text): 解析商品详情页HTML提取结构化数据 Args: html_text: 商品详情页的HTML文本字符串 Returns: dict: 包含商品ID、标题、价格、库存等字段的字典 字段解析失败时对应值为None不会抛出异常 Notes: 价格字段位于script标签内的JSON数据中不在DOM节点直接展示 对应页面class: .goods-info 模块 3. 行内关键逻辑注释只注释 “代码本身读不出来的信息”解释原因而非复述代码。错误示范# 发送get请求废话看代码就知道正确示范# 增加2秒随机延时绕过列表页频率检测3.2 爬虫代码里必须加注释的 7 个位置加密 / 签名参数生成逻辑说明参数来源、加密算法、对应网站的校验规则这是爬虫里最容易忘的部分。DOM 解析规则标注对应的页面区域和节点特征网站改版时能快速定位修改位置。反爬绕过逻辑说明这段代码是为了绕过什么检测比如 “添加 navigator.webdriver 覆盖绕过无头浏览器识别”。异常捕获分支说明为什么捕获这个异常对应的业务场景是什么。数据清洗规则解释字段的处理逻辑比如 “去除价格中的 ¥ 符号和千分位逗号统一转为单位为元的浮点数”。限速 / 延时逻辑说明限速的依据比如 “详情页限速 1 秒 / 次实测该阈值下不会触发验证码”。临时兼容逻辑标注临时方案的原因和移除条件比如 “临时兼容旧版页面结构2026 年 6 月全站改版后可删除”。3.3 避开这些注释误区废话注释对一眼就能看懂的代码做字面解释纯属于冗余。留存废弃代码不要用注释把不用的代码包起来留着版本管理工具会帮你记录历史。只写实现不写原因爬虫里很多写法是踩坑踩出来的不写原因下次自己都不敢改。代码更新注释不动修改逻辑后忘记同步注释错误的注释比没有注释更害人。四、实战规范的爬虫代码与 README 模板4.1 带规范注释的爬虫示例python运行# -*- coding: utf-8 -*- xxx商城商品列表爬虫 功能按分类爬取商品基础信息输出为CSV文件 创建时间2026-03-10 最后更新2026-06-18 适配站点xxx商城PC端分类列表页 注意分类接口携带加密参数timestampsign签名规则为MD5(timestampsecret_key) import time import hashlib import requests from lxml import etree import csv # 配置区 BASE_URL https://example.com/api/goods/list SECRET_KEY your_secret_key_here REQUEST_INTERVAL 2 # 请求间隔2秒实测为不触发限流的临界值 DEFAULT_HEADERS { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 ..., Referer: https://example.com/category # 必须携带否则接口返回403 } def generate_sign(timestamp): 生成接口请求签名 签名规则将时间戳与固定密钥拼接后做MD5加密对应后端校验逻辑 Args: timestamp: 10位时间戳字符串 Returns: str: 32位小写MD5签名值 raw f{timestamp}{SECRET_KEY} return hashlib.md5(raw.encode(utf-8)).hexdigest() def fetch_goods_list(category_id, page): 获取指定分类、指定页码的商品列表数据 Args: category_id: 分类ID page: 页码从1开始 Returns: list: 商品字典列表请求失败返回空列表 timestamp str(int(time.time())) params { category_id: category_id, page: page, page_size: 20, timestamp: timestamp, sign: generate_sign(timestamp) } try: resp requests.get(BASE_URL, paramsparams, headersDEFAULT_HEADERS, timeout10) resp.raise_for_status() data resp.json() return data.get(data, {}).get(list, []) except requests.exceptions.RequestException as e: # 网络异常或接口报错时返回空不中断整体爬取失败信息可在日志中排查 print(f第{page}页请求失败: {e}) return [] def save_to_csv(goods_list, output_path): 将商品数据写入CSV文件 Args: goods_list: 商品数据列表 output_path: 输出文件路径 fields [goods_id, title, price, sales, shop_name] with open(output_path, w, newline, encodingutf-8-sig) as f: writer csv.DictWriter(f, fieldnamesfields) writer.writeheader() writer.writerows(goods_list) def main(category_id, max_page, output_path): 主爬取流程循环翻页爬取最终保存为CSV Args: category_id: 目标分类ID max_page: 最大爬取页数 output_path: 结果输出路径 all_goods [] for page in range(1, max_page 1): print(f正在爬取第 {page}/{max_page} 页) goods fetch_goods_list(category_id, page) if not goods: break all_goods.extend(goods) time.sleep(REQUEST_INTERVAL) save_to_csv(all_goods, output_path) print(f爬取完成共获取 {len(all_goods)} 条商品数据) if __name__ __main__: main(category_id1001, max_page10, output_path./goods_result.csv)4.2 通用爬虫 README 模板markdown# 项目名称xxx商城商品爬虫 ## 项目概述 - 目标站点xxx商城 PC 端 - 爬取内容分类下商品基础信息ID、标题、价格、销量、店铺名 - 业务用途竞品价格监控数据采集 - 适配版本2026年4月页面改版后接口 ## 环境依赖 - Python 3.9 - 核心依赖 - requests2.31.0 - lxml4.9.3 - 安装命令 bash pip install -r requirements.txt快速开始复制config.example.py为config.py填入你的SECRET_KEY运行入口脚本bash运行python goods_spider.py结果默认输出到./output/goods_result.csv配置说明表格配置项说明默认值SECRET_KEY接口签名密钥无需自行配置REQUEST_INTERVAL单页请求间隔秒2MAX_PAGE最大爬取页数10OUTPUT_PATH结果输出路径./output/爬取逻辑按分类 ID 调用商品列表接口分页循环爬取接口请求携带 timestamp sign 签名签名规则为 MD5 (timestamp secret_key)单页请求失败自动跳过不中断整体任务爬取完成后统一写入 CSV 文件反爬说明已适配请求头 Referer 校验、接口签名校验、请求频率限制注意事项请求间隔低于 1 秒大概率触发 IP 限流单日单 IP 爬取量建议不超过 5 万条否则可能触发验证码维护记录v1.2 2026-06-18适配新版接口签名规则v1.1 2026-04-25新增失败重试机制优化输出字段v1.0 2026-03-10初始版本支持基础商品列表爬取常见问题接口返回 403检查 Referer 是否正确SECRET_KEY 是否过期输出数据为空确认分类 ID 是否有效页面是否改版频繁请求失败调大 REQUEST_INTERVAL或配置代理 IP五、让文档持续生效的几个习惯 文档和注释不是写完就一劳永逸需要跟着项目一起迭代。 1. **代码变更文档同步**改了解析规则、换了签名算法、加了新配置项顺手更新README和对应注释。 2. **踩过的坑立刻沉淀**每次排查完问题把原因和解决方案加到FAQ里下次直接复用。 3. **日志与注释互补**运行时的状态、错误信息用日志输出设计层面的逻辑、踩坑经验用注释说明。 4. **模块化拆分配合文档**把请求、解析、存储、反爬拆分成独立模块每个模块单独维护注释整体结构更清晰。 爬虫从来都不是一锤子买卖的“跑通就行”。一份清晰的README和精准的注释本质上是把你的开发经验沉淀成了可复用的资产。当下次再打开这个项目时你不用再对着一堆裸代码逆向推理自己当初的思路也不用再因为一点点改动就推翻重写——这才是工程化写爬虫的意义。