尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

GitHub高星Python爬虫实战:批量、增量与垂直型项目解析

GitHub高星Python爬虫实战:批量、增量与垂直型项目解析 最近好多读者问我“爬虫圈又有什么新动向GitHub 上哪些开源项目值得关注”说实话真正让爬虫开发者兴奋的往往不是某个封闭的采集工具而是那些开源、免费、可持续迭代的 Python 项目。这几天在 GitHub 热榜上不少 Python 爬虫相关仓库又冲上了前排有的聚焦浏览器自动化有的主打增量采集有的专注垂直领域数据清洗。对新手来说这些项目既是学习源码的好素材也是快速搭建采集服务的“轮子”。这篇文章我会从爬虫的基础分类讲起结合当前 GitHub 上值得关注的开源项目带你从零写一个可复用的 Python 爬虫脚本最后再梳理工程落地的常见问题和最佳实践。无论你是刚入门 Python还是在做数据采集、数据分析、后端开发都能从中找到可以直接使用的方案。1. 为什么一个 Python 工具能在 GitHub 上“炸圈”1.1 爬虫开发者的真实痛点做爬虫开发的人应该都有体会写一个能跑的单页爬虫并不难难的是让它稳定、高效、易维护地长期运行。结合社区里经常讨论的热词我整理出几个最典型的痛点反爬策略越来越复杂服务器端 UA 校验、IP 频率限制、JavaScript 动态渲染、字体反爬、验证码层层叠加。请求与解析耦合很多初学者把请求、解析、存储全部塞在一个脚本里想换数据源就要大改代码。缺少增量能力批量爬虫跑完一轮就结束无法感知“哪些数据是新增的”导致重复采集、浪费资源。维护成本高目标网站页面结构一变之前写的 CSS 选择器、XPath 全部失效如果没有好的工程结构改起来很痛苦。学习资料零散网上教程大多是“爬某一个站”的单点示例缺少通用的方法论。正因为这些痛点GitHub 上那些封装完善、设计清晰的 Python 爬虫开源项目才会被大量开发者 star。一个优秀的开源项目通常能解决上面至少两三个问题。1.2 开源项目对爬虫学习与生产落地的意义接触过开源项目的朋友会发现阅读一个高质量的爬虫框架源码比看十篇零散博客更有效。因为开源项目里包含了很多工程化思考请求重试怎么设计代理池如何管理去重使用什么数据结构数据管道如何解耦异常日志怎么记录如何实现分布式采集。比如很多人关注的 GitHub 开源项目不只包括爬虫框架本身还有一些“用 Python 构建的 AI 小镇”之类的模拟类项目。这类项目虽然不是爬虫但因为它使用 Python 模拟大量 Agent 行为也涉及数据处理、队列调度、异步任务等与爬虫相通的技术所以同样被爬虫开发者拿来研究。再看热词里的“批量型爬虫、增量型爬虫、垂直型爬虫”这些其实对应着三种不同的应用场景。理解这些分类才能真正理解为什么有人需要简单脚本有人需要完整框架。1.3 爬虫工具的三种典型形态在 GitHub 上看到的 Python 爬虫项目大体可以分为三类形态特点适合场景代表思路命令行/脚本工具轻量、启动快、适合小规模采集临时抓取、数据量不大requests BeautifulSoup可视化采集平台拖拽式配置、非程序员友好运营、产品快速搭建采集规则类似 Web Scraper 的思路爬虫框架/类库调度、去重、管道、扩展完整大规模、长期运行、分布式Scrapy、Playwright、Crawlee对于大多数开发者建议先掌握第一类再根据自己的业务体量升级到第三类。这也是后文实战部分会采用“轻量脚本 工程化改造”双线程的原因。2. 写在动手之前Python 爬虫的基础概念与分类为了照顾刚入门的朋友这里先梳理三个基础分类。它们是热词里反复出现的概念也是你判断“该选什么工具”的出发点。2.1 批量型爬虫批量型爬虫的核心特点是“一次跑完拿到全部目标数据”。它通常用于静态网站的全量导出某个列表页的分页抓取定时全量刷新数据仓库。优点逻辑简单容易实现。缺点如果数据量大重复采集会浪费带宽和存储如果目标网站更新频率较低全量采集的性价比不高。批量型爬虫最常见的写法是循环请求列表页再对每个详情页发请求解析。示例结构如下for page in range(1, total_pages 1): list_html fetch(page) for item in parse_list(list_html): detail_html fetch(item[url]) parse_detail(detail_html)看到问题了吗这种写法的顺序性很强网络等待时间被串行放大。提升性能的方法是使用线程池或异步请求。2.2 增量型爬虫增量型爬虫解决的问题是“只采集新增或变化的数据”。它比批量型复杂但更适合长期运行。常见的增量策略有时间戳记录上次采集时间只解析发布时间在时间戳之后的条目。内容指纹对标题或正文计算 MD5/SHA1与已存数据比对相同则跳过。数据库唯一键利用主键或唯一索引插入时使用INSERT IGNORE或ON DUPLICATE KEY UPDATE。增量爬虫在 GitHub 开源项目里非常常见因为很多数据源新闻、招聘、商品价格、社交媒体都需要持续跟踪。实现增量爬虫的关键是“去重”和“状态记录”既要判断“这条数据是否已经存在”也要记录“上次抓到了哪里”。2.3 垂直型爬虫垂直型爬虫聚焦某个特定领域或网站比如某电商平台的商品价格监控招聘网站的职位信息聚合学术数据库的论文元数据收集财经新闻的公告抓取。垂直型爬虫的特点是“每个站点一套规则”很难做到通用。但它能带来更精准的数据、更稳定的字段结构也更容易维护。GitHub 上很多细分领域爬虫项目例如 QQ 空间归档工具、B 站数据分析项目、1688 商品抓取等本质上都是垂直型爬虫。2.4 爬虫与反爬的边界认知在动手写代码前必须明确合规边界只能采集公开信息不碰账号、不碰隐私、不碰需要权限才能访问的数据遵守目标网站的robots.txt协议控制请求频率不给目标服务器造成压力采集数据的使用方式要符合法律法规和平台条款。本文后续示例会使用官方提供的公开测试网站目的是演示技术流程而不是教授“如何绕过反爬”。这一点请大家务必记住。3. 环境准备与版本说明既然是 Python 工具推荐与实战环境准备是必不可少的一步。版本需要根据你的项目实际情况调整本文示例以常见环境为例重点演示配置思路。3.1 Python 与操作系统建议使用操作系统Windows 10/11、macOS、Linux 均可Python 版本3.9 及以上。新版 Python 对类型注解、异步支持更好也兼容主流爬虫库包管理工具pip 或 pipenv。检查 Python 是否安装成功python --version pip --version如果提示“不是内部或外部命令”需要先配置环境变量或者使用 Anaconda 来管理 Python 环境。3.2 安装依赖本文实战部分会用到以下库requests发送 HTTP 请求beautifulsoup4解析 HTMLlxml解析器速度快pandas用于数据保存和处理。安装命令pip install requests beautifulsoup4 lxml pandas如果你的网络环境下载较慢可以临时使用国内镜像源pip install requests beautifulsoup4 lxml pandas -i https://pypi.tuna.tsinghua.edu.cn/simple3.3 IDE 与调试工具写爬虫最舒服的方式是在 IDE 里边写边调试。常见选择VS Code插件丰富支持 Jupyter Notebook、Python 调试PyCharmPython 专业 IDE调试功能强大Jupyter Notebook适合做数据分析和爬虫调试。另外建议安装浏览器开发者工具用来查看网页结构、定位元素。按 F12 打开 DevTools在 Elements 面板里右键复制 XPath 或 CSS 选择器这是写解析规则的基础操作。4. 当前 GitHub 上值得关注的 Python 开源项目方向这一节不是简单地让你去 star 一堆仓库而是帮你建立“我需要什么就去找什么”的思路。结合热词我整理了几个最值得关注的方向。4.1 请求与浏览器自动化方向纯 requests 已经很难应对复杂网站GitHub 上活跃度很高的两个项目值得关注Playwright微软出品的浏览器自动化库支持 Chromium、Firefox、WebKit。它能执行 JavaScript也能拦截网络请求适合爬取动态页面。与 Selenium 相比它的自动等待和上下文管理更优雅。DrissionPage国产开源项目将页面控制与数据抓取结合语法简洁深受中文开发者喜爱。它支持两种模式一种是类似 requests 的收发数据包模式另一种是操作浏览器的模式。这两个项目都是“给爬虫装上浏览器”能解决大量动态渲染和反爬问题。但要注意浏览器自动化消耗的资源比纯 HTTP 请求大不适合大规模并行。4.2 爬虫框架与调度方向ScrapyPython 爬虫领域的老牌框架。它的架构把引擎、调度器、下载器、爬虫中间件、管道分得很清楚。学习 Scrapy 能帮助你建立工程化爬虫思维。Crawlee for Python源自 Node.js 生态的爬虫库API 设计更现代与 Playwright 深度集成。对于新手我建议先用 requests 写小脚本再过渡到 Scrapy。直接上手框架容易迷失在配置文件里。4.3 数据解析与去重方向BeautifulSoup4最流行的 HTML 解析库适合快速开发。parselScrapy 官方推荐的选择器库支持 CSS、XPath、正则。Bloom Filter / Redis Set在增量型爬虫中做 URL 去重比直接查数据库更高效。4.4 学习资源型项目GitHub 上还有很多“awesome-python-crawler”之类的资源集合仓库里面整理了电子书、博客、实战项目、面试题。对于不知道如何入门的读者这类项目是最好的导航。不过要提醒一句资源仓库 star 高不代表内容一定权威要挑选近期更新、代码可运行、有明确文档的项目。关于热词里提到的 AI 小镇项目链接虽然它本身不是爬虫但作为一个 Python 开源项目的完整示例里面涉及数据模拟、Agent 调度、状态管理等工程细节对爬虫开发者很有借鉴意义。学习开源项目时不要只看 README要重点阅读src、core、utils这类目录下的代码理解作者如何组织项目结构。5. 完整实战用 Python 编写一个可复用的批量采集脚本接下来进入本文核心部分。我们会从零编写一个规范、可复现的 Python 爬虫项目。为了安全与合规目标站点选择官方测试网站quotes.toscrape.com这是一个专门用于爬虫教学的公开网站可以放心练习。5.1 需求分析需求采集网站上的名人名言数据包括名言内容text作者author标签tags。要求支持翻页并最终保存为 CSV 和 JSON 两种格式。设计上要保留后续扩展为增量型爬虫的可能。分析网站结构列表页 URLhttps://quotes.toscrape.com/page/1/每页包含多个div.quote内部有span.text、small.author、div.tags。最后一页没有下一页按钮时停止。5.2 项目结构建议先建一个目录结构如下quote_spider/ ├── main.py ├── spider/ │ ├── __init__.py │ ├── parser.py │ └── storage.py ├── data/ │ ├── quotes.csv │ └── quotes.json └── requirements.txt用模块化管理的好处是请求、解析、存储逻辑分离后续替换数据源或增加字段时不需要改动全部代码。5.3 编写请求模块先封装一个请求函数统一处理超时、异常和 UA 头。文件路径spider/parser.py但请求模块建议单独放这里先新增spider/fetcher.py。# 文件路径spider/fetcher.py import requests from requests.adapters import HTTPAdapter from urllib3.util.retry import Retry def create_session(retries: int 3, backoff_factor: float 0.5) - requests.Session: 创建带重试机制的 requests Session。 retries: 重试次数 backoff_factor: 重试等待时间的基数按指数增长。 session requests.Session() retry_strategy Retry( totalretries, backoff_factorbackoff_factor, status_forcelist[500, 502, 503, 504], ) adapter HTTPAdapter(max_retriesretry_strategy) session.mount(http://, adapter) session.mount(https://, adapter) session.headers.update({ User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0 Safari/537.36 }) return session def fetch_html(session: requests.Session, url: str, timeout: int 10) - str: 请求 URL 并返回 HTML 文本。 resp session.get(url, timeouttimeout) resp.raise_for_status() resp.encoding resp.apparent_encoding or utf-8 return resp.text这里的关键点有两个使用Retry对 5xx 错误自动重试避免网络抖动导致整个任务失败。设置User-Agent模拟浏览器请求减少被服务器拒绝的概率。注意resp.encoding resp.apparent_encoding or utf-8是为了处理中文乱码问题。虽然测试网站是英文但实战中经常遇到中文页面这一行很实用。5.4 编写解析模块解析模块负责从 HTML 中提取结构化数据。文件路径spider/parser.py。# 文件路径spider/parser.py from bs4 import BeautifulSoup from dataclasses import dataclass, asdict dataclass class QuoteItem: 单条名言的数据结构 text: str author: str tags: str def parse_quotes(html: str) - list[QuoteItem]: 解析列表页 HTML返回 QuoteItem 列表。 soup BeautifulSoup(html, lxml) items [] for div in soup.select(div.quote): text div.select_one(span.text).get_text(stripTrue) author div.select_one(small.author).get_text(stripTrue) tags ,.join([tag.get_text(stripTrue) for tag in div.select(a.tag)]) items.append(QuoteItem(texttext, authorauthor, tagstags)) return items def has_next_page(html: str) - bool: 判断是否存在下一页。 soup BeautifulSoup(html, lxml) next_btn soup.select_one(li.next a) return next_btn is not None为什么使用dataclass因为它让数据字段变得明确后续存数据库、转 JSON 都很方便。QuoteItem每个字段都对应一个明确的业务含义比直接用字典更容易维护。5.5 编写存储模块存储模块把数据写成 CSV 和 JSON。文件路径spider/storage.py。# 文件路径spider/storage.py import csv import json from pathlib import Path from spider.parser import QuoteItem def save_to_csv(items: list[QuoteItem], file_path: str) - None: 将数据追加写入 CSV 文件。 path Path(file_path) path.parent.mkdir(parentsTrue, exist_okTrue) is_new_file not path.exists() with open(path, a, newline, encodingutf-8) as f: writer csv.DictWriter(f, fieldnames[text, author, tags]) if is_new_file: writer.writeheader() for item in items: writer.writerow(item.__dict__) def save_to_json(items: list[QuoteItem], file_path: str) - None: 将数据写入 JSON 文件。 path Path(file_path) path.parent.mkdir(parentsTrue, exist_okTrue) data [item.__dict__ for item in items] with open(path, w, encodingutf-8) as f: json.dump(data, f, ensure_asciiFalse, indent2)这里的 CSV 使用追加模式方便增量写入JSON 使用覆盖模式适合全量导出。实际项目中可以根据需求调整。5.6 编写主入口最后把请求、解析、存储串起来。文件路径main.py。# 文件路径main.py import time import random from urllib.parse import urljoin from spider.fetcher import create_session, fetch_html from spider.parser import parse_quotes, has_next_page from spider.storage import save_to_csv, save_to_json def crawl(start_url: str, max_pages: int 10) - None: session create_session() current_url start_url page_count 0 all_items [] while current_url and page_count max_pages: print(f[*] 正在抓取: {current_url}) html fetch_html(session, current_url) items parse_quotes(html) print(f - 解析到 {len(items)} 条数据) all_items.extend(items) if not has_next_page(html): print([*] 没有下一页停止抓取) break next_page urljoin(current_url, page/ str(page_count 2) /) current_url next_page page_count 1 # 礼貌抓取随机休眠 1-2 秒 time.sleep(random.uniform(1, 2)) save_to_csv(all_items, data/quotes.csv) save_to_json(all_items, data/quotes.json) print(f[*] 抓取完成共 {len(all_items)} 条数据) if __name__ __main__: crawl(https://quotes.toscrape.com/page/1/, max_pages10)主流程说明while循环逐页抓取has_next_page判断是否到达最后一页每爬完一页随机休眠 1-2 秒避免请求过快最后统一保存数据。5.7 运行与验证在项目根目录执行python main.py预期输出类似[*] 正在抓取: https://quotes.toscrape.com/page/1/ - 解析到 10 条数据 [*] 正在抓取: https://quotes.toscrape.com/page/2/ - 解析到 10 条数据 ... [*] 抓取完成共 100 条数据运行完成后打开data/quotes.csv和data/quotes.json可以看到字段整齐的数据。这个脚本虽然简单但已经具备小型爬虫项目的基本结构请求、解析、存储、调度分离。如果要扩展到其他网站只需要替换解析规则和 URL 规则。6. 从批量到增量、垂直工程化改造思路第一个版本能跑通后就要开始思考改造。如果你只是做一次性数据导出批量爬虫完全够用。但如果你想长期维护就需要把项目升级为增量型或垂直型。6.1 增量型改造记录状态与去重增量爬虫的关键是“记住上次抓到哪里”。几种常见方案方案一时间戳记录在数据表里加一个crawled_at字段。每次启动爬虫时读取数据库中的最大时间戳只解析晚于该时间戳的数据。# 伪代码 last_time storage.get_max_crawled_at() items parse_quotes(html) for item in items: if item.published_at last_time: storage.save(item)方案二唯一键去重对名言原文计算哈希存入集合或数据库唯一索引。同样内容再次出现时直接跳过。import hashlib def make_fingerprint(text: str) - str: return hashlib.md5(text.encode(utf-8)).hexdigest()方案三数据库唯一约束即使不去重逻辑写错数据库的主键或唯一索引也能兜底避免脏数据。ALTER TABLE quotes ADD UNIQUE KEY uk_text (text(200));6.2 垂直型改造字段建模与配置化垂直型爬虫通常围绕某个固定领域建模。比如采集招聘信息时字段会包含职位名称、公司、薪资、城市、发布时间采集商品信息时字段会包含价格、库存、销量、店铺名。可以把这些字段定义在配置文件中解析时按配置提取。推荐使用dataclass定义模型再配合类型注解这样在后端接口对接时不容易出错。另外垂直型爬虫往往需要定期更新建议加入日志记录和异常通知。比如抓取任务结束后统计成功数、失败数、耗时发送到钉钉/企业微信/邮件。这些能力可以用 Python 内置的logging模块完成。6.3 数据存储选择建议数据量小万级以内CSV、SQLite 足够数据量中等百万级MySQL、PostgreSQL数据量大且需要搜索Elasticsearch需要列存储分析ClickHouse。对大多数个人项目和数据团队而言PostgreSQL 或 MySQL 是性价比最高的选择。数据库的字段设计要预留唯一键和索引方便增量更新。7. 常见问题与排查思路爬虫开发中没有“一次成功”的脚本遇到报错是常态。下面整理一些高频问题并给出排查思路。问题现象常见原因解决思路请求返回 403 Forbidden服务器拒绝请求多半是缺少 UA 或被识别为爬虫设置 User-Agent添加 Cookies降低请求频率页面中文乱码编码识别失败手动指定resp.encoding utf-8或从响应头中获取 charset解析结果为空HTML 结构与预期不一致或数据由 JS 动态生成用浏览器开发者工具检查实际渲染后的 DOM改用 Playwright爬取到一半程序崩溃网络异常或解析异常未捕获增加 try-except 和重试机制把已抓取数据先保存循环抓取停不下来下一页判断条件失效增加max_pages上限检查has_next_page逻辑requests 很慢单线程串行请求使用线程池或异步请求合理控制并发数内存占用过高一次性把所有数据放在内存里改为一页一存使用生成器解析数据7.1 requests 返回 403 的详细排查403 是最常见的问题。排查顺序如下检查是否有User-Agent检查是否被限流短时间内请求过多被临时封 IP检查是否需要在请求头中携带Referer检查目标站点是否需要登录 Cookie确认是单 IP 限制还是账号限制。如果只是临时测试可以用time.sleep()降低频率。如果是大规模采集需要考虑使用代理服务。但要注意不要使用来源不明、可能涉及违规的代理工具。7.2 动态加载页面的处理先按 F12 打开开发者工具在 Network 面板中查看页面加载时的 XHR 请求。如果内容是通过接口返回的直接请求接口通常比渲染页面更高效。示例import requests api_url https://example.com/api/list?page1 resp requests.get(api_url, headers{User-Agent: Mozilla/5.0}) data resp.json() # 直接拿到 JSON 数据这种方式的性能比浏览器渲染高得多但某些接口带有签名参数需要分析 JavaScript 加密逻辑。在安全合规前提下建议优先使用公开接口。7.3 增量爬虫中断后如何续传推荐把“已抓取 URL”或“已处理数据指纹”持久化。最简单的做法是保存到本地文件import json from pathlib import Path SEEN_FILE data/seen.json def load_seen() - set: if Path(SEEN_FILE).exists(): return set(json.loads(Path(SEEN_FILE).read_text(encodingutf-8))) return set() def save_seen(seen: set) - None: Path(SEEN_FILE).write_text( json.dumps(list(seen), ensure_asciiFalse), encodingutf-8 )爬虫启动时加载seen遇到新 URL 时判断是否处理过处理完再追加进去。这样即使程序中断下次也能继续。8. 最佳实践与工程建议8.1 合规与伦理边界这是所有爬虫文章都必须强调的部分。采集数据前建议确认以下几点目标数据是公开信息不需要登录、不涉及个人隐私目标网站robots.txt允许爬虫访问请求频率合理不给目标服务器造成压力采集后的数据不做违法、侵权、骚扰用途不对目标系统进行渗透、绕过权限、暴力枚举等行为。技术本身没有对错但使用技术的方式决定结果。我希望读者能把爬虫用在数据分析、学术研究、竞品公开信息整理等合法场景。8.2 代码健壮性建议统一封装请求模块不要在每个脚本里重复写 requests.get。设置超时和重试网络是不稳定的必须假设请求会失败。捕获具体异常优先捕获requests.RequestException而不是裸Exception。日志代替 print在生产环境用logging模块记录时间、级别、模块名。import logging logging.basicConfig( levellogging.INFO, format%(asctime)s - %(name)s - %(levelname)s - %(message)s, ) logger logging.getLogger(__name__) logger.info(开始抓取: %s, url)8.3 数据管理建议每条数据尽量带上“抓取时间”字段建立唯一键防止重复插入定期清理过期数据对文本类字段考虑设置合理长度避免数据库报错。8.4 性能优化思路使用requests.Session()复用连接多页面抓取时使用线程池推荐并发数 5-10异步方案可以使用httpx.AsyncClient或aiohttp解析时优先使用 lxml 解析器大批量存储时使用批量插入而不是逐条 insert。8.5 学习路线建议如果你是 Python 新手建议按以下顺序学习Python 基础语法变量、循环、函数、文件读写requests 库GET、POST、Headers、SessionBeautifulSoup 解析CSS 选择器、XPath数据存储CSV、JSON、SQLite动态页面Playwright 的基本用法框架进阶Scrapy 架构与管道工程化日志、异常、定时任务、部署。如果还没有搭建 Python 环境可以先从安装 Python 解释器开始然后使用 VS Code 写第一个脚本。不要一开始就追求复杂的分布式爬虫先跑通一个简单流程再逐步扩展。GitHub 上有很多优秀的 Python 爬虫项目阅读源码时不要只看热闹要问自己几个问题它的请求封装在哪个模块它的去重逻辑用了什么数据结构它的数据管道如何处理异常带着问题去读代码收获会大得多。本文从爬虫分类、GitHub 开源项目方向、完整实战、增量改造、常见问题到工程建议覆盖了 Python 爬虫从入门到落地的关键链路。你可以先跟着 5.6 节的代码跑通一个示例然后试着把解析目标换成自己关注的网站再慢慢加入重试机制、日志、增量去重。如果哪一步遇到报错欢迎对照第 7 节的排查表逐个检查。爬虫技术并不神秘关键在于多动手、多总结、敬畏规则。希望这篇内容能帮你少走一些弯路。
返回列表