技术宅的二次元宝藏!Python爬虫实战,批量获取米游社原神角色美图与动态
1. 为什么选择Python爬虫获取米游社原神资源作为一个玩了三年原神的老玩家我经常在米游社看到各种精美的角色同人图和官方壁纸。每次手动保存实在太麻烦直到我发现了Python爬虫这个神器。用requests库抓取米游社API数据不仅能批量下载高清图片还能自动分类整理简直是技术宅的二次元宝藏相比手动操作爬虫有三大优势一是效率高几分钟就能获取上百张图片二是可以定时自动更新不错过任何新发布的优质内容三是能实现智能分类比如按角色、画师或发布时间整理。我实测下来用Python脚本每天自动收集新图半年就建起了超过2万张的原神图库。2. 准备工作环境配置与工具选择2.1 基础环境搭建首先需要安装Python环境推荐使用3.8以上版本。我习惯用conda创建独立环境conda create -n genshin python3.8 conda activate genshin核心依赖库就三个requests处理网络请求、json解析API数据、os和pathlib管理文件路径。安装命令很简单pip install requests2.2 开发者工具的使用技巧按F12打开浏览器开发者工具切换到Network标签页。在米游社随便点开一张角色图就能在XHR请求里找到关键的API接口。我常用的筛选技巧是过滤XHR类型请求搜索关键词get或list查看返回JSON数据的请求找到目标API后右键复制为cURL命令再通过在线工具转成Python代码能省去很多手动构造请求的时间。3. 解析米游社API数据结构3.1 关键接口分析通过反复测试我发现米游社主要使用两种API格式分页列表接口通常包含list、page等字段详情接口包含高清图url和元数据典型的响应结构如下{ data: { list: [ { id: 123, title: 甘雨同人图, images: [https://xxx.jpg], character: [甘雨], author: 某画师 } ], total: 100 } }3.2 动态加载逻辑破解米游社采用滚动加载方式通过page和size参数控制分页。我通过修改参数测试出最大允许的size值是50超过会返回错误。所以批量获取时需要循环请求直到list为空为止。处理分页的代码模板page 1 while True: params {page: page, size: 50} response requests.get(url, paramsparams) data response.json() if not data[data][list]: break # 处理当前页数据 page 14. 图片下载与分类存储实战4.1 高效下载方案直接使用requests的流式下载可以避免内存溢出问题特别是处理高清大图时。我的下载函数通常会添加重试机制def download_image(url, save_path): for i in range(3): # 最多重试3次 try: with requests.get(url, streamTrue) as r: r.raise_for_status() with open(save_path, wb) as f: for chunk in r.iter_content(chunk_size8192): f.write(chunk) return True except Exception as e: print(f第{i1}次下载失败: {e}) return False4.2 智能分类系统我设计了一套基于元数据的自动分类规则按角色创建文件夹从API提取character字段按画师分子目录author字段按月份归档从create_time解析核心分类代码def organize_image(data): char_dir Path(images) / data[character][0] author_dir char_dir / data[author] author_dir.mkdir(parentsTrue, exist_okTrue) timestamp datetime.fromtimestamp(data[create_time]) month_dir author_dir / f{timestamp.year}-{timestamp.month:02d} month_dir.mkdir(exist_okTrue) return month_dir / f{data[id]}.jpg5. 高级技巧与优化方案5.1 增量爬取实现为了避免重复下载我会记录已爬取的id到sqlite数据库。每次启动时先查询已有id只请求新内容import sqlite3 def get_existing_ids(): conn sqlite3.connect(genshin.db) c conn.cursor() c.execute(SELECT id FROM images) return {row[0] for row in c.fetchall()}5.2 反爬虫策略应对米游社会对频繁请求进行限制我的解决方案是随机延迟1-3秒 between请求轮换User-Agent使用代理IP池需合规使用from time import sleep import random user_agents [ Mozilla/5.0 (Windows NT 10.0; Win64; x64), Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) ] def safe_request(url): headers {User-Agent: random.choice(user_agents)} sleep(random.uniform(1, 3)) return requests.get(url, headersheaders)6. 完整代码示例与使用说明下面是我一直在用的增强版脚本框架包含所有上述功能import requests import json from pathlib import Path import sqlite3 from datetime import datetime import random from time import sleep class GenshinSpider: def __init__(self): self.base_url https://api.miyoushe.com/xxx self.db_conn sqlite3.connect(genshin.db) self._init_db() def _init_db(self): c self.db_conn.cursor() c.execute(CREATE TABLE IF NOT EXISTS images (id TEXT PRIMARY KEY, title TEXT, character TEXT)) self.db_conn.commit() def get_existing_ids(self): c self.db_conn.cursor() c.execute(SELECT id FROM images) return {row[0] for row in c.fetchall()} def crawl(self, max_page10): existing_ids self.get_existing_ids() page 1 while page max_page: data self._fetch_page(page) if not data[list]: break for item in data[list]: if item[id] not in existing_ids: self._process_item(item) page 1 def _fetch_page(self, page): # 实现分页请求逻辑 pass def _process_item(self, item): # 实现图片下载和分类 pass if __name__ __main__: spider GenshinSpider() spider.crawl(max_page20)使用前需要替换base_url为实际API地址建议先用浏览器开发者工具获取最新的接口信息。运行后会自动创建genshin.db数据库记录爬取状态图片按角色/画师/月份分类存储在images目录下。