2148
11 分钟
Pixiv爬虫/下载/代理,无需服务器即可一键部署!
把去年用python写的pixiv爬虫项目用AI和serverless架构重写了一下,支持定时任务,支持下载,支持代理访问。
2025-10-07
统计加载中...

项目简介#

把去年用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.git
cd serverless_pixiv_crawler
npm install

步骤2:配置环境变量#

复制 .env.example 为 .env:

# Supabase 数据库配置
SUPABASE_URL=your_supabase_url_here
SUPABASE_ANON_KEY=your_supabase_anon_key_here
# Pixiv 配置
PIXIV_COOKIE=your_pixiv_cookie_here
# Cloudflare R2 配置(可选)
CLOUDFLARE_ACCOUNT_ID=your_account_id
CLOUDFLARE_ACCESS_KEY_ID=your_access_key
CLOUDFLARE_SECRET_ACCESS_KEY=your_secret_key
CLOUDFLARE_BUCKET_NAME=your_bucket_name

步骤3:部署到 Vercel#

# 安装 Vercel CLI
npm i -g vercel
# 登录并部署
vercel login
vercel --prod

步骤4:部署定时任务(可选)#

cd cron_worker
npm install
# 配置 Cloudflare Workers
npx wrangler login
npx 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 count
FROM illustrations
CROSS JOIN LATERAL unnest(tags) as tag
GROUP BY tag
ORDER BY count DESC
LIMIT 20;
-- 热度分布分析
SELECT
CASE
WHEN popularity >= 0.8 THEN '超高热度'
WHEN popularity >= 0.5 THEN '高热度'
WHEN popularity >= 0.2 THEN '中等热度'
ELSE '低热度'
END as level,
COUNT(*) as count
FROM illustrations
GROUP BY level;

高级特性#

1. 智能推荐算法#

系统内置智能推荐算法,能够: - 内容发现:基于已有数据发现相似优质内容 - 热度预测:预测内容未来的热度趋势 - 风格分析:识别和分类不同的艺术风格

2. 防封机制#

  • 请求头轮换:模拟真实浏览器行为
  • ⏱️ 智能延迟:动态调整请求间隔
  • 错误重试:智能处理网络异常

3. 数据质量保证#

  • 自动去重:避免重复数据
  • 内容验证:确保数据完整性
  • 质量评分:为每个内容计算质量分数

成本分析#

这个项目的最大优势是完全免费

服务免费额度足够支撑
Vercel100GB 带宽/月中小型项目
Supabase500MB 数据库50万条记录
Cloudflare Workers10万请求/天大部分使用场景
Cloudflare R210GB 存储数万张图片

故障排除#

常见问题#

  1. 部署失败
  2. 检查环境变量配置
  3. 确认 Supabase 连接正常
  4. 爬取失败
  5. 验证 Pixiv Cookie 有效性
  6. 检查网络连接状态
  7. 图片无法显示
  8. 确认代理服务正常运行
  9. 检查跨域配置

性能优化建议#

  • 启用缓存:合理设置 CDN 缓存策略
  • 监控指标:定期检查系统性能指标
  • 定期清理:清理过期数据和日志

总结#

这个 Serverless Pixiv 爬虫项目展示了现代化 Web 开发的强大能力:

  • 零运维成本:完全基于云服务,无需管理服务器
  • 高可扩展性:自动伸缩,应对流量波动
  • 功能完整:爬取、存储、分析、展示一体化
  • 部署简单:3分钟即可完成部署

无论你是想学习 Serverless 架构,还是需要一个实用的数据收集工具,这个项目都是一个很好的起点。

相关资源#


免责声明:本项目仅供学习和研究使用,请遵守相关网站的服务条款,合理控制爬取频率。

如果这篇文章对你有帮助,请给项目点个 ⭐ Star!

v2-a211000410c25bbc31bbac49312d1020_1440w.png

这篇文章是否对你有帮助?

发现错误或想要改进这篇文章?

在 GitHub 上编辑此页
Pixiv爬虫/下载/代理,无需服务器即可一键部署!
https://blog.chaosyn.com/posts/pixiv爬虫-下载-代理-无需服务器即可一键部署/
作者
叶桐
发布于
2025-10-07
许可协议
CC BY-NC-SA 4.0