高效爬取Pixiv每日推荐:从动态加载到批量下载的完整指南

张开发
2026/4/12 2:28:02 15 分钟阅读

分享文章

高效爬取Pixiv每日推荐:从动态加载到批量下载的完整指南
1. 理解Pixiv每日推荐的工作原理Pixiv作为全球知名的插画分享平台其每日推荐功能是许多创作者和爱好者获取灵感的重要来源。这个推荐系统会根据用户偏好、作品热度等因素每天精选500幅优质作品展示给用户。但直接通过网页浏览存在两个痛点一是需要不断手动滚动加载二是无法批量保存心仪的作品。动态加载机制是这类现代网站常用的技术手段。当你滚动页面到底部时浏览器会向服务器发送新的请求获取下一批作品数据。这种设计能显著减少初始页面加载时间但也给数据采集带来了挑战。通过浏览器开发者工具观察网络请求可以发现每次滚动触发的请求URL中都包含一个页码参数p1, p2...每页返回50个作品总共10页正好对应500个推荐作品。与传统静态网页不同动态加载的内容不会直接出现在HTML源码中。这就是为什么简单的requests.get()可能抓不到完整数据。我们需要模拟浏览器的行为构造包含正确参数的API请求。Pixiv的API接口返回的是结构化JSON数据其中包含作品ID、标题等关键信息这些正是我们构建爬虫的基础。2. 环境准备与基础配置在开始编写爬虫前需要准备好Python环境。我推荐使用Python 3.8版本太老的版本可能会遇到依赖兼容问题。核心依赖库有三个requests用于网络请求、re用于正则表达式匹配、os用于文件操作。安装命令很简单pip install requestsPixiv对爬虫有一定防护措施所以我们需要配置合理的请求头。最重要的两个字段是User-Agent和Referer。User-Agent用于模拟浏览器访问Referer则告诉服务器请求的来源页面。下面是我经过多次测试后总结出的有效配置headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36, Referer: https://www.pixiv.net/ranking.php?modedailycontentillust }文件存储路径也需要提前规划。建议为每天的推荐创建一个独立文件夹按日期分类。这里有个小技巧使用os.path.join()代替硬编码路径可以避免不同操作系统下的路径分隔符问题import os import datetime today datetime.datetime.now().strftime(%Y-%m-%d) save_path os.path.join(pixiv_daily, today) os.makedirs(save_path, exist_okTrue)3. 单张图片的精准抓取技术抓取单张高清图片是批量下载的基础。通过分析页面结构我发现原图URL藏在作品页面的JavaScript数据中而不是直接显示在HTML里。使用正则表达式提取是最直接的方法关键是要找到可靠的匹配模式。经过多次测试原图URL通常出现在original:...这样的JSON字段中。我们可以用以下正则表达式精准捕获pattern roriginal:(.?)},tags match re.search(pattern, response.text) if match: original_url match.group(1)图片命名也是个需要注意的细节。直接从作品信息中提取的标题可能包含非法字符如/:*?|会导致保存失败。我的解决方案是先用正则过滤非法字符再用作品ID作为备选名称def sanitize_filename(name): return re.sub(r[\\/*?:|], , name) title re.search(illustTitle:(.?), response.text).group(1) safe_title sanitize_filename(title) or fillust_{illust_id}完整的单图下载函数还需要处理网络异常。我习惯给请求加上超时设置并自动重试失败的任务def download_image(url, save_as): for attempt in range(3): try: resp requests.get(url, headersheaders, timeout10) resp.raise_for_status() with open(save_as, wb) as f: f.write(resp.content) return True except Exception as e: print(fAttempt {attempt1} failed: {str(e)}) time.sleep(2) return False4. 批量获取每日推荐作品列表获取全部500个推荐作品的关键在于理解Pixiv的API参数。通过分析滚动加载时的网络请求发现核心API端点是https://www.pixiv.net/ranking.php?modedailycontentillustp[页码]formatjson其中页码参数p从1到10每个返回50个作品。这里有个容易忽略的点必须加上formatjson参数否则返回的是HTML页面而非结构化数据。作品ID提取可以使用正则表达式但更稳健的方法是直接解析JSON。不过Pixiv的JSON响应有些特殊需要先解码unicode转义字符import json response requests.get(api_url, headersheaders) data json.loads(response.text.encode().decode(unicode-escape)) illust_ids [item[illust_id] for item in data[contents]]为了提升效率我建议使用多线程来并发获取各页数据。但要注意控制并发数避免触发反爬机制from concurrent.futures import ThreadPoolExecutor def fetch_page(page): url fhttps://www.pixiv.net/ranking.php?modedailyp{page}formatjson response requests.get(url, headersheaders) return re.findall(illust_id:(\d?),, response.text) with ThreadPoolExecutor(max_workers4) as executor: all_ids list(executor.map(fetch_page, range(1, 11)))5. 完整爬虫的工程化实现将各个模块组合起来时需要考虑异常处理和日志记录。我习惯使用logging模块记录运行状态方便排查问题import logging logging.basicConfig( levellogging.INFO, format%(asctime)s - %(levelname)s - %(message)s, handlers[ logging.FileHandler(pixiv_crawler.log), logging.StreamHandler() ] )完整的爬虫类应该包含配置管理、状态跟踪和断点续传功能。下面是我的实现框架class PixivDailyCrawler: def __init__(self, config): self.headers config[headers] self.save_path config[save_path] self.completed_ids set() self.load_progress() def load_progress(self): try: with open(progress.json) as f: self.completed_ids set(json.load(f)) except FileNotFoundError: pass def save_progress(self): with open(progress.json, w) as f: json.dump(list(self.completed_ids), f) def run(self): try: illust_ids self.fetch_all_ids() self.download_batch(illust_ids) finally: self.save_progress()对于大规模下载还需要考虑代理设置和速度限制。我建议在每个请求之间添加随机延迟import random import time def random_delay(min1, max3): time.sleep(random.uniform(min, max))6. 常见问题与优化方案在实际运行中我遇到过几个典型问题。首先是403禁止访问错误这通常是因为请求头设置不当。解决方案是确保包含正确的Referer并定期更新User-Agent字符串。另一个常见问题是图片名称重复。Pixiv允许不同作品使用相同标题直接用作文件名会导致覆盖。我的解决方法是在重名文件后添加后缀counter 1 filename f{safe_title}.{ext} while os.path.exists(os.path.join(save_path, filename)): filename f{safe_title}_{counter}.{ext} counter 1对于网络不稳定的情况可以考虑使用持久化会话和自动重试机制session requests.Session() adapter requests.adapters.HTTPAdapter( max_retries3, pool_connections10, pool_maxsize10 ) session.mount(https://, adapter)最后提醒一点法律风险大规模爬取可能违反Pixiv的服务条款。建议控制请求频率仅用于个人学习目的。更好的做法是使用Pixiv官方API虽然功能有限但完全合规。

更多文章