initial commit

This commit is contained in:
kai
2026-03-31 18:18:35 +08:00
commit 97c48995b1
36 changed files with 5985 additions and 0 deletions
Vendored
BIN
View File
Binary file not shown.
+140
View File
@@ -0,0 +1,140 @@
# ZLibrary 电子书下载器
从 [zlib.li](https://zlib.li) 搜索和下载电子书的命令行工具。
## 特性
-**自动绕过反爬保护**:自动解决网站的 SHA1 工作量证明(PoW)挑战
-**智能搜索匹配**:支持书名、作者、ISBN 等多维度匹配
-**格式优先级**:自动选择 epub + pdf 版本下载
-**代理轮询**:支持 ShadowsocksSurge 格式)代理列表,每 IP 5 本后自动切换
-**AI 友好**:JSON 输出,结构化搜索结果,适合 AI Agent 调用
## 安装
```bash
cd /path/to/zlib-dl
python3 -m venv .venv
source .venv/bin/activate
pip install curl_cffi beautifulsoup4 lxml
```
### 代理依赖(全自动)
脚本内置自动代理引擎配置。如果使用 Shadowsocks 代理列表(如 Surge 格式),脚本**会在首次运行时自动将对应平台架构的 `mihomo` 引擎打包进执行环境中**,完全脱离 Host 依赖,无需手动通过 brew 安装任何插件。
## 使用方法
### 搜索图书
```bash
# 按标题和作者搜索
python3 zlib_dl.py search --title "Project Hail Mary" --author "Andy Weir"
# 自由搜索
python3 zlib_dl.py search --query "我从达尔文那里学到的投资知识 普拉克·普拉萨德"
# JSON 输出(AI Agent 推荐)
python3 zlib_dl.py --json search --title "Project Hail Mary" --author "Andy Weir"
# 按 ISBN 搜索
python3 zlib_dl.py search --isbn "9780593355275"
```
### 下载图书
```bash
# 自动搜索 + 下载最佳 epub 和 pdf
python3 zlib_dl.py download --title "Project Hail Mary" --author "Andy Weir"
# 指定下载路径(从搜索结果中获取)
python3 zlib_dl.py download --dl-path "/dl/O2pPQwkq2l" --title "Project Hail Mary" --format epub
# 指定输出目录
python3 zlib_dl.py download --title "Project Hail Mary" --author "Andy Weir" -o ./books
# 使用代理列表
python3 zlib_dl.py download --title "Project Hail Mary" --author "Andy Weir" --proxy-file proxies.txt
```
### 详细模式
```bash
python3 zlib_dl.py --verbose search --title "..."
python3 zlib_dl.py --verbose --json download --title "..."
```
## 代理配置
### Surge Shadowsocks 格式
创建 `proxies.txt`,每行一个代理:
```
🇭🇰 香港 01= ss, server.example.com, 18300, encrypt-method=aes-128-gcm, password=your_password, obfs=http, obfs-host=example.microsoft.com, tfo=true, udp-relay=true
🇭🇰 香港 02= ss, server.example.com, 18305, encrypt-method=aes-128-gcm, password=your_password, obfs=http, obfs-host=example.microsoft.com, tfo=true, udp-relay=true
```
### SOCKS5/HTTP 代理格式
也支持直接的代理 URL 格式:
```
socks5://127.0.0.1:1080
socks5://127.0.0.1:1081
http://127.0.0.1:8080
```
### 代理轮询机制
- 每个代理最多下载 **5 本**zlib.li 的匿名限制)
- 达到上限后自动停止当前代理进程,启动下一个
- SS 代理会自动启动 `mihomo` 进程创建本地隧道,无需宿主机环境准备
## AI Agent 集成
### JSON 搜索结果结构
```json
{
"status": "success",
"query": { "title": "...", "author": "...", "combined_query": "..." },
"total_results": 50,
"results": [
{
"id": "17576434",
"title": "Project Hail Mary",
"author": "Andy Weir",
"format": "epub",
"filesize": "1.21 MB",
"language": "English",
"year": "2021",
"publisher": "Ballantine Books",
"isbn": "9780593355275",
"quality": "5.0",
"rating": "5.0",
"download_path": "/dl/O2pPQwkq2l",
"page_url": "/book/ZOE1baGkOP/project-hail-mary.html"
}
],
"recommended": {
"epub": { "...best epub..." },
"pdf": { "...best pdf..." },
"mobi": { "...best mobi..." }
},
"message": "找到 50 个结果。推荐: epub (1.21 MB, Q:5.0, English), pdf (7.44 MB, Q:5.0, English)"
}
```
### 典型 Agent 工作流
1. 搜索:`zlib_dl.py --json search --title "书名" --author "作者"`
2.`recommended` 中选择合适的版本
3. 下载:`zlib_dl.py --json download --dl-path "/dl/xxx" --title "书名" --format epub`
4. 检查下载结果的 `status` 字段
## 限制
- 匿名用户每 IP 每天只能下载 5 本
- 需要代理才能批量下载
- 网站随时可能更新反爬机制
Binary file not shown.
Binary file not shown.
+1934
View File
File diff suppressed because one or more lines are too long
+1934
View File
File diff suppressed because one or more lines are too long
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
mixed-port: 7890
+17
View File
@@ -0,0 +1,17 @@
⏳ 下载遇到 PoW 挑战,正在解决...
✅ 挑战已解决 (耗时 0.002s,节点 zlib.li)
<z-bookcard contenttypeparam="" deleted="0" download="/dl/oznMQByLxl" extension="epub" filesize="4.87 MB" href="/book/mDJxkg7yO6/%E6%B5%AA%E6%BD%AE%E4%B9%8B%E5%B7%85%E7%AC%AC%E5%9B%9B%E7%89%88.html" id="5315955" isbn="9787115514226" language="Chinese" publisher="人民邮电出版社" quality="4.5" rating="5.0" termshash="d01830a687fbea2795b3389a07a0b93c" year="2019">
<img data-src="https://s3proxy-alp2-covers.cdn-zlib.sk/covers100/collections/userbooks/a03a361b4dc7b6b1dca3befd0e2c663845b0bc1fd5aa1be8a8921db14babc73d.jpg">
<div slot="title">
浪潮之巅第四版
</div>
<div slot="author">
吴军
</div>
<div slot="note">
</div>
<div slot="extend">
</div>
</img>
</z-bookcard>
+9
View File
@@ -0,0 +1,9 @@
Item 0:
title: 浪潮之巅第四版
page_url: /book/mDJxkg7yO6/%E6%B5%AA%E6%BD%AE%E4%B9%8B%E5%B7%85%E7%AC%AC%E5%9B%9B%E7%89%88.html
Item 1:
title: 浪潮之巅 (第4版)
page_url: /book/P9X1nPLjOL/%E6%B5%AA%E6%BD%AE%E4%B9%8B%E5%B7%85-%E7%AC%AC4%E7%89%88.html
Item 2:
title: 浪潮之巅(第四版)(上下册)
page_url: /book/p9zYrJqWDZ/%E6%B5%AA%E6%BD%AE%E4%B9%8B%E5%B7%85%E7%AC%AC%E5%9B%9B%E7%89%88%E4%B8%8A%E4%B8%8B%E5%86%8C.html
+28
View File
@@ -0,0 +1,28 @@
📡 已加载 13 个代理
🔍 搜索: 浪潮之巅 吴军
⏳ 正在解决 PoW 挑战...
✅ 挑战已解决 (耗时 0.002s)
🔗 已启动代理隧道: 🇺🇸 美国 01 -> 127.0.0.1:10800
⬇️ 下载: 浪潮之巅 - 吴军.epub (代理: 🇺🇸 美国 01)
🔗 正在预热书籍详情页以注册当前代理指纹和获取新 Session...
⏳ 下载遇到 PoW 挑战,正在解决...
✅ 挑战已解决 (耗时 0.027s,节点 zh.ngd101.ru)
🔌 已停止代理隧道: 🇺🇸 美国 01
🔗 已启动代理隧道: 🇺🇸 美国 02 -> 127.0.0.1:10801
🔄 下载受阻 (未能从书籍详情页获取到新的真实下载链接,页面内容可能因配额或要求登录被限制。),切换代理重试: 🇺🇸 美国 02
⬇️ 下载: 浪潮之巅 - 吴军.epub (代理: 🇺🇸 美国 02)
🔗 正在预热书籍详情页以注册当前代理指纹和获取新 Session...
⏳ 下载遇到 PoW 挑战,正在解决...
✅ 挑战已解决 (耗时 0.021s,节点 zh.ngd101.ru)
🔌 已停止代理隧道: 🇺🇸 美国 02
🔗 已启动代理隧道: 🇺🇸 美国 03 -> 127.0.0.1:10802
🔄 下载受阻 (未能从书籍详情页获取到新的真实下载链接,页面内容可能因配额或要求登录被限制。),切换代理重试: 🇺🇸 美国 03
⬇️ 下载: 浪潮之巅 - 吴军.epub (代理: 🇺🇸 美国 03)
🔗 正在预热书籍详情页以注册当前代理指纹和获取新 Session...
⏳ 下载遇到 PoW 挑战,正在解决...
✅ 挑战已解决 (耗时 0.024s,节点 zh.ngd101.ru)
🔌 已停止代理隧道: 🇺🇸 美国 03
🔗 已启动代理隧道: 🇺🇸 美国 04 -> 127.0.0.1:10803
🔄 下载受阻 (未能从书籍详情页获取到新的真实下载链接,页面内容可能因配额或要求登录被限制。),切换代理重试: 🇺🇸 美国 04
⬇️ 下载: 浪潮之巅 - 吴军.epub (代理: 🇺🇸 美国 04)
🔗 正在预热书籍详情页以注册当前代理指纹和获取新 Session...
+18
View File
@@ -0,0 +1,18 @@
from zlib_dl import ZLibSession
import re
from bs4 import BeautifulSoup
s = ZLibSession(verbose=True)
url = "https://zlib.li/book/mDJxkg7yO6/%E6%B5%AA%E6%BD%AE%E4%B9%8B%E5%B7%85%E7%AC%AC%E5%9B%9B%E7%89%88.html"
resp = s._request_download(url)
soup = BeautifulSoup(resp.text, 'html.parser')
a_tag = soup.find('a', href=re.compile(r"^/dl/\w+"))
if a_tag:
print(f"FOUND: {a_tag['href']}")
else:
print("NOT FOUND")
# let's try another heuristic
dl_btn = soup.find('a', class_=re.compile(r"addDownloadedBook"))
if dl_btn:
print("FOUND VIA CLASS:", dl_btn.get("href"))
else:
print("STILL NOT FOUND")
+56
View File
@@ -0,0 +1,56 @@
🇭🇰 香港 01= ss, d32b6cd.gylcxo.xyz, 18300, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇭🇰 香港 02= ss, d32b6cd.gylcxo.xyz, 18305, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇭🇰 香港 03= ss, d32b6cd.gylcxo.xyz, 18310, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇭🇰 香港 04= ss, d32b6cd.gylcxo.xyz, 18315, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇭🇰 香港 05= ss, d32b6cd.gylcxo.xyz, 18320, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇭🇰 香港 06= ss, d32b6cd.gylcxo.xyz, 18325, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇭🇰 香港 07= ss, d32b6cd.gylcxo.xyz, 18330, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇭🇰 香港 08= ss, d32b6cd.gylcxo.xyz, 18335, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇭🇰 香港 09= ss, d32b6cd.gylcxo.xyz, 18340, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇭🇰 香港 10= ss, d32b6cd.gylcxo.xyz, 18345, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇭🇰 香港 11= ss, d32b6cd.gylcxo.xyz, 18350, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇭🇰 香港 12= ss, d32b6cd.gylcxo.xyz, 18400, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇭🇰 香港 13= ss, d32b6cd.gylcxo.xyz, 18405, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇭🇰 香港 14= ss, d32b6cd.gylcxo.xyz, 18410, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇭🇰 香港 15= ss, d32b6cd.gylcxo.xyz, 18415, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇭🇰 香港 16= ss, d32b6cd.gylcxo.xyz, 18420, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇭🇰 香港 17= ss, d32b6cd.gylcxo.xyz, 18425, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇭🇰 香港 18= ss, d32b6cd.gylcxo.xyz, 18430, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇭🇰 香港 19= ss, d32b6cd.gylcxo.xyz, 18435, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇭🇰 香港 20= ss, d32b6cd.gylcxo.xyz, 18440, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇭🇰 香港 21= ss, d32b6cd.gylcxo.xyz, 18445, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇺🇸 美国 01= ss, tgv5af1.qeuhco.xyz, 18100, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇺🇸 美国 02= ss, tgv5af1.qeuhco.xyz, 18105, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇺🇸 美国 03= ss, tgv5af1.qeuhco.xyz, 18110, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇺🇸 美国 04= ss, tgv5af1.qeuhco.xyz, 18115, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇺🇸 美国 05= ss, tgv5af1.qeuhco.xyz, 18120, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇺🇸 美国 06= ss, tgv5af1.qeuhco.xyz, 18125, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇺🇸 美国 07= ss, tgv5af1.qeuhco.xyz, 18130, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇺🇸 美国 08= ss, tgv5af1.qeuhco.xyz, 18135, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇺🇸 美国 09= ss, tgv5af1.qeuhco.xyz, 18140, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇺🇸 美国 10= ss, tgv5af1.qeuhco.xyz, 18145, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇺🇸 美国 11= ss, tgv5af1.qeuhco.xyz, 18150, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇺🇸 美国 12= ss, tgv5af1.qeuhco.xyz, 18155, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇺🇸 美国 13= ss, tgv5af1.qeuhco.xyz, 18160, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇯🇵 日本 01= ss, tgv5af1.qeuhco.xyz, 18002, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇯🇵 日本 02= ss, tgv5af1.qeuhco.xyz, 18005, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇯🇵 日本 03= ss, tgv5af1.qeuhco.xyz, 18010, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇯🇵 日本 04= ss, tgv5af1.qeuhco.xyz, 18015, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇯🇵 日本 05= ss, tgv5af1.qeuhco.xyz, 18020, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇯🇵 日本 06= ss, tgv5af1.qeuhco.xyz, 18025, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇯🇵 日本 07= ss, tgv5af1.qeuhco.xyz, 18030, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇯🇵 日本 08= ss, tgv5af1.qeuhco.xyz, 18035, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇨🇳 台湾 01= ss, d32b6cd.gylcxo.xyz, 18355, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇨🇳 台湾 02= ss, d32b6cd.gylcxo.xyz, 18360, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇨🇳 台湾 03= ss, d32b6cd.gylcxo.xyz, 18365, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇨🇳 台湾 04= ss, d32b6cd.gylcxo.xyz, 18370, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇨🇳 台湾 05= ss, d32b6cd.gylcxo.xyz, 18375, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇨🇳 台湾 06= ss, d32b6cd.gylcxo.xyz, 18356, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇨🇳 台湾 07= ss, d32b6cd.gylcxo.xyz, 18361, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇨🇳 台湾 08= ss, d32b6cd.gylcxo.xyz, 18366, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇨🇳 台湾 09= ss, d32b6cd.gylcxo.xyz, 18371, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇨🇳 台湾 10= ss, d32b6cd.gylcxo.xyz, 18376, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇸🇬 新加坡 01= ss, d32b6cd.gylcxo.xyz, 18380, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇸🇬 新加坡 02= ss, d32b6cd.gylcxo.xyz, 18385, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇸🇬 新加坡 03= ss, d32b6cd.gylcxo.xyz, 18390, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇸🇬 新加坡 04= ss, d32b6cd.gylcxo.xyz, 18395, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
+1
View File
@@ -0,0 +1 @@
77188
+5
View File
@@ -0,0 +1,5 @@
📡 已加载 56 个代理
🔗 已启动代理隧道: 🇭🇰 香港 01 -> 127.0.0.1:10800
⏳ 下载遇到 PoW 挑战,正在解决...
✅ 挑战已解决 (耗时 0.024s,节点 zh.ngd101.ru)
下载返回了 HTML 页面(可能是限制或错误)
+4
View File
@@ -0,0 +1,4 @@
Proxy IP: 61.171.248.193
Index status: 503
Index status after PoW: 503
Search status: 503
+88
View File
@@ -0,0 +1,88 @@
import urllib.request, time, hashlib, re, os, subprocess
from curl_cffi import requests
def solve_challenge(html):
m = re.search(r"\['([A-F0-9]{40})'", html)
if not m: return None, None
c = m.group(1)
n1 = int(c[0], 16)
i = 0
t0 = time.time()
while True:
d = hashlib.sha1((c + str(i)).encode()).digest()
if d[n1] == 0xb0 and d[n1+1] == 0x0b: break
i += 1
return c + str(i), f"{time.time() - t0:.3f}"
yaml_config = """
mode: global
mixed-port: 10899
bind-address: '127.0.0.1'
proxies:
"""
proxy_str = ""
with open("proxies.txt") as f:
for line in f:
if "ss," in line:
proxy_str = line.strip()
break
parts = proxy_str.split("=", 1)
cfg = parts[1].strip().split(",")
params = dict(p.strip().split("=", 1) for p in cfg[3:] if "=" in p)
yaml_config += f""" - name: "test"
type: ss
server: "{cfg[1].strip()}"
port: {cfg[2].strip()}
cipher: "{params.get('encrypt-method', '')}"
password: "{params.get('password', '')}"
"""
if "obfs" in params:
yaml_config += f" plugin: obfs\n plugin-opts:\n mode: {params['obfs']}\n host: {params['obfs-host']}\n"
with open("test_503.yaml", "w") as f: f.write(yaml_config)
proc = subprocess.Popen(["./.venv/bin/mihomo", "-f", "test_503.yaml"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
time.sleep(2)
s = requests.Session()
p = {"http": "socks5://127.0.0.1:10899", "https": "socks5://127.0.0.1:10899"}
try:
with open("test_503.log", "w") as out:
ip_resp = s.get("http://httpbin.org/ip", proxies=p, impersonate="chrome", timeout=5)
out.write(f"Proxy IP: {ip_resp.json()['origin']}\n")
r1 = s.get("https://zlib.li/", proxies=p, impersonate="chrome", timeout=10)
out.write(f"Index status: {r1.status_code}\n")
if r1.status_code == 503 and "Checking your browser" in r1.text:
ct, cti = solve_challenge(r1.text)
if ct:
s.cookies.set("c_token", ct, domain="zlib.li", path="/")
s.cookies.set("c_time", cti, domain="zlib.li", path="/")
r1 = s.get("https://zlib.li/", proxies=p, impersonate="chrome", timeout=10)
out.write(f"Index status after PoW: {r1.status_code}\n")
r2 = s.get("https://zlib.li/s/Project", proxies=p, impersonate="chrome", timeout=10)
out.write(f"Search status: {r2.status_code}\n")
from bs4 import BeautifulSoup
soup = BeautifulSoup(r2.text, "lxml")
card = soup.find("z-bookcard")
if card and card.get("download"):
dl = card.get("download")
out.write(f"Got dl path: {dl}\n")
r3 = s.get("https://zlib.li" + dl, proxies=p, impersonate="chrome", allow_redirects=True, timeout=10)
out.write(f"Download status: {r3.status_code}\n")
if r3.status_code == 503:
if "Checking your browser" in r3.text:
ct, cti = solve_challenge(r3.text)
if ct:
s.cookies.set("c_token", ct, domain="zlib.li", path="/")
s.cookies.set("c_time", cti, domain="zlib.li", path="/")
r4 = s.get("https://zlib.li" + dl, proxies=p, impersonate="chrome", allow_redirects=True, timeout=10)
out.write(f"Retry status: {r4.status_code}\n")
with open("test_503_body.html", "w") as f2: f2.write(r4.text)
else:
out.write("Not PoW 503\n")
finally:
proc.terminate()
+23
View File
@@ -0,0 +1,23 @@
mode: rule
mixed-port: 10899
bind-address: '127.0.0.1'
proxies:
- name: "test"
type: ss
server: "d32b6cd.gylcxo.xyz"
port: 18300
cipher: "aes-128-gcm"
password: "ced24190439d1ed1"
plugin: obfs
plugin-opts:
mode: http
host: Sm0lO349ch.microsoft.com
proxy-groups:
- name: "Proxy"
type: select
proxies:
- "test"
rules:
- MATCH, Proxy
+61
View File
@@ -0,0 +1,61 @@
import urllib.request, time, hashlib, re, os, subprocess
from curl_cffi import requests
def solve_challenge(html):
m = re.search(r"\['([A-F0-9]{40})'", html)
if not m: return None, None
c = m.group(1)
n1 = int(c[0], 16)
i = 0
t0 = time.time()
while True:
d = hashlib.sha1((c + str(i)).encode()).digest()
if d[n1] == 0xb0 and d[n1+1] == 0x0b: break
i += 1
return c + str(i), f"{time.time() - t0:.3f}"
yaml_config = """
mode: global
mixed-port: 10899
bind-address: '127.0.0.1'
proxies:
"""
proxy_str = ""
with open("proxies.txt") as f:
for line in f:
if "ss," in line:
proxy_str = line.strip()
break
parts = proxy_str.split("=", 1)
cfg = parts[1].strip().split(",")
params = dict(p.strip().split("=", 1) for p in cfg[3:] if "=" in p)
yaml_config += f""" - name: "test"
type: ss
server: "{cfg[1].strip()}"
port: {cfg[2].strip()}
cipher: "{params.get('encrypt-method', '')}"
password: "{params.get('password', '')}"
"""
if "obfs" in params:
yaml_config += f" plugin: obfs\n plugin-opts:\n mode: {params['obfs']}\n host: {params['obfs-host']}\n"
with open("test_503.yaml", "w") as f: f.write(yaml_config)
proc = subprocess.Popen(["./.venv/bin/mihomo", "-f", "test_503.yaml"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
time.sleep(2)
s = requests.Session()
p = {"http": "socks5://127.0.0.1:10899", "https": "socks5://127.0.0.1:10899"}
try:
r1 = s.get("https://zlib.li/", proxies=p, impersonate="chrome", timeout=10)
print("Initial:", r1.status_code)
if r1.status_code == 503 and "Checking your browser" in r1.text:
ct, cti = solve_challenge(r1.text)
s.cookies.set("c_token", ct, domain="zlib.li", path="/")
s.cookies.set("c_time", cti, domain="zlib.li", path="/")
r1 = s.get("https://zlib.li/", proxies=p, impersonate="chrome", timeout=10)
print("After PoW:", r1.status_code)
if r1.status_code == 503:
print(r1.text[:500])
finally:
proc.terminate()
+13
View File
@@ -0,0 +1,13 @@
port: 7890
socks-port: 7891
proxies:
- name: "ss-obfs"
type: ss
server: "127.0.0.1"
port: 18300
cipher: "aes-128-gcm"
password: "ced"
plugin: obfs
plugin-opts:
mode: http
host: Sm0lO349ch.microsoft.com
+6
View File
@@ -0,0 +1,6 @@
from curl_cffi import requests
s = requests.Session()
s.cookies.set("1", "A", domain="zlib.li", path="/")
s.cookies.set("2", "B", domain=".zlib.li", path="/")
s.get("http://httpbin.org/cookies", impersonate="chrome")
print(s.cookies)
+7
View File
@@ -0,0 +1,7 @@
from zlib_dl import ProxyManager, ZLibSession
mgr = ProxyManager("proxies.txt", verbose=True)
mgr.rotate()
s = ZLibSession(proxy_url=mgr.get_current_proxy_url(), verbose=True)
res, msg = s.download_file("/dl/22909249/a93325", "test.epub")
print(msg)
import os; os.path.exists("test.epub") and print("Saved epub size:", os.path.getsize("test.epub"))
+16
View File
@@ -0,0 +1,16 @@
from zlib_dl import ZLibSession
import re
s1 = ZLibSession(verbose=True)
resp1 = s1._request_download("https://zlib.li/book/22909249/a93325")
match = re.search(r'href="(/dl/[^"]+)"', resp1.text)
if match:
print("Found exact link:", match.group(1))
else:
print("Could not find /dl/ link in HTML!")
lines = [line.strip() for line in resp1.text.split('\n')]
for i, line in enumerate(lines):
if "download" in line.lower() or "href" in line.lower():
if "/22909249/" in line:
print(f"Possible DL Line [{i}]: {line[:300]}")
+22
View File
@@ -0,0 +1,22 @@
import urllib.request
import platform
system = platform.system().lower()
machine = platform.machine().lower()
is_arm = machine in ("arm64", "aarch64")
if system == "darwin":
arch_str = "arm64" if is_arm else "amd64-compatible"
elif system == "linux":
arch_str = "arm64" if is_arm else "amd64-compatible"
version = "v1.19.21"
url = f"https://github.com/MetaCubeX/mihomo/releases/download/{version}/mihomo-{system}-{arch_str}-{version}.gz"
print("URL:", url)
try:
req = urllib.request.Request(url, method='HEAD')
resp = urllib.request.urlopen(req, timeout=5)
print("Status:", resp.status)
except Exception as e:
print("Error:", e)
+72
View File
@@ -0,0 +1,72 @@
import subprocess
import time
import os
import urllib.request
from curl_cffi import requests
# We will read the first proxy from proxies.txt to really test it
proxy_str = ""
with open("proxies.txt") as f:
for line in f:
if "ss," in line:
proxy_str = line.strip()
break
parts = proxy_str.split("=", 1)
name = parts[0].strip()
cfg = parts[1].strip().split(",")
host = cfg[1].strip()
port = cfg[2].strip()
params = {}
for p in cfg[3:]:
if "=" in p:
k, v = p.split("=", 1)
params[k.strip()] = v.strip()
method = params.get("encrypt-method", "")
password = params.get("password", "")
obfs = params.get("obfs", "")
obfs_host = params.get("obfs-host", "")
def test_mihomo(use_en0):
port_local = 11111 if use_en0 else 11112
interface_cfg = "\n interface-name: en0" if use_en0 else ""
plugin_cfg = f"""
plugin: obfs
plugin-opts:
mode: {obfs}
host: {obfs_host}
""" if obfs else ""
yaml_cfg = f"""
mode: global
mixed-port: {port_local}
bind-address: '127.0.0.1'
dns:
enable: true
nameserver:
- 223.5.5.5
proxies:
- name: "test_proxy"
type: ss
server: "{host}"
port: {port}
cipher: "{method}"
password: "{password}"{interface_cfg}{plugin_cfg}
"""
with open(f"test_cfg_{port_local}.yaml", "w") as f: f.write(yaml_cfg)
proc = subprocess.Popen(["./.venv/bin/mihomo", "-f", f"test_cfg_{port_local}.yaml"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
time.sleep(2)
try:
prox = {"http": f"socks5://127.0.0.1:{port_local}", "https": f"socks5://127.0.0.1:{port_local}"}
resp = requests.get("http://httpbin.org/ip", proxies=prox, impersonate="chrome", timeout=5)
return resp.json()["origin"]
except Exception as e:
return f"Error: {e}"
finally:
proc.terminate()
proc.wait(timeout=2)
os.remove(f"test_cfg_{port_local}.yaml")
print("Without en0:", test_mihomo(False))
print("With en0:", test_mihomo(True))
+46
View File
@@ -0,0 +1,46 @@
import subprocess
import time
import os
import json
import yaml
# 1. 启动 mihomo 并绑定到具体网卡 (en0)
local_port = 10850
cfg = """
mode: global
mixed-port: 10850
bind-address: '127.0.0.1'
dns:
enable: true
nameserver:
- https://223.5.5.5/dns-query
- https://1.1.1.1/dns-query
proxies:
- name: "test-direct"
type: direct
interface-name: en0
"""
with open("test_b.yaml", "w") as f:
f.write(cfg)
# 找到 mihomo
mihomo = "./.venv/bin/mihomo"
if not os.path.exists(mihomo):
mihomo = "mihomo"
proc = subprocess.Popen([mihomo, "-f", "test_b.yaml"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
time.sleep(2)
try:
from curl_cffi import requests
resp = requests.get("http://httpbin.org/ip", proxies={"http": "socks5://127.0.0.1:10850", "https": "socks5://127.0.0.1:10850"}, impersonate="chrome")
print("Mihomo (direct bound to en0) IP:", resp.json()["origin"])
resp_direct = requests.get("http://httpbin.org/ip", impersonate="chrome")
print("System (Surge default) IP:", resp_direct.json()["origin"])
finally:
proc.kill()
os.remove("test_b.yaml")
+52
View File
@@ -0,0 +1,52 @@
import urllib.request, time, os, subprocess
from curl_cffi import requests
yaml_config = """
mode: rule
mixed-port: 10899
bind-address: '127.0.0.1'
proxies:
"""
proxy_str = ""
with open("proxies.txt") as f:
for line in f:
if "ss," in line:
proxy_str = line.strip()
break
parts = proxy_str.split("=", 1)
cfg = parts[1].strip().split(",")
params = dict(p.strip().split("=", 1) for p in cfg[3:] if "=" in p)
yaml_config += f""" - name: "test"
type: ss
server: "{cfg[1].strip()}"
port: {cfg[2].strip()}
cipher: "{params.get('encrypt-method', '')}"
password: "{params.get('password', '')}"
"""
if "obfs" in params:
yaml_config += f" plugin: obfs\n plugin-opts:\n mode: {params['obfs']}\n host: {params['obfs-host']}\n"
yaml_config += """
proxy-groups:
- name: "Proxy"
type: select
proxies:
- "test"
rules:
- MATCH, Proxy
"""
with open("test_503.yaml", "w") as f: f.write(yaml_config)
proc = subprocess.Popen(["./.venv/bin/mihomo", "-f", "test_503.yaml"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
time.sleep(2)
s = requests.Session()
p = {"http": "socks5://127.0.0.1:10899", "https": "socks5://127.0.0.1:10899"}
try:
ip_resp = s.get("http://httpbin.org/ip", proxies=p, impersonate="chrome", timeout=5)
print("Proxy IP:", ip_resp.json()["origin"])
r1 = s.get("https://zlib.li/", proxies=p, impersonate="chrome", timeout=10)
print("Index status:", r1.status_code)
finally:
proc.terminate()
+42
View File
@@ -0,0 +1,42 @@
import platform, os, gzip, urllib.request, json
import yaml
def gen_config(proxy, local_port):
cfg = {
"port": 0,
"socks-port": local_port,
"mode": "Global",
"proxies": [{
"name": proxy["name"],
"type": "ss",
"server": proxy["host"],
"port": proxy["port"],
"cipher": proxy["method"],
"password": proxy["password"],
"plugin": "obfs",
"plugin-opts": {
"mode": proxy["obfs"],
"host": proxy["obfs_host"]
}
}],
"proxy-groups": [{
"name": "Proxy",
"type": "select",
"proxies": [proxy["name"]]
}],
"rules": [
"MATCH,Proxy"
]
}
return yaml.dump(cfg)
proxy_test = {
"name": "HK 01",
"host": "d32b6cd.gylcxo.xyz",
"port": 18300,
"method": "aes-128-gcm",
"password": "ced",
"obfs": "http",
"obfs_host": "Sm0lO349ch.microsoft.com"
}
print(gen_config(proxy_test, 10800))
+19
View File
@@ -0,0 +1,19 @@
import urllib.request
import json
from bs4 import BeautifulSoup
def get_ip(proxy_url=None):
import subprocess
import sys
try:
from curl_cffi import requests
session = requests.Session()
proxies = {"http": proxy_url, "https": proxy_url} if proxy_url else None
resp = session.get("http://httpbin.org/ip", proxies=proxies, impersonate="chrome")
return resp.json()["origin"]
except Exception as e:
return f"Error: {e}"
print("Direct IP:", get_ip())
+3
View File
@@ -0,0 +1,3 @@
⏳ 下载遇到 PoW 挑战,正在解决...
✅ 挑战已解决 (耗时 0.003s,节点 zlib.li)
Could not find /dl/ link in HTML!
+10
View File
@@ -0,0 +1,10 @@
from zlib_dl import ZLibSession
s = ZLibSession(verbose=True)
resp = s._request_download("https://zlib.li/s/%E6%B5%AA%E6%BD%AE%E4%B9%8B%E5%B7%85")
from bs4 import BeautifulSoup
soup = BeautifulSoup(resp.text, "html.parser")
cards = soup.find_all("z-bookcard")
if cards:
print(cards[0].prettify())
else:
print("No cards found")
+13
View File
@@ -0,0 +1,13 @@
from zlib_dl import ZLibSession
import re
url = "https://zlib.li/book/mDJxkg7yO6/%E6%B5%AA%E6%BD%AE%E4%B9%8B%E5%B7%85%E7%AC%AC%E5%9B%9B%E7%89%88.html"
s = ZLibSession(verbose=True, proxy_url="socks5://127.0.0.1:10800")
print("Requesting clean detail URL:", url)
resp = s._request_download(url)
print("FINAL URL:", resp.url)
print("HTML Title:", re.search(r'<title>(.*?)</title>', resp.text).group(1))
match = re.search(r'href="(/dl/[^"]+)"', resp.text)
if match:
print("DOWNLOAD LINK FOUND:", match.group(1))
else:
print("NO DOWNLOAD LINK FOUND")
+21
View File
@@ -0,0 +1,21 @@
from zlib_dl import ZLibSession
s = ZLibSession(verbose=True, proxy_url="socks5://127.0.0.1:10800")
# Hit the detail page manually
resp = s._request_download("https://zlib.li/book/mDJxkg7yO6/%E6%B5%AA%E6%BD%AE%E4%B9%8B%E5%B7%85%E7%AC%AC%E5%9B%9B%E7%89%88.html")
print(f"STATUS CODE: {resp.status_code}")
print(f"FINAL URL: {resp.url}")
content = resp.text
print(f"CONTENT LENGTH: {len(content)}")
if '/dl/' in content:
print("FOUND /dl/ literally in content!")
else:
print("NO /dl/ FOUND!")
import re
links = re.findall(r'href="(.*?)"', content)
print("Some links found on page:")
for l in [x for x in links if 'book' in x or 'dl' in x or 'download' in x][:10]:
print(" - ", l)
if "daily limit" in content.lower() or "limit reached" in content.lower() or "已达下载" in content:
print("HIT RATE LIMIT MESSAGE ON DETAIL PAGE!")
+9
View File
@@ -0,0 +1,9 @@
from zlib_dl import ZLibSession
s = ZLibSession()
results = s.search("浪潮之巅")
if results:
for i, r in enumerate(results[:3]):
print(f"Item {i}:")
print(f" title: {r.title}")
print(f" page_url: {r.page_url}")
+13
View File
@@ -0,0 +1,13 @@
🇺🇸 美国 01= ss, tgv5af1.qeuhco.xyz, 18100, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇺🇸 美国 02= ss, tgv5af1.qeuhco.xyz, 18105, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇺🇸 美国 03= ss, tgv5af1.qeuhco.xyz, 18110, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇺🇸 美国 04= ss, tgv5af1.qeuhco.xyz, 18115, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇺🇸 美国 05= ss, tgv5af1.qeuhco.xyz, 18120, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇺🇸 美国 06= ss, tgv5af1.qeuhco.xyz, 18125, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇺🇸 美国 07= ss, tgv5af1.qeuhco.xyz, 18130, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇺🇸 美国 08= ss, tgv5af1.qeuhco.xyz, 18135, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇺🇸 美国 09= ss, tgv5af1.qeuhco.xyz, 18140, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇺🇸 美国 10= ss, tgv5af1.qeuhco.xyz, 18145, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇺🇸 美国 11= ss, tgv5af1.qeuhco.xyz, 18150, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇺🇸 美国 12= ss, tgv5af1.qeuhco.xyz, 18155, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
🇺🇸 美国 13= ss, tgv5af1.qeuhco.xyz, 18160, encrypt-method=aes-128-gcm, password=ced24190439d1ed1, obfs=http, obfs-host=Sm0lO349ch.microsoft.com, tfo=true, udp-relay=true
+1302
View File
File diff suppressed because it is too large Load Diff