Python爬虫学习框架:从请求到入库的完整路线与避坑指南
简介这份PDF面向零基础到进阶的Python爬虫学习者系统梳理了从入门到实战的完整知识框架帮助初学者解决「学什么、怎么学、在哪里学」的困惑。内容围绕爬虫三部曲展开获取数据环节讲解urllib、requests、aiohttp等请求库及异步抓取思路解析数据环节对比pyquery、BeautifulSoup、XPath与正则的适用场景数据存储环节则涉及TXT、JSON、CSV及MySQL、MongoDB等方案并延伸至代理IP、请求头伪装、Selenium动态渲染与分布式爬虫等进阶技巧同时提醒Robots协议与合规边界。资源包共1个PDF文件大小约2.1MB便于随时查阅与打印。目前已有174人学习适合希望用一份文档建立完整爬虫知识体系、少走弯路的开发者参考。1. 一张爬虫学习地图从请求到入库到底该按什么顺序学很多人学 Python 爬虫第一反应是打开编辑器写requests.get()跑通了就觉得自己会了结果一遇到动态加载、登录校验、数据量上万就原地翻车。问题不在代码在于没有一张完整的学习地图。这份《2023年最新Python爬虫的完整学习框架》把整个方向拆成了四块请求库、解析库、存储方案、工程化框架。四块之间不是并列关系而是递进关系——先能拿到网页再能从网页里取出数据再把数据存下来最后用框架把整条链路工程化。轻量级爬虫和工程化爬虫的分界线就在第三步到第四步之间。如果你只是偶尔抓几十条数据做分析前三块够用如果你要面对海量页面、复杂反爬、分布式调度第四块绕不过去。这份笔记按这个顺序梳理每一块都落到具体库、具体参数、具体易错点适合正在系统学爬虫或者准备复习的人对照查漏补缺。2. 请求库选型urllib、requests、aiohttp 到底怎么选2.1 同步请求的两条路urllib 与 requestsPython 自带的urllib是内置的 HTTP 请求库不需要额外安装适合理解请求的底层结构。但它的 API 设计比较绕构造一个带参数的 GET 请求要拼接 URL、创建 Request 对象、再调用urlopen代码量大且可读性差。requests的口号是“为人类设计的 HTTP 库”同样的请求用requests写出来简洁得多而且自带 JSON 解析器处理返回的 JSON 数据不需要额外调json.loads()。import requests # 设置请求头模拟真实浏览器访问 headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36, Accept-Language: zh-CN,zh;q0.9, } # 带参数的 GET 请求params 会自动拼接到 URL resp requests.get( https://example.com/search, params{q: python, page: 1}, headersheaders, timeout10, # 超时设置避免无限等待 ) # 检查状态码非 200 直接抛异常 resp.raise_for_status() # 自动解析 JSON 响应 data resp.json() print(data)这段代码里几个参数值得注意headers中的User-Agent是最基本的反反爬手段很多网站会直接拒绝没有 UA 的请求timeout必须设否则遇到慢响应会一直挂住raise_for_status()帮你快速定位 4xx 和 5xx 错误。requests的文档和社区资源非常丰富遇到问题基本都能搜到答案。提示建议先从urllib开始学理解请求的构造过程再切换到requests提升开发效率。直接上requests容易知其然不知其所以然。2.2 异步请求aiohttp 与性能差距同步请求的瓶颈在于等待。每次请求都要等服务器响应回来才能发下一个100 次请求按每次 0.3 秒算至少 30 秒。异步请求可以在等待响应的间隙去发下一个请求同样的 100 次请求能压缩到 3 秒左右。aiohttp是 Python 异步请求的主流库配合async/await语法代码结构比回调风格清晰很多。import aiohttp import asyncio async def fetch(session, url): async with session.get(url, timeoutaiohttp.ClientTimeout(total10)) as resp: return await resp.text() async def main(urls): async with aiohttp.ClientSession() as session: tasks [fetch(session, url) for url in urls] results await asyncio.gather(*tasks) return results urls [fhttps://example.com/page/{i} for i in range(100)] results asyncio.run(main(urls))ClientSession是复用的核心不要在每次请求时都新建 session否则连接池的优势就没了。asyncio.gather把所有任务并发提交await等待全部完成。异步代码的调试比同步麻烦出错时堆栈信息不够直观建议先用少量 URL 验证逻辑再放大规模。2.3 动态页面与自动化Selenium 的适用边界有些页面内容不是直接写在 HTML 里的而是通过 JavaScript 异步加载后再渲染出来的。这时候requests拿到的源码里没有你要的数据需要浏览器抓包分析真实请求或者用Selenium驱动真实浏览器渲染页面后再提取。Selenium的优势是能模拟点击、滚动、输入等交互操作适合处理登录、翻页、懒加载等场景。代价是速度慢、资源占用高不适合大规模抓取。注意能用抓包分析真实 API 解决的就不要上 Selenium。Selenium 是最后的手段不是首选方案。3. 解析库对比正则、BeautifulSoup、PyQuery、XPath 各自的主场3.1 四种解析方式的定位差异拿到网页源码之后下一步是从 HTML 或 JSON 中提取目标数据。原文提到了四种主流方式正则表达式、BeautifulSoup、PyQuery、XPath。它们不是互相替代的关系而是各有适用场景。解析方式核心优势适用场景学习曲线正则 re速度最快不依赖 HTML 结构提取格式固定的文本片段较高正则语法容易写错BeautifulSoup容错性强自动修正不规范 HTML结构混乱的页面低API 直观PyQueryjQuery 语法CSS 选择器前端基础好的人低有 jQuery 经验几乎零成本XPath函数丰富支持复杂条件嵌套深、需要精确定位中等语法需要记原文的建议是前端基础扎实的用 PyQuery 最方便BeautifulSoup 也不错正则速度最快但写起来麻烦。这个判断是合理的。实际项目中常见组合是requests BeautifulSoup做快速原型Scrapy XPath做工程化抓取。3.2 BeautifulSoup 的解析器选择BeautifulSoup 本身不解析 HTML它依赖外部解析器。Python 标准库自带html.parser速度一般但不需要额外安装。lxml解析器速度更快、容错性更好是推荐选择。安装lxml后初始化时指定解析器即可。from bs4 import BeautifulSoup html htmlbody div classitem h2 classtitle示例标题/h2 span classprice¥99.00/span /div /body/html soup BeautifulSoup(html, lxml) # 按标签和 class 定位 title soup.find(h2, class_title).text price soup.find(span, class_price).text # 按 CSS 选择器定位返回列表 items soup.select(div.item) for item in items: print(item.select_one(.title).text)find返回第一个匹配元素find_all返回列表select支持 CSS 选择器语法。.text提取标签内的纯文本。注意class_带下划线是因为class是 Python 关键字。3.3 XPath 的核心语法与高频函数XPath 用路径表达式在 XML 和 HTML 文档中定位节点功能比 CSS 选择器更强。Scrapy 的response.xpath()返回的是选择器列表需要配合extract()或get()取出字符串。# 假设 response 是 Scrapy 的 Response 对象 # 提取所有 class 为 title 的 h2 文本 titles response.xpath(//h2[classtitle]/text()).getall() # 提取 href 属性 links response.xpath(//a/href).getall() # 使用 contains 做模糊匹配 items response.xpath(//div[contains(class, item)]) # 使用 position 取第一个 first response.xpath(//ul/li[1]/text()).get()//表示任意层级/表示直接子节点取属性text()取文本内容。contains()用于 class 名有多个值的情况position()用于取指定位置的元素。XPath 内置超过 100 个函数覆盖字符串处理、数值比较、日期时间等遇到复杂提取需求时先查函数列表往往有现成方案。提示解析库的选择没有绝对优劣关键看页面结构。结构规整用 CSS 选择器结构混乱用 BeautifulSoup 的容错需要复杂条件用 XPath格式固定的文本片段用正则。4. 数据存储从 TXT 到 Redis 的选型逻辑4.1 小数据量文件存储够用数据量在几千条以内时直接写文件是最省事的方案。TXT 适合纯文本CSV 适合表格型数据JSON 适合嵌套结构。Python 标准库的csv和json模块足够应付。import csv import json # 写入 CSV with open(data.csv, w, newline, encodingutf-8) as f: writer csv.DictWriter(f, fieldnames[title, price]) writer.writeheader() writer.writerow({title: 示例商品, price: 99.00}) # 写入 JSON Lines每行一个独立 JSON 对象 with open(data.jsonl, w, encodingutf-8) as f: for item in [{title: A, price: 10}, {title: B, price: 20}]: f.write(json.dumps(item, ensure_asciiFalse) \n)JSON Lines 格式比单个大 JSON 数组更适合爬虫场景因为可以逐行追加写入不需要一次性加载全部数据到内存。4.2 中等数据量MySQL 与 MongoDB 的分工数据量上万之后文件存储的查询和去重变得困难需要上数据库。MySQL 是关系型数据库的代表适合结构化程度高、字段固定的数据成熟度高、生态完善。MongoDB 是文档型数据库适合非结构化数据比如评论正文、图片链接、嵌套的 JSON 结构。原文提到 MongoDB 可以方便地存储非结构化数据并且可以通过PyMongo在 Python 中操作。from pymongo import MongoClient client MongoClient(mongodb://localhost:27017/) db client[spider_db] collection db[items] # 插入单条 collection.insert_one({title: 示例, price: 99.0, tags: [新品, 热卖]}) # 批量插入 collection.insert_many([ {title: 商品A, price: 10.0}, {title: 商品B, price: 20.0}, ]) # 按条件查询 results collection.find({price: {$gt: 15}}) for doc in results: print(doc[title])MongoDB 的$gt、$lt、$in等操作符支持灵活的查询条件。insert_many比逐条插入快得多批量操作是提升写入效率的关键。4.3 大规模与分布式Redis 的角色Redis 是内存数据库数据全部存在内存中访问速度极快。在爬虫场景中Redis 主要承担两个角色一是作为分布式爬虫的请求队列多个爬虫实例从同一个 Redis 队列中取 URL实现协同工作二是作为去重集合利用 Redis 的 Set 结构记录已抓取的 URL避免重复请求。原文提到 Redis 支持 hash、set、list 等丰富的数据结构一般应用于分布式爬虫的数据存储。import redis r redis.Redis(hostlocalhost, port6379, db0) # 用 Set 做 URL 去重 url https://example.com/page/1 if r.sadd(visited_urls, url): print(新 URL继续抓取) else: print(已抓取过跳过) # 用 List 做请求队列 r.lpush(url_queue, https://example.com/page/2) next_url r.rpop(url_queue)sadd返回 1 表示元素是新加入的返回 0 表示已存在。这个特性天然适合去重。lpush和rpop组合可以实现先进先出的队列。注意数据库知识在爬虫中的要求并不高核心就是入库和查询。不需要系统学完数据库再开始爬虫用到什么学什么即可。5. 工程化框架Scrapy、PySpider、Nutch 的定位与选择5.1 Scrapy最接近爬虫本质的框架Scrapy 是 GitHub 上 star 数最高的 Python 爬虫框架核心优势在于灵活的定制化爬取和模块化的架构。它把爬虫拆成 Spider、Item Pipeline、Downloader Middleware、Scheduler 等组件每个组件都可以独立替换和扩展。学会 Scrapy 之后基本具备爬虫工程师的思维。import scrapy class ExampleSpider(scrapy.Spider): name example start_urls [https://example.com/list] def parse(self, response): # 提取列表页中的详情页链接 for link in response.css(a.detail::attr(href)).getall(): yield response.follow(link, callbackself.parse_detail) # 翻页 next_page response.css(a.next::attr(href)).get() if next_page: yield response.follow(next_page, callbackself.parse) def parse_detail(self, response): yield { title: response.css(h1::text).get(), price: response.css(span.price::text).get(), }start_urls定义入口页面parse是默认的回调函数。response.follow会自动处理相对 URL 和域名拼接。yield返回的字典会进入 Item Pipeline可以在 Pipeline 中做清洗、去重、入库。Scrapy 的异步下载器基于 Twisted并发性能远超手写的同步爬虫。5.2 PySpider 与 Nutch 的差异化定位PySpider 的特点是提供了 Web UI可以在浏览器界面上编写脚本、调度任务、实时查看抓取结果。后端使用常用数据库存储结果。它的功能完整度更像一个产品而不是框架适合需要可视化管理和快速上手的场景。Nutch 是 Apache 顶级项目天生为搜索引擎设计支持分布式抓取有 Hadoop 支持可以进行多机分布抓取、存储和索引。它提供了插件框架方便扩展各种网页内容的解析和数据采集功能。原文的建议是先从 Scrapy 学起再去接触 PySpider最后了解 Nutch。这个顺序是合理的Scrapy 帮你建立爬虫的工程化思维PySpider 让你看到产品化的可能性Nutch 则是搜索引擎级别的解决方案学习成本最高。框架核心定位学习优先级适用场景Scrapy灵活定制化爬取最先学通用爬虫工程化PySpider产品级 WebUI其次需要可视化调度Nutch搜索引擎解决方案最后分布式大规模抓取5.3 从轻量级到工程化的能力跃迁轻量级爬虫和工程化爬虫的分界线不在于代码量而在于是否具备可维护、可扩展、可监控的能力。轻量级爬虫是脚本工程化爬虫是系统。Scrapy 的中间件机制让你可以统一处理请求头、代理、重试、异常Pipeline 机制让你可以统一处理数据清洗、去重、入库信号机制让你可以监控爬虫的运行状态。这些能力在脚本里需要自己实现在框架里是开箱即用的。提示不要为了用框架而用框架。如果目标只是抓几百条数据requests BeautifulSoup更快。框架的价值在规模化和可维护性上。6. 易漏点与易错点那些跑通之后才暴露的问题6.1 请求头缺失导致 403易漏点只写了requests.get(url)没有设置User-Agent。为什么漏本地测试时有些网站不校验 UA跑通了就以为没问题换一个网站就 403。怎么补养成习惯每次请求都带上完整的请求头至少包含User-Agent、Accept、Accept-Language。可以从浏览器开发者工具里复制真实请求头。6.2 编码问题导致乱码易漏点resp.text返回的文本出现乱码。为什么漏requests会根据响应头猜测编码但有些网站声明错误或缺失编码信息。怎么补手动指定编码resp.encoding utf-8或resp.encoding resp.apparent_encoding。BeautifulSoup 初始化时也可以指定from_encoding参数。6.3 动态加载内容抓不到易漏点requests拿到的 HTML 里没有目标数据。为什么漏数据是通过 JavaScript 异步加载的不在初始 HTML 中。怎么补打开浏览器开发者工具的 Network 面板筛选 XHR/Fetch 请求找到真实的数据接口直接请求接口。如果接口有加密参数再考虑 Selenium。6.4 数据库连接未关闭易漏点爬虫跑完后数据库连接没有释放。为什么漏脚本运行时间短问题不明显长时间运行后连接数耗尽。怎么补使用上下文管理器或try/finally确保连接关闭。MongoDB 的MongoClient内部有连接池通常不需要手动关闭但 MySQL 连接必须显式关闭。6.5 忽略 Robots 协议易漏点没有检查目标网站的robots.txt。为什么漏觉得“我只是抓一点点没关系”。怎么补爬取前先访问https://目标网站/robots.txt查看Disallow规则。Robots 协议是爬虫的规矩遵守它既是法律要求也是道德底线。原文明确提到“无规矩不成方圆Robots 协议就是爬虫中的规矩”。7. 复习清单从请求到入库的查漏补缺路线复习爬虫知识最怕的是东看一眼西看一眼没有主线。我自己的习惯是按“请求 → 解析 → 存储 → 框架”四步走一遍每一步问自己三个问题这个环节的核心库是什么关键参数有哪些最容易翻车的地方在哪下面这张清单可以直接拿来对照。复习模块核心检查项常见翻车点请求urllib/requests/aiohttp 的适用场景没设 timeout、没设 UA解析BeautifulSoup/PyQuery/XPath/正则的选择编码错误、选择器写错存储文件/MySQL/MongoDB/Redis 的选型连接未关闭、批量插入未用框架Scrapy 的 Spider/Pipeline/Middleware中间件顺序、异步调试合规Robots 协议、请求频率忽略 Disallow、请求过密具体操作上我建议拿一个真实的目标页面从零走一遍完整流程先用requests拿到 HTML确认状态码和编码再用 BeautifulSoup 或 XPath 提取目标字段打印出来核对然后写入 CSV 或 MongoDB确认数据完整最后如果数据量大用 Scrapy 重写一遍对比代码量和运行效率。这一套走下来哪个环节薄弱一目了然。还有一个容易被忽略的复习点异步请求的调试。aiohttp的报错信息不如同步请求直观建议在fetch函数里加日志记录每个请求的开始和结束时间方便定位是哪个 URL 出了问题。Scrapy 的日志系统更完善但中间件的执行顺序需要特别注意process_request是正序执行process_response是逆序执行搞反了会导致请求头没加上或者响应被提前拦截。从那以后我每次复习爬虫都强制自己从请求到入库完整走一遍不跳步。哪怕是最简单的页面也把四个环节都过一遍因为翻车往往发生在你觉得“这个我肯定会”的地方。希望这份清单帮到你。本文还有配套的精品资源点击获取