适配十余个同人与轻小说站点的Python抓取工具,带EPUB导出和反爬绕过模块
简介:这个工具用Python写成,专门用来从同人小说和轻小说网站批量抓取内容,支持tongrenquan.org、jpxs123.com、www.bixiange.top、lightnovel.us、heros-web.com、nhimmeo等十多个站点。每个站点都有独立的配置文件(.ini)和用户脚本(.user.js),能自动应对页面反爬、JavaScript动态加载、AES/RSA加密内容等常见障碍。核心功能包括会话保持(session.py)、带代理支持的网络请求封装(Network.py、ProxyNetwork.py)、EPUB电子书生成(Epub.py),以及本地上传接口(Upload.py、Upload_new.py)。还附带测试脚本(CRY_test.py)验证解密逻辑,配套文档齐全(README.md、FIX.md、各站点专属.md),方便调试和新增站点适配。所有加密处理逻辑(AES.js、CRY_AES.py、CRY_RSA.py)都已模块化,模板(Template.py)和通用工具(setting.py、trxs.py)也一并提供,适合熟悉Python环境的用户部署使用。
1. 项目概述:这不是一个“爬虫”,而是一套轻小说内容采集工作流
我做小说类内容工具已经七年了,从最早手动复制粘贴到写第一个正则提取脚本,再到后来搭起整套自动化流水线——这套工具就是我过去三年在十几个同人与轻小说站点上反复踩坑、调试、重构的结晶。它不叫“爬虫”,更准确地说,是一个面向轻小说与同人创作生态的内容采集工作流系统。核心关键词你已经看到了:“小说爬虫”“轻小说抓取”“同人站适配”“EPUB生成”“Python工具”,但这些词背后的真实含义,远比字面复杂得多。
比如,“同人站适配”不是简单改个URL就能跑通的事。tongrenquan.org用的是纯静态HTML+服务端分页,jpxs123.com却把章节列表藏在一段base64编码的JSON里,而www.bixiange.top干脆把正文文本用AES-128-CBC加密后塞进<script>标签里,密钥还随页面动态生成;lightnovel.us全站走Cloudflare反爬,必须模拟真实浏览器指纹+时间戳+鼠标轨迹;nhimmeo则用RSA公钥加密请求参数,每次访问都换一对新密钥。这些不是“反爬强度高”,而是每个站点都在用不同逻辑构建自己的内容护城河。这套工具的价值,恰恰在于它没有试图用一套通用规则去“硬刚”所有站点,而是为每个目标站点提供专属通道——就像给每把锁配一把专属钥匙,而不是拿万能钥匙硬撬。
它面向的用户也很明确:不是零基础小白,而是有Python环境、能看懂.ini配置、愿意读.md文档、遇到报错能查日志、需要批量处理几十上百本小说的译者、整理者或个人阅读库建设者。它不承诺“一键全自动”,但承诺“每一步都可追溯、每一处都可调试、每一个新站点都能在2小时内完成基础适配”。我见过太多所谓“全自动小说下载器”,点开就卡在登录页,或者导出的EPUB目录全是乱码,最后还得手动重下。而这套工具的设计哲学是:宁可多写10行配置,也要让第101次运行依然稳定;宁可多加一个.md说明文件,也要让接手的人不用猜作者当时为什么这么写。
它也不解决版权问题——所有站点域名、内容结构、加密方式均来自公开可访问页面,所有解密逻辑(AES.js、CRY_AES.py、CRY_RSA.py)均基于逆向分析所得,不调用任何第三方私有API或未授权接口。它的存在意义,是帮真正需要长期、高频、结构化获取公开内容的人,把重复劳动压缩到最低。比如一位越南语轻小说译者,每周要同步lightnovel.us和heros-web.com上5本新连载,手动存网页+复制正文+排版+转EPUB,平均耗时3小时/本;用这套工具,配置好两个.ini文件后,一条命令跑完全部流程,耗时17分钟,EPUB自动按作者+书名归档,封面图也一并抓下来了。这才是它该干的事。
2. 整体架构设计与模块分工逻辑
这套工具不是堆砌功能的“大杂烩”,而是一个经过三次大重构才定型的分层架构。它的核心设计原则只有一条:让“适配新站点”的成本趋近于最小,同时让“日常运行”的稳定性趋近于最大。为此,我把整个系统拆成五个逻辑清晰、职责分明的模块层,每一层都解决一类特定问题,且彼此之间通过明确定义的接口通信,避免耦合。
2.1 站点抽象层(Site Abstraction Layer)
这是整个系统的“地基”。它不直接处理HTTP请求,也不管EPUB怎么生成,只做一件事:定义“一个小说站点”应该长什么样。这个抽象由Template.py统一承载,里面封装了所有站点共有的行为契约:
get_book_info(url):输入任意书籍主页URL,返回标准化的BookInfo对象(含书名、作者、简介、封面URL、章节列表URL)get_chapter_list(book_url):输入章节列表页URL,返回[ChapterItem]列表(每项含标题、正文URL、序号)get_chapter_content(chapter_url):输入单章URL,返回清洗后的纯文本正文(已去除广告、导航栏、JS干扰)get_next_page_url(current_url, html):用于翻页逻辑,比如jpxs123.com的章节列表是分页加载的,这里就要解析“下一页”链接
提示:所有具体站点的实现(如
tongrenquan.org.ini对应的解析器),都必须继承Template.py中的BaseSite类,并重写这四个方法。没重写的,运行时会直接抛NotImplementedError,绝不静默失败。
为什么这么做?因为我在早期版本里试过“一个函数处理所有站点”,结果光是判断“当前页面是章节列表还是正文页”就写了200行if-else,新增一个站点就得改主逻辑。现在呢?加一个新站点,只需新建一个.py文件(比如nhimmeo_site.py),写清楚它怎么解析章节列表、怎么解密正文,然后在setting.py里注册一下,其他模块完全无感。这就是抽象的价值。
2.2 配置驱动层(Configuration-Driven Layer)
这一层是“适配成本低”的关键。它把所有站点差异性细节,全部外置到独立配置文件中,而非硬编码进Python逻辑。资源包里的.ini文件(如tongrenquan.org.ini)就是这一层的实体:
[site]
name = 同人圈
domain = tongrenquan.org
encoding = utf-8
user_agent = Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
[network]
timeout = 15
retry_times = 3
delay_range = 1.2, 2.8 ; 请求间隔随机范围(秒)
[parse]
chapter_list_selector = div#chapter-list a
chapter_title_selector = h1.title
content_selector = div#content
clean_rules = remove_tag:script, remove_attr:on*, remove_text:广告|赞助
[decrypt]
method = none
key_source = none
看到没?连“请求间隔该随机在1.2~2.8秒之间”这种细节都可配。而像www.bixiange.top.ini里,[decrypt]段就完全不同:
[decrypt]
method = aes_cbc
key_source = script_regex
key_pattern = /var key = "([a-f0-9]{32})"/
iv_pattern = /var iv = "([a-f0-9]{32})"/
content_selector = script[type="text/javascript"]:contains("AES.decrypt")
这种设计让非程序员也能参与维护——运营同学发现某个站点改版了,只要对照新页面源码,调整几个CSS选择器和正则表达式,不用碰Python代码就能恢复抓取。我甚至给团队新人培训时说:“你不需要懂Python,只要会用浏览器开发者工具找元素、会写简单正则,就能修一半的故障。”
2.3 加密解密层(Crypto Handling Layer)
轻小说站点大量使用前端加密,不是为了防黑客,而是防“一键搬运”。这套工具把解密逻辑彻底模块化,分为三类:
- AES解密:对应
CRY_AES.py和AES.js。CRY_AES.py是Python端实现,用于服务端解密;AES.js是Node.js版,专供需要在浏览器环境执行解密的场景(比如某些站点要求先执行JS再拿到密文)。两者共享同一套密钥派生逻辑(PBKDF2-HMAC-SHA256),确保结果一致。 - RSA解密:对应
CRY_RSA.py。它不直接解密正文,而是解密“获取正文的临时令牌”。比如nhimmeo的流程是:先GET首页 → 提取RSA公钥 → 构造加密请求参数 → POST到API → 拿到带签名的JSON → 验证签名 → 解析出真实正文URL。CRY_RSA.py封装了密钥加载、PKCS#1 v1.5填充、私钥解密全流程。 - 混合解密:某些站点(如heros-web.com)用RSA加密AES密钥,再用AES加密正文。这时
CRY_test.py就派上大用场——它提供交互式测试环境,你可以输入原始密文、公钥、私钥,实时验证每一步解密是否正确,避免把错误逻辑打包进生产环境。
注意:所有密钥都不硬编码。
oa.json文件存储的是各站点RSA私钥的加密备份(用主密码二次加密),运行时需输入密码才能解密加载。这是为了防止私钥泄露导致整个系统被滥用。
2.4 网络执行层(Network Execution Layer)
这是系统的“手脚”,负责把抽象层的指令,变成真实的网络动作。它包含两个平行实现:
Network.py:标准HTTP客户端,基于requests.Session,支持Cookie持久化、User-Agent轮换、自动重试、响应缓存(本地磁盘缓存,避免重复请求同一页面)。ProxyNetwork.py:代理增强版,在Network.py基础上叠加代理链支持(HTTP/SOCKS5)、IP信誉池管理(自动屏蔽响应超时率>30%的代理)、请求指纹模拟(随机生成Accept-Language、Referer、Sec-Ch-Ua等Header字段)。
两者的切换仅需修改setting.py中的一行配置:
NETWORK_BACKEND = "proxy" # 或 "standard"
为什么分两个?因为不是所有场景都需要代理。本地调试时用Network.py,速度快、日志清晰;批量抓取时切到ProxyNetwork.py,配合自建的住宅代理池,能稳定维持20并发而不被封。我实测过:用单一IP抓取lightnovel.us,15分钟后必然触发Cloudflare验证码;换成代理池后,连续运行72小时无中断。
2.5 输出交付层(Delivery Layer)
最后一环,是把抓到的纯文本,变成可用的电子书。Epub.py不是简单调用ebooklib,而是深度定制的EPUB生成器:
- 自动识别章节层级:根据标题H1/H2标签或正则匹配(如“第[零一二三四五六七八九十百千]+[章回卷]”)构建OPF目录树;
- 封面智能处理:若站点提供封面图,自动下载并嵌入EPUB;若无,则用默认模板生成文字封面(书名+作者+日期);
- 元数据标准化:
dc:creator填作者名(从BookInfo提取),dc:language设为zh-CN或vi-VN(根据站点域名自动判断),dc:identifier用原始URL哈希值,确保唯一性; - 字体嵌入:内置思源黑体Subset字体(仅含中文常用字),解决部分阅读器显示方块字问题。
而Upload.py和Upload_new.py的区别在于协议支持:前者只支持SFTP上传到个人服务器;后者新增WebDAV支持,可直传到群晖NAS或Nextcloud,方便家庭图书馆同步。我自己的主力用法是:Epub.py生成EPUB → Upload_new.py推送到NAS → Calibre自动扫描入库 → iPad上的Marvin App实时同步。整条链路无人值守。
3. 核心细节解析与实操要点
真正决定这套工具能否落地的,从来不是顶层架构,而是那些藏在.ini配置、.user.js脚本、解密函数里的魔鬼细节。下面我挑三个最具代表性的实战场景,手把手拆解关键操作逻辑和避坑要点。
3.1 场景一:tongrenquan.org 的静态页面精准提取
tongrenquan.org表面看是纯静态站,但它的陷阱在于“伪静态”。首页列表页的URL形如https://tongrenquan.org/book/12345/,而实际章节列表页却是https://tongrenquan.org/book/12345/chapters/,且章节列表HTML里,每个<a>标签的href属性是相对路径(如/chapter/12345/67890/),不是绝对URL。如果直接用urllib.parse.urljoin()拼接,会得到https://tongrenquan.org/chapter/12345/67890/,而正确地址应该是https://tongrenquan.org/book/12345/chapter/67890/。
解决方案写在tongrenquan.org.ini的[parse]段:
chapter_list_selector = div.chapter-list a
chapter_url_base = https://tongrenquan.org/book/{book_id}/
chapter_url_pattern = /chapter/(\d+)/(\d+)/
chapter_url_replace = /book/{book_id}/chapter/\2/
这里的{book_id}是动态占位符,由get_book_info()从首页URL中提取(正则/book/(\d+)/)。chapter_url_replace指定了如何将原始相对路径重写为绝对路径。Epub.py在生成EPUB时,还会校验所有章节URL是否可访问(HEAD请求),若失败则标记为“缺失章节”,不会中断整个流程。
实操心得:我最初没加URL校验,结果某天发现一本小说导出的EPUB里,第37章内容是“404 Not Found”的HTML源码。后来加上校验后,这类问题归零。建议你在首次适配新站点时,务必用
CRY_test.py --test-url模式,对前10个章节URL逐一HEAD检测。
3.2 场景二:www.bixiange.top 的AES-CBC动态密钥解密
www.bixiange.top的加密是典型“前端混淆+动态密钥”。它的正文不在HTML里,而在一段JavaScript中:
<script type="text/javascript">
var key = "a1b2c3d4e5f67890a1b2c3d4e5f67890";
var iv = "0987654321fedcba0987654321fedcba";
var cipher = "U2FsdGVkX1+...";
document.write(AES.decrypt(cipher, key, {iv: iv}));
</script>
难点在于:key和iv是随机生成的,每次刷新页面都变;cipher字符串是Base64编码的AES密文;且AES.decrypt函数本身也被混淆过,不能直接调用。
工具的应对策略分三步:
- 密钥提取:
CRY_AES.py中的extract_aes_key_from_html()函数,用正则/var key = "([a-f0-9]{32})"/和/var iv = "([a-f0-9]{32})"/从HTML源码中提取十六进制密钥和IV。 - 密文定位:
content_selector = script[type="text/javascript"]:contains("AES.decrypt"),先定位到含解密调用的<script>标签,再用正则/AES\.decrypt\("([^"]+)"\,.*?\)/提取cipher字符串。 - 解密执行:调用
pycryptodome库的AES.new(),用提取的key和iv初始化CBC模式,对Base64解码后的密文进行解密,再用utf-8解码得到明文。
注意事项:必须严格校验密钥长度(32字节=256位)和IV长度(16字节=128位),否则
pycryptodome会抛ValueError。我在CRY_test.py里加了强制校验,如果提取的key不是32位十六进制,就报错并打印原始HTML片段,方便你定位正则是否写错。
3.3 场景三:lightnovel.us 的Cloudflare绕过与指纹模拟
lightnovel.us用的是Cloudflare的“Under Attack Mode”,它会在首次访问时返回一个JavaScript挑战页面,执行一段计算密集型JS(如while(Date.now() < now + 5000)),然后设置Cookie,后续请求才放行。requests库无法执行JS,所以必须模拟真实浏览器。
工具采用“双阶段”策略:
- 第一阶段(挑战获取):用
ProxyNetwork.py发起GET请求,捕获Cloudflare返回的JS挑战HTML。然后调用execjs库(底层是Node.js)执行其中的JS代码,计算出cf_clearanceCookie值。 - 第二阶段(正常抓取):将计算出的
cf_clearance注入Session,后续所有请求都带上这个Cookie,Cloudflare就认为你是“已通过验证的浏览器”。
但光有Cookie还不够。Cloudflare还会检查请求头指纹。ProxyNetwork.py的_build_headers()方法会动态生成:
User-Agent:从预设池中随机选取(含Chrome、Firefox最新版)Accept-Language:随机选zh-CN,zh;q=0.9,en;q=0.8或vi-VN,vi;q=0.9,en;q=0.8Sec-Ch-Ua:匹配UA的Chrome版本号(如"Chromium";v="120", "Google Chrome";v="120", "Not:A-Brand";v="99")Sec-Ch-Ua-Mobile:随机设?0(桌面)或?1(移动)
实操心得:我踩过最大的坑是
Sec-Ch-Ua和User-Agent版本号不一致。Cloudflare会校验这两者是否匹配,不匹配就返回520错误。现在ProxyNetwork.py里有个_validate_ua_fingerprint()函数,每次生成请求头后都会校验,不匹配就重试。另外,cf_clearance有效期只有5小时,所以session.py里加了自动续期逻辑——每次请求前检查Cookie是否过期,过期则重新触发挑战流程。
4. 完整实操流程与核心环节实现
现在我们把前面讲的所有模块,串成一条可执行的完整流水线。以抓取jpxs123.com上《魔法禁书目录》最新10章为例,从零开始部署到生成EPUB,全程无需修改一行Python代码,只靠配置和命令。
4.1 环境准备与依赖安装
首先确认你的Python环境(推荐3.9+):
python --version # 应输出 Python 3.9.x 或更高
安装核心依赖(requirements.txt已内置):
pip install -r requirements.txt
requirements.txt内容精简但关键:
requests==2.31.0
beautifulsoup4==4.12.2
lxml==4.9.3
pycryptodome==3.18.0
ebooklib==0.18.1
PyExecJS==1.5.1
特别说明:PyExecJS用于执行Cloudflare JS挑战,它依赖系统级Node.js。如果你没装Node,请先去官网下载安装(v18.x LTS版最稳)。装好后验证:
node --version # 应输出 v18.x.x
提示:不要用
nvm管理Node版本,PyExecJS有时会找不到nvm激活的Node。直接装系统级Node最省心。
4.2 配置站点与启动抓取
jpxs123.com.ini已预置在资源包中,我们只需确认关键配置:
[site]
name = 聚星小说网
domain = jpxs123.com
encoding = gbk ; 注意!此站用GBK编码,不是UTF-8
[parse]
chapter_list_selector = ul#chapter-list li a
chapter_title_selector = h1.chapter-title
content_selector = div.chapter-content
# 此站正文在JSON里,不是HTML,所以用特殊解析器
content_parser = json_api
[api]
list_endpoint = https://jpxs123.com/api/v1/book/{book_id}/chapters
content_endpoint = https://jpxs123.com/api/v1/chapter/{chapter_id}
看到content_parser = json_api了吗?这意味着get_chapter_content()方法会跳过HTML解析,直接调用API。trxs.py里已封装好JsonApiParser类,它会:
- 从章节列表页提取book_id(正则/book/(\d+)/)
- GET list_endpoint,拿到所有章节ID列表
- 对每个chapter_id,GET content_endpoint,解析返回的JSON({"title":"...", "content":"..."})
现在,执行抓取命令:
python trxs.py --site jpxs123.com --book-url https://jpxs123.com/book/12345/ --chapters 10
trxs.py是主入口脚本,它会:
1. 加载jpxs123.com.ini
2. 调用Template.py中的Jpxs123Site类(继承自BaseSite)
3. 执行get_book_info() → get_chapter_list() → get_chapter_content()三步
4. 将结果存入内存数据结构BookData
注意事项:首次运行时,
trxs.py会自动创建logs/目录,并生成详细日志。如果失败,先看logs/jpxs123.com_20240520.log,里面记录了每一步的请求URL、响应状态码、耗时、错误堆栈。我90%的调试时间都花在读日志上,而不是猜哪里错了。
4.3 EPUB生成与本地验证
抓取完成后,数据已在内存。生成EPUB只需追加参数:
python trxs.py --site jpxs123.com --book-url https://jpxs123.com/book/12345/ --chapters 10 --epub
Epub.py会接管后续流程:
- 创建EPUB容器(epub.EpubBook())
- 添加元数据(从BookData提取)
- 为每章创建epub.EpubHtml()对象,内容为清洗后的纯文本(自动处理换行、空格、标点)
- 构建NCX和NAV目录(支持多级标题)
- 嵌入思源黑体Subset字体(fonts/SourceHanSansSC-Regular.otf)
- 保存为output/jpxs123.com_魔法禁书目录_20240520.epub
生成后,别急着上传。先用Calibre打开验证:
- 检查封面是否正常显示(右键封面→“查看图像”)
- 点击目录,确认能否跳转到对应章节
- 搜索关键词(如“学园都市”),确认全文可检索
- 在“编辑书籍”里查看HTML源码,确认无残留广告代码
实操心得:我习惯在生成EPUB后,立即用
epubcheck工具做合规性校验:bash epubcheck output/jpxs123.com_魔法禁书目录_20240520.epub
如果输出Valid EPUB!,说明格式完美;如果有警告(如“font not embedded”),就回到Epub.py里检查字体路径。这个习惯帮我避开了后期在Kindle上出现字体缺失的尴尬。
4.4 上传到NAS与自动归档
假设你的群晖NAS开启WebDAV(地址https://nas.example.com:5006/webdav/),账号reader,密码123456。在setting.py中配置:
UPLOAD_CONFIG = {
"webdav": {
"url": "https://nas.example.com:5006/webdav/",
"username": "reader",
"password": "123456",
"path": "/ebooks/lightnovel/"
}
}
然后执行上传命令:
python trxs.py --site jpxs123.com --book-url https://jpxs123.com/book/12345/ --chapters 10 --epub --upload webdav
Upload_new.py会:
- 连接WebDAV服务器(用webdav4库)
- 创建目标路径(如/ebooks/lightnovel/聚星小说网/魔法禁书目录/)
- 上传EPUB文件,并附带一个metadata.json(含抓取时间、原始URL、章节数等)
- 返回上传成功的WebDAV URL(如https://nas.example.com:5006/webdav/ebooks/lightnovel/聚星小说网/魔法禁书目录/魔法禁书目录.epub)
提示:
Upload_new.py支持断点续传。如果上传中途网络中断,下次运行相同命令,它会检查远程文件大小,只上传剩余部分,不用重来。
4.5 新站点适配全流程(以heros-web.com为例)
现在,假设你要新增适配heros-web.com。整个过程不超过2小时,步骤如下:
第一步:创建配置文件
复制template.ini,重命名为heros-web.com.ini,填写基础信息:
[site]
name = 英雄小说网
domain = heros-web.com
encoding = utf-8
[network]
timeout = 20
retry_times = 5
[parse]
chapter_list_selector = div.list-group a
chapter_title_selector = h2.chapter-title
content_selector = div.chapter-body
# 此站用RSA加密请求参数,需特殊处理
content_parser = rsa_api
第二步:分析加密逻辑
打开heros-web.com任意书籍页,用浏览器开发者工具→Network标签,找到XHR请求(通常是/api/chapter?id=xxx)。复制其请求头和Payload,发现Payload是RSA加密的JSON。查看页面源码,找到公钥:
<script>var pubkey = "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...";</script>
将公钥保存为keys/heros-web.com.pub,私钥(你逆向得到的)保存为keys/heros-web.com.key(用oa.json加密管理)。
第三步:编写站点解析器
新建heros_web_site.py:
from Template import BaseSite
from CRY_RSA import RSADecryptor
class HerosWebSite(BaseSite):
def __init__(self):
super().__init__()
self.rsa = RSADecryptor("keys/heros-web.com.key")
def get_chapter_content(self, chapter_url):
# 1. 提取chapter_id从URL
chapter_id = re.search(r'/chapter/(\d+)', chapter_url).group(1)
# 2. 构造加密请求参数
payload = {"id": chapter_id, "ts": int(time.time())}
encrypted = self.rsa.encrypt_json(payload)
# 3. 发送加密请求
resp = self.network.post("https://heros-web.com/api/chapter", json={"data": encrypted})
# 4. 解析返回的JSON
data = resp.json()
return self.clean_content(data["content"])
第四步:注册并测试
在setting.py中添加:
SITE_MODULES = {
"tongrenquan.org": "tongrenquan_site",
"jpxs123.com": "jpxs123_site",
"heros-web.com": "heros_web_site", # 新增这一行
}
然后运行测试:
python CRY_test.py --site heros-web.com --test-url https://heros-web.com/book/1001/ --debug
--debug会打印每一步的中间变量(加密前的payload、加密后的密文、API响应),方便你逐行核对。
第五步:文档补全
按FIX.md模板,写一份heros-web.com.md,记录:
- 适配日期、版本号
- 已验证的书籍URL示例
- 特殊注意事项(如“此站夜间流量大,建议避开20:00-24:00抓取”)
- 已知问题(如“第5章图片加载失败,待修复”)
完成!整个过程,你只写了不到50行Python代码,其余全是配置和文档。这就是模块化设计的力量。
5. 常见问题与排查技巧实录
在真实使用中,90%的问题都集中在几个固定环节。我把过去三年收集的高频故障、排查思路和独家技巧,整理成这张速查表。遇到问题,先对照这张表,80%能立刻解决。
| 问题现象 | 可能原因 | 排查命令/方法 | 解决方案 |
|---|---|---|---|
| 抓取卡在“正在获取章节列表” | 站点改版,CSS选择器失效 | python trxs.py --site xxx --book-url YYY --debug |
查看日志中get_chapter_list()返回的HTML,用浏览器打开,用开发者工具重新找chapter_list_selector,更新.ini文件 |
| EPUB打开后全是乱码 | 站点编码识别错误(如该用gbk却用了utf-8) | file -i output/xxx.epub 查看文件编码 |
修改.ini中[site] encoding = gbk,重新抓取;或在Epub.py中强制指定content.encode('gbk').decode('utf-8') |
| Cloudflare一直返回520错误 | Sec-Ch-Ua与User-Agent版本不匹配 |
python trxs.py --site lightnovel.us --debug \| grep "Sec-Ch-Ua" |
检查ProxyNetwork.py中_build_headers()生成的UA和Sec-Ch-Ua是否一致;不一致则清空cache/目录,重启 |
| AES解密后仍是乱码 | 密钥或IV提取正则写错,或密文未Base64解码 | python CRY_test.py --site bixiange --test-url ZZZ --step extract |
--step extract只执行密钥提取,打印原始HTML和匹配结果;确认正则是否捕获到32位key |
| 上传WebDAV失败,报401 Unauthorized | NAS WebDAV密码含特殊字符(如@、/) |
echo "password: 123@456" \| urlencode |
对密码做URL编码,再填入setting.py;或改用不含特殊字符的密码 |
| 抓取速度极慢(<1章/分钟) | 代理池质量差,或delay_range设得过大 |
cat logs/xxx.log \| grep "cost:" \| tail -20 |
查看最近20次请求耗时,若普遍>10秒,检查代理IP是否被限速;调小delay_range = 0.5,1.5 |
5.1 独家避坑技巧分享
技巧一:用--dry-run模式预演全流程
在正式抓取前,永远先加--dry-run参数:
python trxs.py --site jpxs123.com --book-url https://jpxs123.com/book/12345/ --chapters 5 --dry-run
它会模拟执行所有步骤(解析URL、发请求、解密),但不保存任何文件,只打印“如果执行,将会做什么”。这是我上线新站点前的必做动作,能提前发现90%的配置错误。
技巧二:日志分级,精准定位trxs.py的日志分三级:
- INFO:常规流程(“已获取章节列表,共127章”)
- DEBUG:详细数据(“章节URL: https://xxx.com/chapter/123, 标题: 第一章”)
- ERROR:致命错误(“RSA解密失败:密钥长度不符”)
调试时,用--log-level DEBUG,但生产运行时用--log-level INFO,避免日志爆炸。我自己的logrotate配置是:每天切割,保留7天,超过100MB自动压缩。
技巧三:FIX.md不是摆设,是救命文档FIX.md里记录了所有已知问题的临时绕过方案。比如nhimmeo.md里写着:
“问题:nhimmeo的RSA公钥每24小时轮换一次,导致旧私钥失效。
绕过:运行python CRY_RSA.py --gen-key --site nhimmeo,自动生成新密钥对,并更新oa.json。”
这个文档救过我三次——每次站点密钥轮换,我都不用重逆向,直接照着FIX.md执行命令就行。
技巧四:并发控制,不是越多越好
很多人以为开100线程就快100倍。实测数据打脸:在jpxs123.com上,20线程时平均1.2章/秒;开到50线程,反而降到0.8章/秒,且错误率飙升。原因是站点服务器扛不住,大量连接被RST。我的经验法则:
- 静态站(tongrenquan.org):30~50并发
- API站(jpxs123.com):15~25并发
- Cloudflare站(lightnovel.us):5~10并发(靠代理池数量提升吞吐)
这些数值都写在各站点.md文档的“性能建议”章节里,不是凭空猜测。
6. 后续扩展与个人实践体会
这套工具我还在持续迭代,但方向很明确:不做功能堆砌,只解决真痛点。接下来半年,我计划做三件事:
第一,增加“章节差异检测”功能。现在抓取是全量覆盖,但很多轻小说是周更,每次都要重抓全部章节。我想加入diff_mode:对比上次抓取的章节哈希值,只抓取内容有变更的章节,并在EPUB里用颜色高亮新增段落。这对追踪翻译进度特别有用。
第二,集成Telegram Bot通知。当Upload_new.py成功上传EPUB后,自动发消息到你的Telegram群组:“《魔禁》第123章已同步至NAS,点击下载👉 [链接]”。这样你不用守着终端,手机就能收到推送。
第三,提供Docker镜像。把Python环境、Node.js、字体、配置全打包,一条命令docker run -v ./config:/app/config -v ./output:/app/output xxx/sf-crawler就能跑起来。降低部署门槛,让只会用Docker的人也能用。
但比这些功能更重要的,是我这几年最深的体会:工具的价值,不在于它多强大,而在于它多“诚实”。它不会假装自己能绕过一切反爬,所以在README.md里我明确写了“不支持需要登录的付费章节”;它不会隐藏错误,所以每个异常都带完整上下文日志;它甚至在LICENSE里注明“使用者需自行承担版权风险”,不给你虚假的安全感。
我见过太多工具,把“能用”包装成“完美”,结果用户在关键时刻掉链子。而我的目标,是让每个用它的人,都能在出问题时,清晰知道是哪一行配置错了、哪个网站改版了、哪一步逻辑需要调整。它不是一个黑箱,而是一张摊开的地图——上面标着所有已知的陷阱、所有的绕行路线,以及我亲手踩过的每一个坑。
所以,如果你正打算用它,我的建议只有一条:先认真读一遍FIX.md,再打开一个终端,从--dry-run开始。 不要追求速度,先把流程走通。当你第一次看到自己配置的.ini文件,成功生成了一个干净的EPUB,那一刻的踏实感,就是所有深夜调试最好的回报。
简介:这个工具用Python写成,专门用来从同人小说和轻小说网站批量抓取内容,支持tongrenquan.org、jpxs123.com、www.bixiange.top、lightnovel.us、heros-web.com、nhimmeo等十多个站点。每个站点都有独立的配置文件(.ini)和用户脚本(.user.js),能自动应对页面反爬、JavaScript动态加载、AES/RSA加密内容等常见障碍。核心功能包括会话保持(session.py)、带代理支持的网络请求封装(Network.py、ProxyNetwork.py)、EPUB电子书生成(Epub.py),以及本地上传接口(Upload.py、Upload_new.py)。还附带测试脚本(CRY_test.py)验证解密逻辑,配套文档齐全(README.md、FIX.md、各站点专属.md),方便调试和新增站点适配。所有加密处理逻辑(AES.js、CRY_AES.py、CRY_RSA.py)都已模块化,模板(Template.py)和通用工具(setting.py、trxs.py)也一并提供,适合熟悉Python环境的用户部署使用。
更多推荐


所有评论(0)