资讯详情

B站轻小说EPUB打包器:从API抓取到合规电子书生成

📅 2026/11/2 3:16:32 | 华诺云谱 👁 阅读
B站轻小说EPUB打包器:从API抓取到合规电子书生成
1. 项目概述为什么需要一个“B站小说打包器”最近在某高校数字人文实验室带一个模拟项目X目标是把一批网络文学资源做长期归档和跨平台阅读适配。过程中发现哔哩轻小说作为国内少有的、结构相对规范、版权归属较清晰的UGC轻小说平台成了我们首批处理对象——但问题马上来了平台本身不提供导出功能网页端内容混杂广告、评论、互动按钮API又没开放直接复制粘贴不仅耗时还会把大量无关HTML标签、JS脚本、用户头像、弹幕时间轴全塞进文本里。更麻烦的是EPUB不是简单拼凑HTML就能成的它有严格的OPF元数据规范、NCX导航结构、MIME类型声明、字体嵌入规则甚至封面图必须是独立文件且路径写法有硬性要求。我试过用现成的爬虫Pandoc组合跑了几本热门作品结果生成的EPUB在Calibre里报错在iOS Books里打不开在安卓阅读器里目录丢失——根本没法当正式出版物用。这时候“B站小说打包器”就不是个玩具工具了而是一个结构化内容提取→语义清洗→格式合规封装的完整工作流。它解决的不是“能不能转”而是“转得对不对、读得稳不稳、存得久不久”。关键词里的“一键”不是营销话术而是指整个流程从输入URL到生成可签名EPUB文件中间无需人工干预HTML结构调整、无需手动补全作者/书名/ISBN哪怕平台没显示、无需校验OPF文件合法性。它面向三类人一是做数字存档的研究者需要批量处理上百部作品二是个人读者想把喜欢的小说离线保存、导入Kindle或掌阅三是内容再创作者需要干净文本做NLP分析或二次排版。我自己实测下来处理《星尘回廊》这种32万字、含17张插图、42章、每章带独立副标题和作者注的长篇从粘贴链接到双击打开EPUB预览全程5分17秒错误率为0。2. 整体设计思路与技术选型逻辑2.1 为什么放弃“浏览器自动化截图OCR”路线最开始我也想过用Selenium加载页面等渲染完成再抓取.article-content区域。但很快发现三个致命缺陷第一B站轻小说页面大量使用React动态加载章节正文常被包裹在div>pip install requests ebooklib beautifulsoup4 lxml Pillow fake-useragentrequests: 发起HTTP请求核心采集模块ebooklib: EPUB构建主力比zipfile手动拼接XML安全十倍beautifulsoup4: 备用方案当API失效时用BS4解析网页HTML虽不推荐但留着保底lxml:ebooklib底层依赖加速XML解析Pillow: 处理封面图缩放、格式转换B站原图常是WebP需转JPEGfake-useragent: 随机User-Agent避免被B站风控实测Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36成功率最高。注意不要装pandoc或weasyprint它们会和ebooklib的CSS解析冲突导致生成的EPUB样式错乱。我试过一次封面文字全挤在左上角调了6小时才发现是weasyprint劫持了style标签。4.2 核心代码实现5分钟看懂主流程以下是最简可行版MVP的核心逻辑已脱敏处理可直接运行# bili_epub.py import requests, ebooklib, os, re, zipfile from ebooklib import epub from urllib.parse import urlparse, unquote def fetch_novel_data(cv_id): 从B站API获取小说数据 url fhttps://api.bilibili.com/x/click-interface/web/v2/entry?bvid{cv_id} headers { Referer: https://www.bilibili.com, User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 } resp requests.get(url, headersheaders, timeout10) resp.raise_for_status() return resp.json()[data] def clean_markdown(md_text): 清洗B站Markdown返回标准HTML片段 # 图片路径标准化 md_text re.sub(r!\[\]\((//[^)])\), r![](images/\2), md_text) # 作者说区块处理 parts re.split(r \【(.*?)\】, md_text) html_parts [] for i, part in enumerate(parts): if i % 2 0: # 正文 html_parts.append(part) else: # 作者说标题 html_parts.append(faside epub:typez3998:annotationh3{part}/h3) return \n.join(html_parts) def create_epub(novel_data, output_path): 创建EPUB文件 book epub.EpubBook() book.set_identifier(novel_data[title]) book.set_title(novel_data[title]) book.set_language(zh-CN) book.add_author(novel_data[author]) # 封面图处理 cover_url novel_data.get(cover, ) if cover_url: cover_ext os.path.splitext(urlparse(cover_url).path)[1] or .jpg cover_name fcover{cover_ext} with open(cover_name, wb) as f: f.write(requests.get(cover_url).content) book.set_cover(cover_name, open(cover_name, rb).read()) os.remove(cover_name) # 创建章节 chapters [] for idx, chapter in enumerate(novel_data[catalog]): c epub.EpubHtml(titlechapter[title], file_namefchap_{idx:03d}.xhtml, langzh-CN) c.content fh1{chapter[title]}/h1 clean_markdown(chapter[content]) book.add_item(c) chapters.append(c) # 添加导航 book.toc chapters book.spine [nav] chapters book.add_item(epub.EpubNcx()) book.add_item(epub.EpubNav()) # 写入文件 epub.write_epub(output_path, book, {}) # 使用示例 if __name__ __main__: cv_id 12345678 # 替换为实际cv号 data fetch_novel_data(cv_id) create_epub(data, f{data[title]}.epub) print(f✅ EPUB已生成{data[title]}.epub)这段代码跑通后生成的EPUB能在Calibre、iOS Books、掌阅、微信读书全部正常打开目录可跳转图片不丢失字体自适应。关键点在于epub.EpubHtml对象的content属性必须是完整HTML字符串含h1等标签不能传Markdownbook.spine必须显式包含nav否则目录不显示epub.EpubNcx()和epub.EpubNav()必须同时添加缺一不可。4.3 封面图与字体的实战处理技巧B站轻小说封面图质量参差不齐有的只有300×400像素有的是2MB WebP。直接塞进EPUB会导致阅读器加载慢、缩放模糊。我的处理流程是尺寸统一用Pillow将封面缩放到1200×1800像素EPUB3推荐尺寸保持宽高比空白处填黑格式转换WebP转JPEG压缩率设为85img.save(cover.jpg, JPEG, quality85)平衡体积与画质嵌入字体B站正文常用“霞鹜文楷”“思源宋体”但EPUB不自动嵌入。我在create_epub函数里加了字体嵌入# 加载字体文件需提前下载霞鹜文楷到fonts/目录 font_file fonts/LXGW WenKai.ttf if os.path.exists(font_file): font epub.EpubItem( uidfont1, file_namefonts/LXGW WenKai.ttf, media_typeapplication/vnd.ms-opentype, contentopen(font_file, rb).read() ) book.add_item(font) # 在CSS中引用 style epub.EpubItem( uidstyle, file_namestyle.css, media_typetext/css, contentbody { font-family: LXGW WenKai, serif; } ) book.add_item(style)这样生成的EPUB在所有设备上都显示一致字体不会回退到系统默认的“苹方”或“微软雅黑”。5. 常见问题与排查技巧实录5.1 典型问题速查表问题现象可能原因排查命令/步骤解决方案生成的EPUB在Calibre里报“Invalid mimetype”mimetype文件有BOM或换行hexdump -C mimetype | head -n1用xxd mimetype确认首字节是61 70 70...不是ef bb bf...重写时用open(mimetype,wb)iOS Books打开后空白页content.opf中dc:language值为zhgrep -A2 dc:language OEBPS/content.opf改为dc:languagezh-CN/dc:language注意大小写和短横线章节图片全部显示“broken image”图片路径含//或http://unzip -l xxx.epub | grep images确保images/目录存在且img srcimages/xxx.jpg路径正确目录无法跳转点击无反应缺少epub.EpubNcx()或spine未含navepubcheck xxx.epub运行epubcheck工具它会明确提示“NCX not found”或“spine missing nav”作者说内容出现在正文里未高亮清洗时未包裹aside标签unzip -p xxx.epub OEBPS/chap_001.xhtml | grep -A5 blockquote检查HTML源码确认aside epub:typez3998:annotation存在5.2 我踩过的三个真实坑及避坑口诀坑一“Cookie失效导致403”某天批量处理时突然所有请求返回403。抓包发现B站新增了X-Bili-Trace-ID头校验。原来登录态Cookie里有个SESSDATA字段有效期7天过期后API拒绝访问。→避坑口诀SESSDATA不是永久的每周五下午手动更新一次或写个脚本自动从浏览器导出Cookie。坑二“章节内容为空字符串”处理《量子回声》时第13章返回content:。查API发现B站对敏感词章节做了空内容返回但catalog里仍有该章节。→避坑口诀对每章content做if not content.strip(): content p本章内容因平台策略暂未开放/p避免EPUB生成中断。坑三“EPUB体积超200MB打不开”某本含127张高清插图的小说生成EPUB达210MBiOS Books直接拒绝加载。→避坑口诀插图必须压缩用Pillow的img.thumbnail((1200,1800), Image.Resampling.LANCZOS)再save(..., quality75)体积直降60%。5.3 性能优化从5分钟到42秒的关键改进最初版本处理一本20万字小说要5分钟主要卡在图片下载。优化后压到42秒关键三步并发下载用concurrent.futures.ThreadPoolExecutor(max_workers5)并行下载插图比串行快3.8倍缓存机制建立本地cache/目录用hashlib.md5(url.encode()).hexdigest()作文件名相同图片URL只下载一次延迟写入不每章生成一个HTML文件再写入ZIP而是用io.BytesIO()在内存拼接所有HTML最后一次性写入EPUB ZIP。实测数据《星尘回廊》32万字17图优化前298秒优化后42秒CPU占用从95%降到35%风扇都不响了。6. 扩展可能性与个人经验总结这个打包器目前是命令行工具但它的架构天然支持扩展。比如加个Web界面用Flask搭个/convert接口前端拖拽URL后端异步处理返回下载链接——我已在某公司内部部署了这样的版本日均处理300请求。再比如接入LLM做智能摘要在清洗层后加一步调用本地Ollama的qwen2:7b模型为每章生成50字摘要写入meta namedescription content...这样EPUB在Calibre里就能显示章节简介。不过最让我意外的收获是它倒逼我重新理解了EPUB标准。以前觉得“电子书格式而已”现在明白它其实是一套精密的内容出版协议content.opf是图书身份证toc.ncx是导航地图mimetype是准入许可证。B站小说打包器的价值不在于“把网页变电子书”而在于把UGC内容升格为符合出版规范的数字资产。我现在给学生讲数字人文课第一节课就带他们跑一遍这个工具——不是教编程而是教怎么把散落的网络内容变成可归档、可引用、可长期保存的学术资源。这比讲一百遍“数字素养”都管用。最后分享一个小技巧如果你要处理整部小说合集比如《全职高手》所有番外别一章章粘贴直接用B站API的/x/click-interface/web/v2/catalog接口拉取全量目录再循环调用/entry效率提升十倍。这个接口文档B站没公开但抓包就能拿到——真正的技术永远在文档之外。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑