一个简单的 Serverless Pixiv 爬虫项目分享
前言
最近把之前用 Python 写的 Pixiv 爬虫用 AI 和 Serverless 架构重新实现了一遍,主要是想实践榨干一下 serverless的免费额度。虽然功能还比较基础,但整个过程学到了不少东西,想和大家分享一下。
声明:这个项目纯粹是为了学习技术,请大家合理使用,遵守相关网站的服务条款。
技术选型思考
为什么选择 Serverless?
说实话,一开始我也在犹豫要不要用 Serverless。传统的服务器部署我比较熟悉,但 Serverless 有几个吸引我的地方:
-
成本低:对于个人项目来说,免费额度基本够用,这是主要原因
-
免运维:不用担心服务器宕机、更新等问题,也不用担心替换代码,直接git action自动触发部署
-
自动扩容:流量大的时候自动处理,不用手动调整
技术栈选择
经过一番调研,最终选择了这套组合:
-
Vercel:主要 API 服务,部署简单,国内访问速度还可以
-
Cloudflare Workers:定时任务,全球节点,稳定性不错
-
Supabase:PostgreSQL 数据库,有免费额度,功能够用
-
TypeScript:类型安全,开发体验比 JavaScript 好很多
系统架构设计
整个系统采用了分布式的设计思路,主要分为几个部分:
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Vercel API │ │ Cloudflare Cron │ │ Supabase DB │
│ (主要服务) │◄──►│ (定时调度) │◄──►│ (数据存储) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │ │
▼ ▼ ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ 图片代理服务 │ │ 任务分发器 │ │ 数据分析API │
│ (免翻墙访问图片) │ │ (适配多节点) │ │ (统计查询) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
核心模块介绍
1. 主服务 (Vercel API)
这是整个系统的核心,提供了所有的 API 接口。主要功能包括:
-
爬虫服务:负责实际的数据抓取工作
-
图片代理:免翻墙访问 Pixiv 图片
-
数据管理:提供 CRUD 操作和统计查询
-
Web 界面:一个简单的管理后台
2. 定时任务 (Cloudflare Cron Worker)
用来做任务调度,比如:
-
定时抓取排行榜数据
-
定期请求获取推荐图片
-
分发任务给多个节点
这部分的设计比较简单,主要是读取数据库中的待处理任务,然后调用主服务的 API。
3. 数据存储 (Supabase)
选择 Supabase 主要是因为它提供了不错的免费额度。数据库设计也比较简单:
-
pic 表:存储作品信息
-
pic_task 表:任务队列管理
核心功能实现
1. 智能推荐算法
这个功能我花了不少时间思考。最初的想法很简单,就是根据一个作品 ID 去找相关的推荐内容。但实际实现时发现,单纯的推荐容易陷入局部最优,所以加了几个策略:
-
多种推荐类型:支持按插画、作者、首页等不同类型的推荐
-
热度过滤:设置一个热度阈值,过滤掉质量不高的内容
-
自动去重:避免重复抓取相同内容
-
动态调整:根据目标数量自动调整推荐深度
2. 热度计算
这个算法随便想的仅供参考,最终采用了这个公式:
热度 = (点赞数 × 0.55 + 收藏数 × 0.45) ÷ 浏览量
权重的选择主要考虑了:
-
点赞比收藏更容易,所以权重稍低
-
浏览量作为分母,避免新作品虚高
-
整体范围在 0-1 之间,便于设置阈值
3. 防封机制
这部分比较重要,毕竟不想给目标网站造成太大压力:
-
请求头轮换:每隔一段时间切换不同的浏览器标识
-
随机延迟:每次请求之间加入随机等待时间
4. 图片代理服务
这个功能主要是为了解决前端访问图片的翻墙问题。实现思路比较直接:
-
前端请求我们的代理接口
-
后端用正确的 Referer 去请求原图
-
将图片数据流直接返回给前端
-
加上适当的缓存头,提升访问速度
部署和运维
部署流程
整个部署过程还是比较简单的:
-
配置环境变量:主要是数据库连接和 Pixiv Cookie
-
部署主服务:一条命令部署到 Vercel
-
部署定时任务:使用 Wrangler CLI 部署到 Cloudflare
-
初始化数据库:执行 SQL 脚本创建表结构
成本控制
这套方案的成本控制做得还不错:
| 服务 | 免费额度 | 实际使用 |
|------|----------|----------|
| Vercel | 100GB 带宽/月 | 通常用不到 10GB |
| Supabase | 500MB 数据库 | 存储几十万条记录没问题 |
| Cloudflare Workers | 10万请求/天 | 定时任务用量很少 |
基本上个人使用完全免费。
遇到的问题和解决方案
1. IP 封禁问题
最开始想直接在 Cloudflare Worker 里做爬虫,结果发现 CF 的 IP 已经被封了。后来改成了现在这种架构,定时任务只负责调度,实际爬取在 Vercel 上进行。
2. 图片质量低下问题
最开始的pic_task会无限递归爬取,导致图片质量低下无限扩散,现在采用爬取插画推荐和作者推荐前判断当前图片热度,热度高的图片才进行推荐爬取。
3. serverless请求超时问题
最初是按照我之前的思路,在edge function中直接递归爬取指定数量图片,后来发现这种实现完全不稳定,爬了几张就停了。后面采用task表记录爬取情况,爬取推荐和爬取图片详细信息单独分配任务给节点去爬取,效率和稳定性都提高了。
功能特色
Web 管理界面
虽然我不是前端出身,但还是做了一个简单的管理界面:
-
实时监控:显示系统状态和统计数据
-
任务管理:可以手动启动最初版本的递归爬取任务
-
日志查看:实时查看系统运行日志
界面比较简单,经典紫色心情的风格。
API 接口
提供了完整的 RESTful API:
GET 接口:
-
/api?action=status- 系统状态检查,返回服务运行状态和环境信息 -
/api?action=stats- 统计信息,返回图片总数、下载数量、平均热度等 -
/api?action=env-check- 环境变量检查,验证配置完整性 -
/api?action=logs&taskId=xxx&limit=100- 获取日志,支持按任务ID过滤 -
/api?action=get-pic&pid=xxx- 获取指定PID的图片信息 -
/api?action=proxy-image&pid=xxx&size=xxx- 代理访问Pixiv图片,支持指定尺寸 -
/api?action=home- 获取首页推荐PID并入库 -
/api?action=random-pids&count=10- 从数据库随机获取指定数量的PID -
/api?action=illust-recommend-pids&pid=xxx&targetNum=30- 获取插画推荐PID列表 -
/api?action=author-recommend-pids&pid=xxx&targetNum=30- 获取作者推荐PID列表 -
/api?action=pid-detail-info&pid=xxx- 获取PID详细信息并入库 -
/api?action=daily- 触发日榜抓取任务 -
/api?action=weekly- 触发周榜抓取任务 -
/api?action=monthly- 触发月榜抓取任务 -
/api- 返回Web管理界面
POST 接口:
/api(爬虫任务) - 启动爬虫任务,支持单个PID或批量PID
```json
{
"pid": "123456", // 单个PID
"pids": ["123456", "789012"], // 批量PID
"targetNum": 1000, // 目标数量
"popularityThreshold": 0.22 // 热度阈值
}
```
/api(下载任务) - 启动下载任务,需要R2配置
```json
{
"action": "download",
"downloadPid": "123456", // 单个下载
"downloadPids": ["123456", "789012"] // 批量下载
}
```
接口设计比较简单,主要是为了方便调用。
多节点爬取
为了提高爬取效率,采用了多节点并行爬取的方式。每个节点负责一部分任务,任务分配采用定时分配策略,不同任务分配频率不一样。
总结
这个项目虽然功能比较简单又是AI实现的,但让我学到了很多东西:
-
Serverless 架构:体验了无服务器开发的便利性,学习了运维部署方式
-
云服务集成:学会了如何组合使用不同的云服务
-
系统设计:在成本和功能之间找到平衡点
当然,项目还有很多不足的地方,比如错误处理还不够完善,监控系统也比较简陋。但作为一个学习项目,我觉得还是达到了预期目标。
如果你也对 Serverless 开发感兴趣,希望这个项目能给你一些参考。代码都在 GitHub 上,欢迎交流讨论。
最后再次提醒:这个项目仅供学习使用,请大家合理控制爬取频率,遵守相关网站的服务条款。技术无罪,但使用技术的方式很重要。
项目地址:GitHub - serverless_pixiv_crawler
体验前端地址(只有递归爬取功能,大部分功能都在api接口中):pixiv.chaosyn.com
如果觉得有用的话,欢迎给个 Star ⭐
各位佬如果有啥建议和想法,欢迎在项目仓库提 issue 或者 PR,也可以直接在评论区下方交流~