2148 字
11 分钟
Pixiv爬虫/下载/代理,无需服务器即可一键部署!
把去年用python写的pixiv爬虫项目用AI和serverless架构重写了一下,支持定时任务,支持下载,支持代理访问。
项目简介
把去年用python写的pixiv爬虫项目用AI和serverless架构重写了一下,支持定时任务,支持下载,支持代理访问。
✨ 核心特性
- 无服务器架构:基于 Vercel + Cloudflare Workers,零运维成本
- 智能爬取:支持热度过滤,自动发现优质内容
- ️ 图片代理:解决跨域问题,提供高速图片访问
- 数据存储:集成 Supabase 数据库,支持复杂查询
- 批量下载:支持图片批量下载到 Cloudflare R2
- ⏰ 定时任务:自动爬取排行榜,无需人工干预
️ 系统架构
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐│ Vercel API │ │ Cloudflare Cron │ │ Supabase DB ││ (主服务) │◄──►│ (定时任务) │◄──►│ (数据存储) │└─────────────────┘ └─────────────────┘ └─────────────────┘ │ │ │ ▼ ▼ ▼┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐│ 图片代理服务 │ │ 爬虫调度器 │ │ 数据分析API ││ (跨域解决方案) │ │ (任务分发) │ │ (统计查询) │└─────────────────┘ └─────────────────┘ └─────────────────┘核心功能实现
1. 智能爬虫引擎
我们的爬虫不仅能获取基础信息,还能智能分析内容质量:
/** * Pixiv 爬虫核心类 * 支持智能推荐和热度计算 */export class PixivCrawler { private headers: any; private logManager: any; private taskId: string;
constructor(pid: string, headers: any, logManager: any, taskId: string) { this.headers = headers; this.logManager = logManager; this.taskId = taskId; }
/** * 获取作品详细信息并计算热度 * @param pid 作品ID * @returns 作品信息和热度分数 */ async getIllustDetail(pid: string) { try { const url = `https://www.pixiv.net/ajax/illust/${pid}`; const response = await fetch(url, { headers: this.headers }); const data = await response.json();
if (data.error) { throw new Error(`API错误: ${data.message}`); }
const illust = data.body;
// 计算热度分数 const popularity = this.calculatePopularity( illust.likeCount, illust.bookmarkCount, illust.viewCount );
return { pid: illust.id, title: illust.title, tags: illust.tags.tags.map((tag: any) => tag.tag), likeCount: illust.likeCount, bookmarkCount: illust.bookmarkCount, viewCount: illust.viewCount, popularity, createDate: illust.createDate }; } catch (error) { this.logManager.addLog(`获取作品 ${pid} 失败: ${error.message}`, 'error', this.taskId); throw error; } }
/** * 热度计算算法 * 综合考虑点赞、收藏、浏览量 */ private calculatePopularity(likes: number, bookmarks: number, views: number): number { if (views === 0) return 0;
const likeRate = likes / views; const bookmarkRate = bookmarks / views;
// 加权计算热度分数 return (likeRate * 0.3 + bookmarkRate * 0.7) * Math.log10(views + 1); }}2. 图片代理服务
解决跨域问题,提供高速图片访问:
/** * Pixiv 图片代理服务 * 支持多尺寸智能选择和自动降级 */export class PixivProxy { private headers: any;
constructor() { this.headers = { 'Referer': 'https://www.pixiv.net/', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36' }; }
/** * 代理访问 Pixiv 图片 * @param pid 图片ID * @param size 期望尺寸 * @returns 图片数据流 */ async proxyImage(pid: string, size: string = 'regular') { // 尺寸优先级:thumb_mini -> small -> regular -> original const sizeOptions = ['thumb_mini', 'small', 'regular', 'original']; const startIndex = sizeOptions.indexOf(size);
if (startIndex === -1) { throw new Error(`不支持的图片尺寸: ${size}`); }
// 按优先级尝试获取图片 for (let i = startIndex; i < sizeOptions.length; i++) { try { const currentSize = sizeOptions[i]; const imageUrl = await this.getImageUrl(pid, currentSize);
if (imageUrl) { const imageResponse = await fetch(imageUrl, { headers: this.headers });
if (imageResponse.ok) { return { data: imageResponse.body, contentType: imageResponse.headers.get('content-type'), size: currentSize }; } } } catch (error) { console.log(`尺寸 ${sizeOptions[i]} 获取失败,尝试下一个尺寸`); continue; } }
throw new Error(`无法获取图片 ${pid} 的任何尺寸版本`); }
/** * 获取指定尺寸的图片URL */ private async getImageUrl(pid: string, size: string): Promise<string | null> { try { const response = await fetch(`https://www.pixiv.net/ajax/illust/${pid}`, { headers: this.headers });
const data = await response.json(); const urls = data.body?.urls;
return urls?.[size] || null; } catch (error) { return null; } }}3. API 接口设计
提供完整的 RESTful API:
/** * 主 API 处理器 * 支持多种操作:爬取、下载、代理、统计 */export default async function handler(req: VercelRequest, res: VercelResponse) { // 设置 CORS 头 res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS'); res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
if (req.method === 'OPTIONS') { res.status(200).end(); return; }
const { action, pid, size } = req.query;
try { switch (action) { case 'proxy-image': // 图片代理访问 if (!pid) { res.status(400).json({ error: '缺少 pid 参数' }); return; }
const proxy = new PixivProxy(); const imageResult = await proxy.proxyImage(pid as string, size as string);
res.setHeader('Content-Type', imageResult.contentType); res.setHeader('Cache-Control', 'public, max-age=86400'); // 缓存1天
return imageResult.data.pipe(res);
case 'get-pic': // 获取图片信息 const crawler = new PixivCrawler(pid as string, getPixivHeaders(), logManager, 'api_request'); const illustInfo = await crawler.getIllustDetail(pid as string);
res.status(200).json({ success: true, data: illustInfo }); break;
case 'stats': // 获取统计信息 const supabase = new SupabaseService(); const stats = await supabase.getStats();
res.status(200).json({ success: true, stats }); break;
default: // 返回 Web 界面 const htmlContent = getWebInterface(); res.setHeader('Content-Type', 'text/html'); res.status(200).send(htmlContent); } } catch (error) { res.status(500).json({ error: '服务器内部错误', message: error.message }); }}4. 定时任务调度
使用 Cloudflare Cron Worker 实现自动化:
/** * Cloudflare Cron Worker * 定时执行爬取任务 */export default { async scheduled(event: ScheduledEvent, env: Env, ctx: ExecutionContext) { console.log('定时任务开始执行:', new Date().toISOString());
try { // 每日排行榜爬取 if (shouldRunDailyRanking(event.cron)) { await triggerRankingCrawl('daily', env); }
// 每周排行榜爬取 if (shouldRunWeeklyRanking(event.cron)) { await triggerRankingCrawl('weekly', env); }
// 清理过期日志 if (shouldCleanLogs(event.cron)) { await cleanExpiredLogs(env); }
} catch (error) { console.error('定时任务执行失败:', error); } }};
/** * 触发排行榜爬取 */async function triggerRankingCrawl(type: 'daily' | 'weekly' | 'monthly', env: Env) { const endpoint = `${env.MAIN_SERVICE_URL}/api/?action=${type}`;
try { const response = await fetch(endpoint, { method: 'GET', headers: { 'Authorization': `Bearer ${env.API_TOKEN}` } });
if (response.ok) { console.log(`${type} 排行榜爬取任务已触发`); } else { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } } catch (error) { console.error(`触发 ${type} 排行榜爬取失败:`, error); }}3分钟快速部署
步骤1:克隆项目
git clone https://github.com/your-username/serverless_pixiv_crawler.gitcd serverless_pixiv_crawlernpm install步骤2:配置环境变量
复制 .env.example 为 .env:
# Supabase 数据库配置SUPABASE_URL=your_supabase_url_hereSUPABASE_ANON_KEY=your_supabase_anon_key_here
# Pixiv 配置PIXIV_COOKIE=your_pixiv_cookie_here
# Cloudflare R2 配置(可选)CLOUDFLARE_ACCOUNT_ID=your_account_idCLOUDFLARE_ACCESS_KEY_ID=your_access_keyCLOUDFLARE_SECRET_ACCESS_KEY=your_secret_keyCLOUDFLARE_BUCKET_NAME=your_bucket_name步骤3:部署到 Vercel
# 安装 Vercel CLInpm i -g vercel
# 登录并部署vercel loginvercel --prod步骤4:部署定时任务(可选)
cd cron_workernpm install
# 配置 Cloudflare Workersnpx wrangler loginnpx wrangler deploy功能演示
1. Web 管理界面
部署完成后,访问你的 Vercel 域名,你将看到一个现代化的管理界面:
- 实时统计:显示爬取数量、成功率等关键指标
- 任务管理:启动、停止、监控爬取任务
- 日志查看:实时查看系统运行日志
- 数据搜索:快速查找和筛选爬取的内容
2. API 接口使用
// 获取图片信息fetch('https://your-domain.vercel.app/api/?action=get-pic&pid=123456') .then(res => res.json()) .then(data => console.log(data));
// 代理访问图片const imageUrl = 'https://your-domain.vercel.app/api/?action=proxy-image&pid=123456&size=regular';document.getElementById('image').src = imageUrl;
// 启动爬取任务fetch('https://your-domain.vercel.app/api/', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ pid: '123456', targetNum: 1000, popularityThreshold: 0.22 })});3. 数据分析
系统自动收集和分析数据,提供丰富的统计信息:
-- 热门标签统计SELECT tag, COUNT(*) as countFROM illustrationsCROSS JOIN LATERAL unnest(tags) as tagGROUP BY tagORDER BY count DESCLIMIT 20;
-- 热度分布分析SELECT CASE WHEN popularity >= 0.8 THEN '超高热度' WHEN popularity >= 0.5 THEN '高热度' WHEN popularity >= 0.2 THEN '中等热度' ELSE '低热度' END as level, COUNT(*) as countFROM illustrationsGROUP BY level;高级特性
1. 智能推荐算法
系统内置智能推荐算法,能够: - 内容发现:基于已有数据发现相似优质内容 - 热度预测:预测内容未来的热度趋势 - 风格分析:识别和分类不同的艺术风格
2. 防封机制
- 请求头轮换:模拟真实浏览器行为
- ⏱️ 智能延迟:动态调整请求间隔
- ️ 错误重试:智能处理网络异常
3. 数据质量保证
- ✅ 自动去重:避免重复数据
- 内容验证:确保数据完整性
- 质量评分:为每个内容计算质量分数
成本分析
这个项目的最大优势是完全免费:
| 服务 | 免费额度 | 足够支撑 |
|---|---|---|
| Vercel | 100GB 带宽/月 | 中小型项目 |
| Supabase | 500MB 数据库 | 50万条记录 |
| Cloudflare Workers | 10万请求/天 | 大部分使用场景 |
| Cloudflare R2 | 10GB 存储 | 数万张图片 |
故障排除
常见问题
- 部署失败
- 检查环境变量配置
- 确认 Supabase 连接正常
- 爬取失败
- 验证 Pixiv Cookie 有效性
- 检查网络连接状态
- 图片无法显示
- 确认代理服务正常运行
- 检查跨域配置
性能优化建议
- 启用缓存:合理设置 CDN 缓存策略
- 监控指标:定期检查系统性能指标
- 定期清理:清理过期数据和日志
总结
这个 Serverless Pixiv 爬虫项目展示了现代化 Web 开发的强大能力:
- ✅ 零运维成本:完全基于云服务,无需管理服务器
- ✅ 高可扩展性:自动伸缩,应对流量波动
- ✅ 功能完整:爬取、存储、分析、展示一体化
- ✅ 部署简单:3分钟即可完成部署
无论你是想学习 Serverless 架构,还是需要一个实用的数据收集工具,这个项目都是一个很好的起点。
相关资源
免责声明:本项目仅供学习和研究使用,请遵守相关网站的服务条款,合理控制爬取频率。
如果这篇文章对你有帮助,请给项目点个 ⭐ Star!

发现错误或想要改进这篇文章?
在 GitHub 上编辑此页 Pixiv爬虫/下载/代理,无需服务器即可一键部署!
https://blog.chaosyn.com/posts/pixiv爬虫-下载-代理-无需服务器即可一键部署/