微信公众号RSS项目对比分析

model delivery-mirror date 2026-03-27 msgs 4 / 30

A
agent15:28

Command:

curl -sL "https://api.github.com/repos/tmwgsicp/wechat-download-api"

{
  "id": 1164859248,
  "node_id": "R_kgDORW5XcA",
  "name": "wechat-download-api",
  "full_name": "tmwgsicp/wechat-download-api",
  "private": false,
  "owner": {
    "login": "tmwgsicp",
    "id": 161463025,
    "node_id": "U_kgDOCZ-68Q",
    "avatar_url": "https://avatars.githubusercontent.com/u/161463025?v=4",
    "gravatar_id": "",
    "url": "https://api.github.com/users/tmwgsicp",
    "html_url": "https://github.com/tmwgsicp",
    "followers_url": "https://api.github.com/users/tmwgsicp/followers",
    "following_url": "https://api.github.com/users/tmwgsicp/following{/other_user}",
    "gists_url": "https://api.github.com/users/tmwgsicp/gists{/gist_id}",
    "starred_url": "https://api.github.com/users/tmwgsicp/starred{/owner}{/repo}",
    "subscriptions_url": "https://api.github.com/users/tmwgsicp/subscriptions",
    "organizations_url": "https://api.github.com/users/tmwgsicp/orgs",
    "repos_url": "https://api.github.com/users/tmwgsicp/repos",
    "events_url": "https://api.github.com/users/tmwgsicp/events{/privacy}",
    "received_events_url": "https://api.github.com/users/tmwgsicp/received_events",
    "type": "User",
    "user_view_type": "public",
    "site_admin": false
  },
  "html_url": "https://github.com/tmwgsicp/wechat-download-api",
  "description": "一款完全开源的微信公众号文章获取、 RSS 订阅API服务,支持IP代理池反风控。",
  "fork": false,
  "url": "https://api.github.com/repos/tmwgsicp/wechat-download-api",
  "forks_url": "https://api.github.com/repos/tmwgsicp/wechat-download-api/forks",
  "keys_url": "https://api.github.com/repos/tmwgsicp/wechat-download-api/keys{/key_id}",
  "collaborators_url": "https://api.github.com/repos/tmwgsicp/wechat-download-api/collaborators{/collaborator}",
  "teams_url": "https://api.github.com/repos/tmwgsicp/wechat-download-api/teams",
  "hooks_url": "https://api.github.com/repos/tmwgsicp/wechat-download-api/hooks",
  "issue_events_url": "https://api.github.com/repos/tmwgsicp/wechat-download-api/issues/events{/number}",
  "events_url": "https://api.github.com/repos/tmwgsicp/wechat-download-api/events",
  "assignees_url": "https://api.github.com/repos/tmwgsicp/wechat-download-api/assignees{/user}",
  "branches_url": "https://api.github.com/repos/tmwgsicp/wechat-download-api/branches{/branch}",
  "tags_url": "https://api.github.com/repos/tmwgsicp/wechat-download-api/tags",
  "blobs_url": "https://api.github.com/repos/tmwgsicp/wechat-download-api/git/blobs{/sha}",
  "git_tags_url": "https://api.github.com/repos/tmwgsicp/wechat-download-api/git/tags{/sha}",
  "git_refs_url": "https://api.github.com/repos/tmwgsicp/wechat-download-api/git/refs{/sha}",
  "trees_url": "https://api.github.com/repos/tmwgsicp/wechat-download-api/git/trees{/sha}",
  "statuses_url": "https://api.github.com/repos/tmwgsicp/wechat-download-api/statuses/{sha}",
  "languages_url": "https://api.github.com/repos/tmwgsicp/wechat-download-api/languages",
  "stargazers_url": "https://api.github.com/repos/tmwgsicp/wechat-download-api/stargazers",
  "contributors_url": "https://api.github.com/repos/tmwgsicp/wechat-download-api/contributors",
  "subscribers_url": "https://api.github.com/repos/tmwgsicp/wechat-download-api/subscribers",
  "subscription_url": "https://api.github.com/repos/tmwgsicp/wechat-download-api/subscription",
  "commits_url": "https://api.github.com/repos/tmwgsicp/wechat-download-api/commits{/sha}",
  "git_commits_url": "https://api.github.com/repos/tmwgsicp/wechat-download-api/git/commits{/sha}",
  "comments_url": "https://api.github.com/repos/tmwgsicp/wechat-download-api/comments{/number}",
  "issue_comment_url": "https://api.github.com/repos/tmwgsicp/wechat-download-api/issues/comments{/number}",
  "contents_url": "https://api.github.com/repos/tmwgsicp/wechat-download-api/contents/{+path}",
  "compare_url": "https://api.github.com/repos/tmwgsicp/wechat-download-api/compare/{base}...{head}",
  "merges_url": "https://api.github.com/repos/tmwgsicp/wechat-download-api/merges",
  "archive_url": "https://api.github.com/repos/tmwgsicp/wechat-download-api/{archive_format}{/ref}",
  "downloads_url": "https://api.github.com/repos/tmwgsicp/wechat-download-api/downloads",
  "issues_url": "https://api.github.com/repos/tmwgsicp/wechat-download-api/issues{/number}",
  "pulls_url": "https://api.github.com/repos/tmwgsicp/wechat-download-api/pulls{/number}",
  "milestones_url": "https://api.github.com/repos/tmwgsicp/wechat-download-api/milestones{/number}",
  "notifications_url": "https://api.github.com/repos/tmwgsicp/wechat-download-api/notifications{?since,all,participating}",
  "labels_url": "https://api.github.com/repos/tmwgsicp/wechat-download-api/labels{/name}",
  "releases_url": "https://api.github.com/repos/tmwgsicp/wechat-download-api/releases{/id}",
  "deployments_url": "https://api.github.com/repos/tmwgsicp/wechat-download-api/deployments",
  "created_at": "2026-02-23T15:06:21Z",
  "updated_at": "2026-03-27T06:51:50Z",
  "pushed_at": "2026-03-25T02:11:39Z",
  "git_url": "git://github.com/tmwgsicp/wechat-download-api.git",
  "ssh_url": "git@github.com:tmwgsicp/wechat-download-api.git",
  "clone_url": "https://github.com/tmwgsicp/wechat-download-api.git",
  "svn_url": "https://github.com/tmwgsicp/wechat-download-api",
  "homepage": "https://wechatrss.waytomaster.com",
  "size": 828,
  "stargazers_count": 389,
  "watchers_count": 389,
  "language": "Python",
  "has_issues": true,
  "has_projects": true,
  "has_downloads": true,
  "has_wiki": true,
  "has_pages": false,
  "has_discussions": false,
  "forks_count": 24,
  "mirror_url": null,
  "archived": false,
  "disabled": false,
  "open_issues_count": 0,
  "license": {
    "key": "agpl-3.0",
    "name": "GNU Affero General Public License v3.0",
    "spdx_id": "AGPL-3.0",
    "url": "https://api.github.com/licenses/agpl-3.0",
    "node_id": "MDc6TGljZW5zZTE="
  },
  "allow_forking": true,
  "is_template": false,
  "web_commit_signoff_required": false,
  "has_pull_requests": true,
  "pull_request_creation_policy": "all",
  "topics": [
    "rss",
    "rss-feed",
    "wechat",
    "wechat-article"
  ],
  "visibility": "public",
  "forks": 24,
  "open_issues": 0,
  "watchers": 389,
  "default_branch": "main",
  "temp_clone_token": null,
  "network_count": 24,
  "subscribers_count": 1
}
A
agent15:28

Interesting project! 389 stars, Python, AGPL license. Let me explore the structure and README to understand how it works.

A
agent15:28

Command:

curl -sL "https://api.github.com/repos/tmwgsicp/wechat-download-api/contents" | python3 -c "import sys,json; d=json.load(sys.stdin); [print(f['name']) for f in d]"

.dockerignore
.gitattributes
.github
.gitignore
CONTENT_TYPES.md
Dockerfile
LICENSE
README.md
app.py
assets
docker-compose.yml
env.example
requirements.txt
routes
start.bat
start.sh
static
status.sh
stop.sh
utils
A
agent15:28

Let me read the README and key files to understand the architecture.

A
agent15:28

Command:

curl -sL "https://api.github.com/repos/tmwgsicp/wechat-download-api/contents/README.md" | python3 -c "import sys,json; d=json.load(sys.stdin); import base64; print(base64.b64decode(d['content']).decode())"

<div align="center">

# WeChat Download API

### 微信公众号文章获取 & RSS 订阅服务

**完全开源 | 免费部署 | RSS 订阅 | 文章抓取 | 反风控**

[![GitHub stars](https://img.shields.io/github/stars/tmwgsicp/wechat-download-api?style=for-the-badge&logo=github)](https://github.com/tmwgsicp/wechat-download-api/stargazers)
[![License](https://img.shields.io/badge/License-AGPL%203.0-blue?style=for-the-badge)](LICENSE)
[![Docker Pulls](https://img.shields.io/docker/pulls/tmwgsicp/wechat-download-api?style=for-the-badge&logo=docker&logoColor=white)](https://hub.docker.com/r/tmwgsicp/wechat-download-api)
[![Python](https://img.shields.io/badge/Python-3.8+-3776AB?style=for-the-badge&logo=python&logoColor=white)](https://www.python.org/)
[![FastAPI](https://img.shields.io/badge/FastAPI-0.104+-009688?style=for-the-badge&logo=fastapi&logoColor=white)](https://fastapi.tiangolo.com/)

> **100% 开源,100% 免费。** 代码完全公开,私有化部署无任何限制,不搞"开源"之名行收费之实。

</div>

---

## 功能特性

- **RSS 订阅** — 订阅任意公众号,自动定时拉取新文章(**包含完整文章内容和图片**),生成标准 RSS 2.0 源,接入 FreshRSS / Feedly 等阅读器即可使用
- **文章内容获取** — 通过 URL 获取文章完整内容(标题、作者、正文 HTML / 纯文本、图片列表)
- **反风控体系** — Chrome TLS 指纹模拟 + SOCKS5 代理池轮转 + 三层自动限频,有效对抗微信封控
- **文章列表 & 搜索** — 获取任意公众号历史文章列表,支持分页和关键词搜索
- **公众号搜索** — 按名称搜索公众号,获取 FakeID
- **扫码登录** — 微信公众平台扫码登录,凭证自动保存,4 天有效期
- **图片代理** — 代理微信 CDN 图片,解决防盗链问题
- **Webhook 通知** — 登录过期、触发验证等事件自动推送(支持企业微信机器人)
- **API 文档** — 自动生成 Swagger UI / ReDoc,在线调试所有接口

<div align="center">
  <img src="assets/dashboard.jpg" width="800" alt="管理面板">
  <p><em>管理面板 — 登录状态、接口文档、在线测试一站式管理</em></p>
  <br>
  <img src="assets/rss.jpg" width="800" alt="RSS 订阅管理">
  <p><em>RSS 订阅管理 — 搜索公众号一键订阅,复制地址接入 RSS 阅读器</em></p>
</div>

---

## Docker 部署 🐳

**最快速的部署方式**,无需配置 Python 环境,一键启动:

```bash
# 方式一:使用 docker-compose(推荐)
git clone https://github.com/tmwgsicp/wechat-download-api.git
cd wechat-download-api
cp env.example .env
# 编辑 .env 设置 SITE_URL 为实际访问地址
docker-compose up -d

# 方式二:直接运行
docker run -d \
  -p 5000:5000 \
  -v $(pwd)/data:/app/data \
  -v $(pwd)/.env:/app/.env \
  --name wechat-api \
  tmwgsicp/wechat-download-api:latest
```

服务启动后访问 `http://localhost:5000/login.html` 扫码登录即可使用。

**支持多架构**:`linux/amd64` / `linux/arm64`(Apple Silicon、树莓派、ARM 服务器)

---

## SaaS 托管版 — 已上线 🚀

**不想折腾部署?30 秒注册即可使用** 👉 **[wechatrss.waytomaster.com](https://wechatrss.waytomaster.com)**

搜索公众号名称,拿到 RSS 链接,丢进你的阅读器——Feedly、Inoreader、NetNewsWire 全部兼容。

| 套餐 | 公众号数量 | 价格 |
|------|-----------|------|
| 免费版 | 2 个 | ¥0 |
| 基础版 | 20 个 | ¥9.9/月 |
| 专业版 | 50 个 | ¥19.9/月 |

> 免费版够用就一直免费,不够了再升级,没有套路。

---

## 使用前提

> 本工具需要通过微信公众平台后台的登录凭证来调用接口,因此使用前需要:

1. **拥有一个微信公众号**(订阅号、服务号均可)
2. 部署并启动服务后,访问登录页面用**公众号管理员微信**扫码登录
3. 登录成功后凭证自动保存到 `.env` 文件,有效期约 **4 天**,过期后需重新扫码

登录后即可通过 API 获取**任意公众号**的公开文章(不限于自己的公众号)。

> **本地电脑可以直接使用!** 不需要公网服务器——在本地启动服务后通过 `localhost` 访问即可完成扫码登录和全部功能。只有当你需要从其他设备(如手机 RSS 阅读器)远程访问时,才需要公网服务器或内网穿透。

---

## 快速开始

### 方式一:Docker 部署(推荐)

```bash
# 1. 克隆项目
git clone https://github.com/tmwgsicp/wechat-download-api.git
cd wechat-download-api

# 2. 配置环境变量
cp env.example .env
# 编辑 .env,设置 SITE_URL 为实际访问地址(如 http://your-domain.com)

# 3. 启动服务
docker-compose up -d

# 4. 查看日志
docker-compose logs -f
```

### 方式二:一键脚本部署

**第一步:克隆项目**

```bash
git clone https://github.com/tmwgsicp/wechat-download-api.git
cd wechat-download-api
```

**第二步:一键启动**

```bash
bash start.sh  # Linux/macOS
# 或
start.bat      # Windows
```

脚本会自动完成环境检查、虚拟环境创建、依赖安装和服务启动。

**第三步:扫码登录**

访问 `http://localhost:5000/login.html`,用**公众号管理员微信**扫码登录。

---

## API 使用

### 访问地址

| 地址 | 说明 |
|------|------|
| http://localhost:5000 | 管理面板 |
| http://localhost:5000/login.html | 扫码登录 |
| http://localhost:5000/api/docs | Swagger API 文档 |
| http://localhost:5000/api/health | 健康检查 |

---

## 服务器部署

### Linux 生产环境(systemd)

`start.sh` 脚本在 Linux 上以 `sudo` 运行时,会自动注册 systemd 服务并启用开机自启:

```bash
sudo bash start.sh
```

之后可通过以下命令管理服务:

```bash
# 查看运行状态
bash status.sh

# 停止服务
bash stop.sh

# 手动操作
sudo systemctl restart wechat-download-api
sudo systemctl status wechat-download-api
```

### 配置反向代理(可选)

如需通过域名或 HTTPS 访问,配置 Nginx 反向代理到 `localhost:5000`:

```nginx
server {
    listen 80;
    server_name your-domain.com;

    location / {
        proxy_pass http://127.0.0.1:5000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}
```

### 环境变量

复制 `env.example` 为 `.env` 并按需修改:

```bash
cp env.example .env
```

主要配置项参见 `env.example` 中的注释说明。

---

## API 接口

### 获取文章内容

`POST /api/article` — 解析微信公众号文章,返回标题、正文、图片等结构化数据

| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `url` | string | 是 | 微信文章链接(`https://mp.weixin.qq.com/s/...`) |

请求示例:

```bash
curl -X POST http://localhost:5000/api/article \
  -H "Content-Type: application/json" \
  -d '{"url": "https://mp.weixin.qq.com/s/xxxxx"}'
```

返回字段:`title` 标题、`content` HTML 正文、`plain_content` 纯文本正文、`author` 作者、`publish_time` 发布时间戳、`images` 图片列表

### 搜索公众号

`GET /api/public/searchbiz` — 按关键词搜索微信公众号,获取 FakeID

| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `query` | string | 是 | 搜索关键词(公众号名称) |

请求示例:

```bash
curl "http://localhost:5000/api/public/searchbiz?query=公众号名称"
```

返回字段:`list[]` 公众号列表,每项包含 `fakeid`、`nickname`、`alias`、`round_head_img`

### 获取文章列表

`GET /api/public/articles` — 获取指定公众号的文章列表,支持分页

| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `fakeid` | string | 是 | 目标公众号的 FakeID(从搜索接口获取) |
| `begin` | int | 否 | 偏移量,默认 `0` |
| `count` | int | 否 | 获取数量,默认 `10`,最大 `100` |
| `keyword` | string | 否 | 在该公众号内搜索关键词 |

请求示例:

```bash
# 获取前 50 篇
curl "http://localhost:5000/api/public/articles?fakeid=YOUR_FAKEID&begin=0&count=50"

# 获取第 51-100 篇
curl "http://localhost:5000/api/public/articles?fakeid=YOUR_FAKEID&begin=50&count=50"
```

### 搜索公众号文章

`GET /api/public/articles/search` — 在指定公众号内按关键词搜索文章

| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `fakeid` | string | 是 | 目标公众号的 FakeID |
| `query` | string | 是 | 搜索关键词 |
| `begin` | int | 否 | 偏移量,默认 `0` |
| `count` | int | 否 | 获取数量,默认 `10`,最大 `100` |

请求示例:

```bash
curl "http://localhost:5000/api/public/articles/search?fakeid=YOUR_FAKEID&query=关键词"
```

### RSS 订阅

`GET /api/rss/{fakeid}` — 获取指定公众号的 RSS 2.0 订阅源

| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `fakeid` | string(路径) | 是 | 公众号 FakeID |
| `limit` | int(查询) | 否 | 返回文章数量上限,默认 `20` |

使用方式:

```bash
# 1. 搜索公众号获取 fakeid
curl "http://localhost:5000/api/public/searchbiz?query=人民日报"
# 返回 fakeid: MzA1MjM1ODk2MA==

# 2. 添加订阅
curl -X POST http://localhost:5000/api/rss/subscribe \
  -H "Content-Type: application/json" \
  -d '{"fakeid": "MzA1MjM1ODk2MA==", "nickname": "人民日报"}'

# 3. 手动触发一次轮询(立即拉取文章)
curl -X POST http://localhost:5000/api/rss/poll

# 4. 获取 RSS 源(把这个地址添加到 RSS 阅读器)
curl "http://localhost:5000/api/rss/MzA1MjM1ODk2MA=="
```

也可以通过管理面板的 **RSS 订阅** 页面可视化管理,搜索公众号一键订阅并复制 RSS 地址。

> **关于 RSS 内容**: RSS 源包含**完整文章内容**(图文混排),您可以直接在 RSS 阅读器中阅读全文。
>
> 系统使用 **SOCKS5 代理池 + Chrome TLS 指纹模拟**技术获取文章内容,有效规避微信风控。
>
> 扫码登录后,系统会**自动**将微信凭证用于内容获取,无需手动配置。如需禁用完整内容获取(仅保留标题和摘要),可在 `.env` 中设置 `RSS_FETCH_FULL_CONTENT=false`。

#### RSS 订阅管理接口

| 方法 | 路径 | 说明 |
|------|------|------|
| `POST` | `/api/rss/subscribe` | 添加 RSS 订阅 |
| `DELETE` | `/api/rss/subscribe/{fakeid}` | 取消 RSS 订阅 |
| `GET` | `/api/rss/subscriptions` | 获取订阅列表 |
| `POST` | `/api/rss/poll` | 手动触发轮询 |
| `GET` | `/api/rss/status` | 轮询器状态 |

### 其他接口

| 方法 | 路径 | 说明 |
|------|------|------|
| `GET` | `/api/image?url=IMG_URL` | 图片代理(仅限微信 CDN 域名) |
| `GET` | `/api/health` | 健康检查 |
| `GET` | `/api/stats` | 限频统计 |
| `POST` | `/api/login/session/{id}` | 初始化登录会话 |
| `GET` | `/api/login/getqrcode` | 获取登录二维码 |
| `GET` | `/api/login/scan` | 检查扫码状态 |
| `POST` | `/api/login/bizlogin` | 完成登录 |
| `GET` | `/api/login/info` | 获取登录信息 |
| `GET` | `/api/admin/status` | 查询登录状态 |
| `POST` | `/api/admin/logout` | 退出登录 |

完整的接口文档请访问 http://localhost:5000/api/docs

---

## 配置说明

复制 `env.example` 为 `.env`,登录后凭证会自动保存:

```bash
cp env.example .env
```

| 配置项 | 说明 | 默认值 |
|--------|------|--------|
| `WECHAT_TOKEN` | 微信 Token(登录后自动填充) | - |
| `WECHAT_COOKIE` | 微信 Cookie(登录后自动填充) | - |
| `WECHAT_FAKEID` | 公众号 FakeID(登录后自动填充) | - |
| `WEBHOOK_URL` | Webhook 通知地址(可选) | 空 |
| `RATE_LIMIT_GLOBAL` | 全局每分钟请求上限 | 10 |
| `RATE_LIMIT_PER_IP` | 单 IP 每分钟请求上限 | 5 |
| `RATE_LIMIT_ARTICLE_INTERVAL` | 文章请求最小间隔(秒) | 3 |
| `RSS_POLL_INTERVAL` | RSS 轮询间隔(秒) | 3600 |
| `RSS_FETCH_FULL_CONTENT` | RSS 是否获取完整内容(true/false) | true |
| `PROXY_URLS` | **SOCKS5 代理池地址(强烈建议配置,避免账号风控)** | 空 |
| `SITE_URL` | **网站访问地址(用于RSS图片代理,必须配置)** | http://localhost:5000 |
| `PORT` | 服务端口 | 5000 |
| `HOST` | 监听地址 | 0.0.0.0 |
| `DEBUG` | 调试模式(开启热重载) | false |

> **⚠️ 重要**: `SITE_URL` 必须配置为实际访问地址(IP或域名),否则RSS图片无法正常显示。例如:
> - 本地开发: `http://localhost:5000`
> - 局域网部署: `http://192.168.1.100:5000`
> - 公网域名: `https://你的域名.com`

### SOCKS5 代理池配置(⚠️ 强烈建议)

**重要提示**: 
- ⚠️ **启用完整内容获取时,强烈建议配置代理池,避免账号被微信风控**
- ⚠️ **不配置代理直连微信可能导致:频繁验证、账号限制、IP封禁**
- ✅ **配置2-3个代理IP可有效分散请求,降低风控风险**

**用途**:获取文章完整内容时分散请求 IP,配合 Chrome TLS 指纹模拟,有效规避微信风控。

> 本项目使用 `curl_cffi` 模拟 Chrome TLS 指纹,请求特征与真实浏览器一致,配合代理池效果更佳。

**方案:多台 VPS 自建 SOCKS5 代理**

准备 2-3 台低价 VPS(各大云厂商轻量应用服务器即可,¥20-30/月/台),每台运行一个 SOCKS5 代理服务。推荐 [gost](https://github.com/go-gost/gost)(Go 语言实现,单二进制文件,无依赖)。

**第一步:在每台 VPS 上安装 gost**

```bash
# 下载最新版(以 Linux amd64 为例,其他架构请去 GitHub Releases 页面选择)
# 国外服务器直接下载
wget https://github.com/go-gost/gost/releases/download/v3.2.6/gost_3.2.6_linux_amd64.tar.gz

# 国内服务器使用加速镜像(任选一个可用的)
wget https://gh-proxy.com/https://github.com/go-gost/gost/releases/download/v3.2.6/gost_3.2.6_linux_amd64.tar.gz
# 或
wget https://ghproxy.cc/https://github.com/go-gost/gost/releases/download/v3.2.6/gost_3.2.6_linux_amd64.tar.gz

# 解压并移动到系统路径
tar -xzf gost_3.2.6_linux_amd64.tar.gz
mv gost /usr/local/bin/
chmod +x /usr/local/bin/gost

# 验证安装
gost -V
```

**第二步:启动 SOCKS5 代理服务**

```bash
# 带用户名密码认证(推荐,替换 myuser / mypass 和端口)
gost -L socks5://myuser:mypass@:1080

# 不带认证(仅内网或已配置防火墙时使用)
gost -L socks5://:1080
```

**第三步:配置为 systemd 服务(开机自启)**

```bash
cat > /etc/systemd/system/gost.service << 'EOF'
[Unit]
Description=GOST Proxy
After=network.target

[Service]
Type=simple
ExecStart=/usr/local/bin/gost -L socks5://myuser:mypass@:1080
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable gost
systemctl start gost
```

**第四步:开放防火墙端口**

```bash
# 仅允许你的主服务器 IP 连接(替换为实际 IP)
ufw allow from YOUR_MAIN_SERVER_IP to any port 1080

# 或者如果用的是云厂商安全组,在控制台添加入站规则:
# 端口 1080 / TCP / 来源 IP 限制为你的主服务器
```

**第五步:在主服务器 `.env` 中配置代理池**

```bash
PROXY_URLS=socks5://myuser:mypass@vps1-ip:1080,socks5://myuser:mypass@vps2-ip:1080,socks5://myuser:mypass@vps3-ip:1080
```

配置后重启服务,每次文章请求会轮流使用不同的代理 IP。可以通过 `GET /api/health` 确认代理池状态。留空则直连(默认行为)。

---

## 项目结构

```
├── app.py                # FastAPI 主应用
├── requirements.txt      # Python 依赖
├── env.example           # 环境变量示例
├── data/                 # 数据目录(运行时自动创建)
│   └── rss.db            # RSS 订阅 SQLite 数据库
├── routes/               # API 路由
│   ├── article.py        # 文章内容获取
│   ├── articles.py       # 文章列表
│   ├── rss.py            # RSS 订阅管理与输出
│   ├── search.py         # 公众号搜索
│   ├── login.py          # 扫码登录
│   ├── admin.py          # 管理接口
│   ├── image.py          # 图片代理
│   ├── health.py         # 健康检查
│   └── stats.py          # 统计信息
├── utils/                # 工具模块
│   ├── auth_manager.py   # 认证管理
│   ├── helpers.py        # HTML 解析
│   ├── http_client.py    # HTTP 客户端(curl_cffi + 代理池)
│   ├── proxy_pool.py     # 代理池轮转
│   ├── rate_limiter.py   # 限频器
│   ├── rss_store.py      # RSS 数据存储(SQLite)
│   ├── rss_poller.py     # RSS 后台轮询器
│   ├── content_processor.py  # 内容处理与图片代理
│   ├── image_proxy.py    # 图片URL代理工具
│   ├── article_fetcher.py    # 批量并发获取文章
│   └── webhook.py        # Webhook 通知
└── static/               # 前端页面(含 RSS 管理)
```

---

## 内容类型与获取策略

本项目支持多种微信公众号内容类型,包括标准富文本、纯图片文章、图文消息、短内容、音频文章等。

详细说明请查看:**[CONTENT_TYPES.md](CONTENT_TYPES.md)**

**文档内容**:
- 所有支持的内容类型及 `item_show_type` 值
- 不可用状态识别(删除、违规、隐私、验证页面等)
- 反爬策略与代理配置
- 关键函数说明
- 开发贡献指南

---

## 常见问题

<details>
<summary><b>提示"服务器未登录"</b></summary>

访问 http://localhost:5000/login.html 扫码登录,凭证会自动保存到 `.env`。
</details>

<details>
<summary><b>触发微信风控 / 需要验证</b></summary>

1. 在浏览器中打开提示的文章 URL 完成验证
2. 等待 30 分钟后重试
3. 降低请求频率(系统已内置自动限频)
</details>

<details>
<summary><b>如何获取公众号的 FakeID</b></summary>

调用搜索接口:`GET /api/public/searchbiz?query=公众号名称`,从返回结果的 `fakeid` 字段获取。
</details>

<details>
<summary><b>Token 多久过期</b></summary>

Cookie 登录有效期约 4 天,过期后需重新扫码登录。配置 `WEBHOOK_URL` 可以在过期时收到通知。
</details>

<details>
<summary><b>可以同时登录多个公众号吗</b></summary>

当前版本不支持多账号。建议部署多个实例,每个登录不同公众号。
</details>

---

## 技术栈

| 层级 | 技术 |
|------|------|
| **Web 框架** | FastAPI |
| **ASGI 服务器** | Uvicorn |
| **HTTP 客户端** | curl_cffi(Chrome TLS 指纹)/ HTTPX(降级) |
| **反风控** | TLS 指纹模拟 + SOCKS5/HTTP 代理池轮转 |
| **RSS 存储** | SQLite(零配置,数据本地化) |
| **配置管理** | python-dotenv |
| **运行环境** | Python 3.8+ |

---

## 开源协议

本项目采用 **AGPL 3.0** 协议开源,**所有功能代码完整公开,私有化部署完全免费**。

| 使用场景 | 是否允许 |
|---------|---------|
| 个人学习和研究 | 允许,免费使用 |
| 企业内部使用 | 允许,免费使用 |
| 私有化部署 | 允许,免费使用 |
| 修改后对外提供网络服务 | 需开源修改后的代码 |

详见 [LICENSE](LICENSE) 文件。

### 免责声明

- 本软件按"原样"提供,不提供任何形式的担保
- 本项目仅供学习和研究目的,请遵守微信公众平台相关服务条款
- 使用者对自己的操作承担全部责任
- 因使用本软件导致的任何损失,开发者不承担责任

---

## 参与贡献

由于个人精力有限,目前**暂不接受 PR**,但非常欢迎:

- **提交 Issue** — 报告 Bug、提出功能建议
- **Fork 项目** — 自由修改和定制
- **Star 支持** — 给项目点 Star,让更多人看到

---

## 联系方式

<table>
  <tr>
    <td align="center">
      <img src="assets/qrcode/wechat.jpg" width="200"><br>
      <b>个人微信</b><br>
      <em>技术交流 · 商务合作</em>
    </td>
    <td align="center">
      <img src="assets/qrcode/sponsor.jpg" width="200"><br>
      <b>赞赏支持</b><br>
      <em>开源不易,感谢支持</em>
    </td>
  </tr>
</table>

- **GitHub Issues**: [提交问题](https://github.com/tmwgsicp/wechat-download-api/issues)
- **邮箱**: creator@waytomaster.com
- **SaaS 托管版**: [wechatrss.waytomaster.com](https://wechatrss.waytomaster.com)

---

## 致谢

- [FastAPI](https://fastapi.tiangolo.com/) — 高性能 Python Web 框架
- [curl_cffi](https://github.com/lexiforest/curl_cffi) — 支持浏览器 TLS 指纹模拟的 HTTP 客户端
- [HTTPX](https://www.python-httpx.org/) — 现代化 HTTP 客户端
- [gost](https://github.com/go-gost/gost) — 轻量级代理工具

---

<div align="center">

**如果觉得项目有用,请给个 Star 支持一下!**

[![Star History Chart](https://api.star-history.com/svg?repos=tmwgsicp/wechat-download-api&type=Date)](https://star-history.com/#tmwgsicp/wechat-download-api&Date)

Made with ❤️ by [tmwgsicp](https://github.com/tmwgsicp)

</div>
A
agent15:28

Excellent! This is a very detailed README. Now let me analyze the key modules to understand the architecture better. Let me check the app.py, routes, and utils to create a comprehensive architecture diagram.

A
agent15:28

Command:

curl -sL "https://api.github.com/repos/tmwgsicp/wechat-download-api/contents/routes" | python3 -c "import sys,json; d=json.load(sys.stdin); [print(f['name']) for f in d]"

__init__.py
admin.py
article.py
articles.py
health.py
image.py
login.py
rss.py
search.py
stats.py
A
agent15:28

Let me check the utils folder and key modules.

A
agent15:28

Command:

curl -sL "https://api.github.com/repos/tmwgsicp/wechat-download-api/contents/utils" | python3 -c "import sys,json; d=json.load(sys.stdin); [print(f['name']) for f in d]"

__init__.py
article_fetcher.py
auth_manager.py
content_processor.py
helpers.py
http_client.py
image_proxy.py
proxy_pool.py
rate_limiter.py
rss_poller.py
rss_store.py
webhook.py
A
agent15:28

Let me check some of the key files to understand the core logic.

A
agent15:28

Command:

curl -sL "https://api.github.com/repos/tmwgsicp/wechat-download-api/contents/utils/http_client.py" | python3 -c "import sys,json; d=json.load(sys.stdin); import base64; print(base64.b64decode(d['content']).decode()[:4000])"

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright (C) 2026 tmwgsicp
# Licensed under the GNU Affero General Public License v3.0
# See LICENSE file in the project root for full license text.
# SPDX-License-Identifier: AGPL-3.0-only
"""
HTTP 客户端封装
优先使用 curl_cffi(模拟 Chrome TLS 指纹),不可用时自动降级到 httpx。
支持代理池轮转:当前代理失败 → 尝试下一个 → 全部失败 → 直连兜底。

注意:
1. curl_cffi 的 AsyncSession 在部分环境下 SOCKS5 代理不工作,
   因此代理场景使用同步 Session + 线程池来规避此问题。
2. 优先使用 SOCKS5 代理,避免被封禁。
"""

import asyncio
import logging
from concurrent.futures import ThreadPoolExecutor
from typing import Optional, Dict

logger = logging.getLogger(__name__)

try:
    from curl_cffi.requests import Session as CurlSession
    HAS_CURL_CFFI = True
except ImportError:
    HAS_CURL_CFFI = False

ENGINE_NAME = "curl_cffi (Chrome TLS)" if HAS_CURL_CFFI else "httpx (fallback)"
logger.info("HTTP engine: %s", ENGINE_NAME)

BROWSER_HEADERS = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                  "AppleWebKit/537.36 (KHTML, like Gecko) "
                  "Chrome/120.0.0.0 Safari/537.36",
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,"
              "image/avif,image/webp,image/apng,*/*;q=0.8",
    "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
    "Accept-Encoding": "gzip, deflate, br",
    "Sec-Ch-Ua": '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"',
    "Sec-Ch-Ua-Mobile": "?0",
    "Sec-Ch-Ua-Platform": '"Windows"',
    "Sec-Fetch-Dest": "document",
    "Sec-Fetch-Mode": "navigate",
    "Sec-Fetch-Site": "none",
    "Sec-Fetch-User": "?1",
    "Upgrade-Insecure-Requests": "1",
}

MAX_PROXY_RETRIES = 3
_executor = ThreadPoolExecutor(max_workers=4)


async def fetch_page(url: str, extra_headers: Optional[Dict] = None,
                     timeout: int = 30) -> str:
    """
    获取网页 HTML 内容。
    请求策略:代理1 → 代理2 → ... → 直连兜底。
    成功的代理会被标记为健康,失败的会被临时冷却。
    """
    from utils.proxy_pool import proxy_pool

    headers = {**BROWSER_HEADERS}
    if extra_headers:
        headers.update(extra_headers)

    tried_proxies = []
    for _ in range(min(MAX_PROXY_RETRIES, proxy_pool.count)):
        proxy = proxy_pool.next()
        if proxy is None or proxy in tried_proxies:
            break
        tried_proxies.append(proxy)

        logger.info("fetch_page: url=%s proxy=%s", url[:80], proxy)
        try:
            result = await _do_fetch(url, headers, timeout, proxy)
            proxy_pool.mark_ok(proxy)
            return result
        except Exception as e:
            logger.warning("Proxy %s failed: %s", proxy, e)
            proxy_pool.mark_failed(proxy)

    logger.info("fetch_page: url=%s proxy=direct (fallback)", url[:80])
    return await _do_fetch(url, headers, timeout, None)


async def _do_fetch(url: str, headers: Dict, timeout: int,
                    proxy: Optional[str]) -> str:
    """执行实际的HTTP请求"""
    # SOCKS5 代理或无代理:正常请求
    if HAS_CURL_CFFI:
        return await _fetch_curl_cffi(url, headers, timeout, proxy)
    return await _fetch_httpx(url, headers, timeout, proxy)


async def _fetch_curl_cffi(url: str, headers: Dict, timeout: int,
                           proxy: Optional[str]) -> str:
    loop = asyncio.get_event_loop()
    return await loop.run_in_executor(
        _executor,
        _fetch_curl_cffi_sync, url, headers, timeout, proxy
    )


def _fetch_curl_cffi_sync(url: str, headers: Dict, timeout: int,
                          proxy: Optional[str]) -> str:
    """同步请求,在线程池中执行。规避 AsyncSession + SOCKS5 代理的兼容性问题。"""
    kwargs = {"timeout": timeout, "allow_redirects": True, "verify": False}  # 跳过 SSL 验证
    if proxy:
        kwargs["proxy"] = proxy
    with CurlSession(impersonate="chrome120") as session:
        resp = session.get(url, headers=headers, **kwargs)
        resp.raise_for_status()
        return resp.text


async def _fetch_httpx(url: str, headers: Dict, timeout: int,
                       proxy: Optional[str]) -> str:
    import httpx
    transport_kwargs = {}
    if proxy:
A
agent15:28

Now I have a good understanding of the project. Let me check one more key file - the auth_manager.py to understand the login flow.

A
agent15:28

Command:

curl -sL "https://api.github.com/repos/tmwgsicp/wechat-download-api/contents/utils/auth_manager.py" | python3 -c "import sys,json; d=json.load(sys.stdin); import base64; print(base64.b64decode(d['content']).decode()[:3000])"

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright (C) 2026 tmwgsicp
# Licensed under the GNU Affero General Public License v3.0
# See LICENSE file in the project root for full license text.
# SPDX-License-Identifier: AGPL-3.0-only
"""
认证管理器 - FastAPI版本
管理微信登录凭证(Token、Cookie等)
"""

import os
import time
from pathlib import Path
from typing import Optional, Dict
from dotenv import load_dotenv, set_key

class AuthManager:
    """认证管理单例类"""
    
    _instance = None
    
    def __new__(cls):
        if cls._instance is None:
            cls._instance = super(AuthManager, cls).__new__(cls)
            cls._instance._initialized = False
        return cls._instance
    
    def __init__(self):
        if self._initialized:
            return
        
        # 设置.env文件路径(python-api目录下)
        self.base_dir = Path(__file__).parent.parent
        self.env_path = self.base_dir / ".env"
        
        # Docker环境下的凭证文件(存储在data目录,权限更可靠)
        self.credentials_file = self.base_dir / "data" / ".credentials.json"
        
        # 加载环境变量
        self._load_credentials()
        self._initialized = True
    
    def _load_credentials(self):
        """
        从多个来源加载凭证,优先级:
        1. data/.credentials.json (Docker环境推荐)
        2. .env 文件 (本地部署)
        3. 环境变量
        """
        # 先尝试从 JSON 凭证文件加载(Docker 环境)
        if self.credentials_file.exists():
            try:
                import json
                with open(self.credentials_file, 'r', encoding='utf-8') as f:
                    self.credentials = json.load(f)
                return
            except Exception as e:
                print(f"Warning: Failed to load credentials from {self.credentials_file}: {e}")
        
        # 回退到 .env 文件(本地部署)
        if self.env_path.exists():
            load_dotenv(self.env_path, override=True)
        
        self.credentials = {
            "token": os.getenv("WECHAT_TOKEN", ""),
            "cookie": os.getenv("WECHAT_COOKIE", ""),
            "fakeid": os.getenv("WECHAT_FAKEID", ""),
            "nickname": os.getenv("WECHAT_NICKNAME", ""),
            "expire_time": int(os.getenv("WECHAT_EXPIRE_TIME") or 0)
        }
    
    def save_credentials(self, token: str, cookie: str, fakeid: str, 
                        nickname: str, expire_time: int) -> bool:
        """
        保存凭证,支持双存储策略:
        1. 优先保存到 data/.credentials.json (Docker环境推荐,权限可靠)
        2. 同时尝试保存到 .env (本地部署兼容)
        
        Args:
            token: 微信Token
            cookie: 微信Cookie
            fakeid: 公众号ID
            nickname: 公众号名称
            expire_time: 过期时间(毫秒时间戳)
        
        Returns:
            保存是否成功
        """
        # 更新内存中的凭证
        self.credentials.update({
            "token": token,
            "cookie": cookie,
            "fakeid": fakeid,
            "nickname": nickname,
            "expire_time": expire_time
        })
        
        success = False
        
        # 策略1: 保存到 data/.credentials.json (Docker 环境优先)
        try:
A
agent15:30

Now I have enough information to create a comprehensive architecture diagram. Let me summarize the project.

A
agent15:30

Now I have enough information. Let me provide a comprehensive analysis with a principle diagram.


🔐 wechat-download-api 架构分析

📋 项目概况

属性
名称 WeChat Download API
描述 微信公众号文章获取 & RSS 订阅服务
Stars 389 ⭐
语言 Python
框架 FastAPI
许可证 AGPL 3.0

🏗️ 系统架构原理图

┌─────────────────────────────────────────────────────────────────────────┐
│                          用户层 (Client)                                 │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│    ┌──────────────┐   ┌──────────────┐   ┌──────────────┐               │
│    │  RSS 阅读器  │   │   管理面板    │   │   API 客户端 │               │
│    │  (Feedly)   │   │  /login.html │   │  (curl/wget) │               │
│    └──────┬───────┘   └──────┬───────┘   └──────┬───────┘               │
│           │                  │                  │                        │
│           │    ┌─────────────┼──────────────────┘                       │
│           │    │             │                                            │
│           ▼    │             ▼                                            │
│    /api/rss/{fakeid}  /api/docs (Swagger)                                │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────────────────┐
│                        FastAPI 应用层 (app.py)                           │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │                         路由层 (routes/)                          │   │
│  │  ┌─────────┐ ┌──────────┐ ┌────────┐ ┌────────┐ ┌───────────┐   │   │
│  │  │ article │ │ articles │ │  rss   │ │ search │ │   login   │   │   │
│  │  │ 文章内容│ │ 文章列表  │ │ RSS订阅│ │公众号搜索│ │  扫码登录  │   │   │
│  │  └────┬────┘ └────┬─────┘ └───┬────┘ └───┬────┘ └─────┬─────┘   │   │
│  └───────┼───────────┼───────────┼──────────┼────────────┼─────────┘   │
│          │           │           │          │            │             │
└──────────┼───────────┼───────────┼──────────┼────────────┼─────────────┘
           │           │           │          │            │
           ▼           ▼           ▼          ▼            ▼
┌─────────────────────────────────────────────────────────────────────────┐
│                         工具层 (utils/)                                  │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  ┌────────────────┐  ┌────────────────┐  ┌─────────────────────────┐  │
│  │  auth_manager  │  │  proxy_pool    │  │    rate_limiter         │  │
│  │  认证管理       │  │  代理池轮转    │  │    三层限频器            │  │
│  │  Token/Cookie  │  │  SOCKS5 轮换   │  │    全局/IP/文章间隔      │  │
│  └───────┬────────┘  └───────┬────────┘  └────────────┬────────────┘  │
│          │                   │                       │                 │
│  ┌───────┴───────────────────┴───────────────────────┴─────────────┐  │
│  │                     http_client (curl_cffi)                      │  │
│  │  ┌────────────────────────────────────────────────────────────┐  │  │
│  │  │  🔐 Chrome TLS 指纹模拟 (impersonate="chrome120")          │  │  │
│  │  │  📋 完整浏览器请求头                                        │  │  │
│  │  │  🔄 代理失败自动重试 + 直连兜底                             │  │  │
│  │  └────────────────────────────────────────────────────────────┘  │  │
│  └──────────────────────────────────────────────────────────────────┘  │
│                                    │                                    │
└────────────────────────────────────┼────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────────────────┐
│                           反风控体系                                      │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│   ┌─────────────┐    ┌─────────────┐    ┌─────────────┐                │
│   │ TLS 指纹    │ +  │  SOCKS5 代理 │ +  │   限频器    │                │
│   │ Chrome 120  │    │   池轮转     │    │  三层控制   │                │
│   └─────────────┘    └──────┬──────┘    └─────────────┘                │
│                              │                                          │
│          ┌───────────────────┼────────────────────┐                     │
│          ▼                   ▼                    ▼                     │
│   ┌────────────┐      ┌────────────┐       ┌────────────┐              │
│   │  VPS 1     │      │  VPS 2     │  ...  │  VPS N     │              │
│   │  SOCKS5    │      │  SOCKS5    │       │  SOCKS5    │              │
│   │  (1080)    │      │  (1080)    │       │  (1080)    │              │
│   └────────────┘      └────────────┘       └────────────┘              │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────────────────┐
│                           微信公众平台 API                                 │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│   ┌─────────────────────────────────────────────────────────────────┐   │
│   │                    mp.weixin.qq.com                             │   │
│   │                                                                  │   │
│   │   ┌──────────────┐  ┌──────────────┐  ┌──────────────────┐    │   │
│   │   │  获取文章内容  │  │  搜索公众号   │  │   获取文章列表   │    │   │
│   │   │  /s/xxx       │  │  searchbiz   │  │   appmsg/list    │    │   │
│   │   └──────────────┘  └──────────────┘  └──────────────────┘    │   │
│   │                                                                  │   │
│   │   ┌──────────────────────────────────────────────────────────┐  │   │
│   │   │  🔑 凭证: Token + Cookie (扫码登录获取,有效期4天)       │  │   │
│   │   └──────────────────────────────────────────────────────────┘  │   │
│   └─────────────────────────────────────────────────────────────────┘   │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────────────────┐
│                           数据存储层                                     │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│   ┌─────────────────┐              ┌─────────────────┐                   │
│   │    SQLite       │              │   .env / JSON   │                   │
│   │   rss.db        │              │  .credentials   │                   │
│   │   RSS订阅数据    │              │   登录凭证      │                   │
│   └─────────────────┘              └─────────────────┘                   │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

🔄 核心流程

1️⃣ 扫码登录流程

用户扫码 → /api/login/getqrcode → 微信公众平台 → 扫码确认 
→ /api/login/scan 检测 → /api/login/bizlogin 完成 → 保存 Token/Cookie

2️⃣ 文章获取流程

API 请求 → 限频检查 → 代理池选择 → Chrome TLS 指纹 → 微信 API 
→ HTML 解析 → 内容处理 → 返回 JSON

3️⃣ RSS 订阅流程

订阅公众号 → 保存 fakeid → 后台轮询器定时触发 
→ 获取新文章 → 存储 SQLite → RSS 格式输出 → 阅读器拉取

🔧 关键技术

技术 用途
curl_cffi Chrome TLS 指纹模拟,让请求看起来像真实浏览器
SOCKS5 代理池 多 VPS 轮转,避免 IP 被封
三层限频 全局 10/min + 单 IP 5/min + 文章间隔 3s
FastAPI 高性能异步 API 框架
SQLite RSS 数据持久化

⚠️ 安全/法律风险

风险 等级 说明
账号风控 🟡 中 频繁请求可能导致微信验证/封禁
法律风险 🟡 中 抓取公众号内容可能违反微信服务条款
代理暴露 🟢 低 代理池配置不当可能暴露源 IP

🏆 总结

这是一个微信公众号内容聚合工具,通过模拟浏览器 TLS 指纹 + 代理池轮转来对抗微信风控,实现:

  • 任意公众号文章获取
  • RSS 订阅支持
  • 图片代理防盗链

⚠️ 仅供学习研究使用,请遵守相关服务条款

A
agent15:30

The user wants me to compare wechat-download-api with another project: rachelos/we-mp-rss. Let me first get information about this second project.

A
agent15:30

Command:

curl -sL "https://api.github.com/repos/rachelos/we-mp-rss"

{
  "id": 983305992,
  "node_id": "R_kgDOOpwPCA",
  "name": "we-mp-rss",
  "full_name": "rachelos/we-mp-rss",
  "private": false,
  "owner": {
    "login": "rachelos",
    "id": 190435456,
    "node_id": "O_kgDOC1nQgA",
    "avatar_url": "https://avatars.githubusercontent.com/u/190435456?v=4",
    "gravatar_id": "",
    "url": "https://api.github.com/users/rachelos",
    "html_url": "https://github.com/rachelos",
    "followers_url": "https://api.github.com/users/rachelos/followers",
    "following_url": "https://api.github.com/users/rachelos/following{/other_user}",
    "gists_url": "https://api.github.com/users/rachelos/gists{/gist_id}",
    "starred_url": "https://api.github.com/users/rachelos/starred{/owner}{/repo}",
    "subscriptions_url": "https://api.github.com/users/rachelos/subscriptions",
    "organizations_url": "https://api.github.com/users/rachelos/orgs",
    "repos_url": "https://api.github.com/users/rachelos/repos",
    "events_url": "https://api.github.com/users/rachelos/events{/privacy}",
    "received_events_url": "https://api.github.com/users/rachelos/received_events",
    "type": "Organization",
    "user_view_type": "public",
    "site_admin": false
  },
  "html_url": "https://github.com/rachelos/we-mp-rss",
  "description": "✨符合阅读习惯的微信公众号助手、微信公众号转MarkDown、微信公众号转PDF、定时更新订阅公众号文章、生成微信公众号RSS订阅源、导出微信公众号订阅源、支持微信公众号Webhook/微信公众号API/AI Agent接入微信公众号微信公众号、订阅微信公众号、微信公众号助手 、微信公众号阅读、微信公众号接口、微信公众号爬虫、微信公众号监测、标签订阅微信公众号、微信公众号源、微信公众号读书、微信公众号文章、微信公众号框架、微信公众号管理、微信公众号源、微信公众号平台、微信公众号代码、微信公众号系统、微信公众号源码",
  "fork": false,
  "url": "https://api.github.com/repos/rachelos/we-mp-rss",
  "forks_url": "https://api.github.com/repos/rachelos/we-mp-rss/forks",
  "keys_url": "https://api.github.com/repos/rachelos/we-mp-rss/keys{/key_id}",
  "collaborators_url": "https://api.github.com/repos/rachelos/we-mp-rss/collaborators{/collaborator}",
  "teams_url": "https://api.github.com/repos/rachelos/we-mp-rss/teams",
  "hooks_url": "https://api.github.com/repos/rachelos/we-mp-rss/hooks",
  "issue_events_url": "https://api.github.com/repos/rachelos/we-mp-rss/issues/events{/number}",
  "events_url": "https://api.github.com/repos/rachelos/we-mp-rss/events",
  "assignees_url": "https://api.github.com/repos/rachelos/we-mp-rss/assignees{/user}",
  "branches_url": "https://api.github.com/repos/rachelos/we-mp-rss/branches{/branch}",
  "tags_url": "https://api.github.com/repos/rachelos/we-mp-rss/tags",
  "blobs_url": "https://api.github.com/repos/rachelos/we-mp-rss/git/blobs{/sha}",
  "git_tags_url": "https://api.github.com/repos/rachelos/we-mp-rss/git/tags{/sha}",
  "git_refs_url": "https://api.github.com/repos/rachelos/we-mp-rss/git/refs{/sha}",
  "trees_url": "https://api.github.com/repos/rachelos/we-mp-rss/git/trees{/sha}",
  "statuses_url": "https://api.github.com/repos/rachelos/we-mp-rss/statuses/{sha}",
  "languages_url": "https://api.github.com/repos/rachelos/we-mp-rss/languages",
  "stargazers_url": "https://api.github.com/repos/rachelos/we-mp-rss/stargazers",
  "contributors_url": "https://api.github.com/repos/rachelos/we-mp-rss/contributors",
  "subscribers_url": "https://api.github.com/repos/rachelos/we-mp-rss/subscribers",
  "subscription_url": "https://api.github.com/repos/rachelos/we-mp-rss/subscription",
  "commits_url": "https://api.github.com/repos/rachelos/we-mp-rss/commits{/sha}",
  "git_commits_url": "https://api.github.com/repos/rachelos/we-mp-rss/git/commits{/sha}",
  "comments_url": "https://api.github.com/repos/rachelos/we-mp-rss/comments{/number}",
  "issue_comment_url": "https://api.github.com/repos/rachelos/we-mp-rss/issues/comments{/number}",
  "contents_url": "https://api.github.com/repos/rachelos/we-mp-rss/contents/{+path}",
  "compare_url": "https://api.github.com/repos/rachelos/we-mp-rss/compare/{base}...{head}",
  "merges_url": "https://api.github.com/repos/rachelos/we-mp-rss/merges",
  "archive_url": "https://api.github.com/repos/rachelos/we-mp-rss/{archive_format}{/ref}",
  "downloads_url": "https://api.github.com/repos/rachelos/we-mp-rss/downloads",
  "issues_url": "https://api.github.com/repos/rachelos/we-mp-rss/issues{/number}",
  "pulls_url": "https://api.github.com/repos/rachelos/we-mp-rss/pulls{/number}",
  "milestones_url": "https://api.github.com/repos/rachelos/we-mp-rss/milestones{/number}",
  "notifications_url": "https://api.github.com/repos/rachelos/we-mp-rss/notifications{?since,all,participating}",
  "labels_url": "https://api.github.com/repos/rachelos/we-mp-rss/labels{/name}",
  "releases_url": "https://api.github.com/repos/rachelos/we-mp-rss/releases{/id}",
  "deployments_url": "https://api.github.com/repos/rachelos/we-mp-rss/deployments",
  "created_at": "2025-05-14T07:28:21Z",
  "updated_at": "2026-03-27T03:52:47Z",
  "pushed_at": "2026-03-27T03:52:42Z",
  "git_url": "git://github.com/rachelos/we-mp-rss.git",
  "ssh_url": "git@github.com:rachelos/we-mp-rss.git",
  "clone_url": "https://github.com/rachelos/we-mp-rss.git",
  "svn_url": "https://github.com/rachelos/we-mp-rss",
  "homepage": "https://werss.csol.store",
  "size": 191579,
  "stargazers_count": 2620,
  "watchers_count": 2620,
  "language": "Python",
  "has_issues": true,
  "has_projects": true,
  "has_downloads": true,
  "has_wiki": true,
  "has_pages": false,
  "has_discussions": true,
  "forks_count": 455,
  "mirror_url": null,
  "archived": false,
  "disabled": false,
  "open_issues_count": 4,
  "license": {
    "key": "other",
    "name": "Other",
    "spdx_id": "NOASSERTION",
    "url": null,
    "node_id": "MDc6TGljZW5zZTA="
  },
  "allow_forking": true,
  "is_template": false,
  "web_commit_signoff_required": false,
  "has_pull_requests": true,
  "pull_request_creation_policy": "all",
  "topics": [
    "folo",
    "mysql",
    "rss-feed",
    "rss-hub",
    "rsshub",
    "we-mp-rss",
    "weichat",
    "weixin",
    "weread",
    "werss",
    "wexinrss",
    "wx",
    "wxsprider"
  ],
  "visibility": "public",
  "forks": 455,
  "open_issues": 4,
  "watchers": 2620,
  "default_branch": "main",
  "temp_clone_token": null,
  "custom_properties": {

  },
  "organization": {
    "login": "rachelos",
    "id": 190435456,
    "node_id": "O_kgDOC1nQgA",
    "avatar_url": "https://avatars.githubusercontent.com/u/190435456?v=4",
    "gravatar_id": "",
    "url": "https://api.github.com/users/rachelos",
    "html_url": "https://github.com/rachelos",
    "followers_url": "https://api.github.com/users/rachelos/followers",
    "following_url": "https://api.github.com/users/rachelos/following{/other_user}",
    "gists_url": "https://api.github.com/users/rachelos/gists{/gist_id}",
    "starred_url": "https://api.github.com/users/rachelos/starred{/owner}{/repo}",
    "subscriptions_url": "https://api.github.com/users/rachelos/subscriptions",
    "organizations_url": "https://api.github.com/users/rachelos/orgs",
    "repos_url": "https://api.github.com/users/rachelos/repos",
    "events_url": "https://api.github.com/users/rachelos/events{/privacy}",
    "received_events_url": "https://api.github.com/users/rachelos/received_events",
    "type": "Organization",
    "user_view_type": "public",
    "site_admin": false
  },
  "network_count": 455,
  "subscribers_count": 13
}
A
agent15:30

Wow, this is a much more popular project - 2620 stars, 455 forks! Let me get more details about its structure and features.

A
agent15:30

Command:

curl -sL "https://api.github.com/repos/rachelos/we-mp-rss/contents" | python3 -c "import sys,json; d=json.load(sys.stdin); [print(f['name']) for f in d]"

.dockerignore
.env.example
.github
.gitignore
.vscode
AGENTS.md
CONTRIBUTING.md
Dockerfile
Dockerfiles
FIX_CASCADE_CONFIG.md
LICENSE
README.zh-CN.md
ReadMe.md
SECURITY.md
TROUBLESHOOTING_CASCADE.md
apis
atack.py
check_cascade_creds.py
compose
config-node.yaml
config.example.yaml
core
data_sync.py
debug_template_parser.py
diagnose_config.py
dns.py
doc2pdf
dock_build.bat
docs
domains.txt
driver
examples
github_update.py
go.mod
init_sys.py
install.sh
job.py
jobs
main.py
migrations
public
publish.bat
qtserver
quick_check_parent.py
requirements.txt
schemas
script
start.bat
start.sh
static
test_article.py
tool.py
tools
update.sh
verify_cascade_creds.py
verify_imports.py
views
web.py
web_ui
A
agent15:32

This is a much larger and more complex project. It has:

  • Python core
  • Go module (go.mod)
  • web_ui (likely Vue or similar frontend)
  • doc2pdf (document to PDF conversion)
  • APIs
  • etc.

Let me get more details about the features and architecture.

A
agent15:32

Command:

curl -sL "https://api.github.com/repos/rachelos/we-mp-rss/contents/README.zh-CN.md" | python3 -c "import sys,json; d=json.load(sys.stdin); import base64; print(base64.b64decode(d['content']).decode()[:8000])"

<div align=center>
<img src="static/logo.svg" alt="We-MP-RSS Logo" width="20%">
<h1>WeRSS - 微信公众号订阅助手</h1>

[![Python Version](https://img.shields.io/badge/python-3.13.1+-red.svg)]()
[![License](https://img.shields.io/badge/license-MIT-green.svg)]()

[中文](README.zh-CN.md)|[English](ReadMe.md)

快速运行
```
docker run -d  --name we-mp-rss  -p 8001:8001 -v ./data:/app/data  ghcr.io/rachelos/we-mp-rss:latest
```
http://<您的ip>:8001/  即可开启

# 快速升级 

```
docker stop we-mp-rss
docker rm we-mp-rss
docker pull ghcr.io/rachelos/we-mp-rss:latest
# 如果添加了其它参数,请自行修改
docker run -d  --name we-mp-rss  -p 8001:8001 -v ./data:/app/data  ghcr.io/rachelos/we-mp-rss:latest
```

# 官方镜像
```
docker run -d  --name we-mp-rss  -p 8001:8001 -v ./data:/app/data  rachelos/we-mp-rss:latest
```
# 代理镜像加速访问(国内访问速度更快)
```
docker run -d  --name we-mp-rss  -p 8001:8001 -v ./data:/app/data  docker.1ms.run/rachelos/we-mp-rss:latest  
```

# 感谢伙伴(排名不分先后)
 cyChaos、 子健MeLift、 晨阳、 童总、 胜宇、 军亮、 余光、 一路向北、 水煮土豆丝、 人可、 须臾、 澄明
、五梭




 <br/>
 <img src="https://github.com/user-attachments/assets/cbe924f2-d8b0-48b0-814e-7c06ccb1911c" height="60" />
    <img src="https://github.com/user-attachments/assets/6997a236-3df3-49d5-98a4-514f6d1a02c4" height="60" />
    <br />
    <br />
    <a href="https://github.com/RSSNext/Folo/stargazers"><img src="https://img.shields.io/github/stars/RSSNext/Follow?color=ffcb47&labelColor=black&style=flat-square&logo=github&label=Stars" /></a>
    <a href="https://github.com/RSSNext/Folo/graphs/contributors"><img src="https://img.shields.io/github/contributors/RSSNext/Folo?style=flat-square&logo=github&label=Contributors&labelColor=black" /></a>
    <a href="https://status.follow.is/" target="_blank"><img src="https://status.follow.is/api/badge/18/uptime?color=%2344CC10&labelColor=black&style=flat-square"/></a>
    <a href="https://github.com/RSSNext/Folo/releases"><img src="https://img.shields.io/github/downloads/RSSNext/Folo/total?color=369eff&labelColor=black&logo=github&style=flat-square&label=Downloads" /></a>
    <a href="https://x.com/intent/follow?screen_name=folo_is"><img src="https://img.shields.io/badge/Follow-blue?color=1d9bf0&logo=x&labelColor=black&style=flat-square" /></a>
    <a href="https://discord.gg/followapp" target="_blank"><img src="https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fdiscord.com%2Fapi%2Finvites%2Ffollowapp%3Fwith_counts%3Dtrue&query=approximate_member_count&color=5865F2&label=Discord&labelColor=black&logo=discord&logoColor=white&style=flat-square"/></a>
    <br />
一个用于订阅和管理微信公众号内容的工具,提供RSS订阅功能。
</div>
<p align="center">
  <a href="https://github.com/DIYgod/sponsors">
    <img src="https://raw.githubusercontent.com/DIYgod/sponsors/main/sponsors.wide.svg" />
  </a>
</p>

## 功能特性

- 微信公众号内容抓取和解析
- RSS订阅生成
- 用户友好的Web管理界面
- 定时自动更新内容
- 支持多种数据库(默认SQLite,可选MySQL)
- 支持多种抓取方式
- 支持多种RSS客户端
- 支持授权过期提醒
- 支持自定义通知渠道
- 支持自定义RSS标题、描述、封面
- 支持自定义RSS分页大小
- 支持导出md/docx/pdf/json格式
- 支持API接口调用/WebHook调用


# ❤️ 赞助
如果觉得 We-MP-RSS 对你有帮助,欢迎给我来一杯啤酒!<br/>
<img src="docs/赞赏码.jpg" width=180/>
[Paypal](https://www.paypal.com/ncp/payment/PUA72WYLAV5KW)

## 界面截图
- 登录界面  
<img src="docs/登录.png" alt="登录" width="80%"/><br/>
- 主界面  
<img src="docs/主界面.png" alt="主界面" width="80%"/><br/>
- 扫码授权  
<img src="docs/扫码授权.png" alt="扫码授权" width="80%"/><br/>
- 添加订阅  
<img src="docs/添加订阅.png" alt="添加订阅" width="80%"/><br/>

- 客户端应用<br/>
<img src="docs/folo.webp" alt="FOLO客户端应用" width="80%"/><br/>



## 系统架构

项目采用前后端分离架构:
- 后端:Python + FastAPI
- 前端:Vue 3 + Vite
- 数据库:SQLite (默认)/MySQL
<img src="docs/架构原理.png" alt="架构原理" width="80%"/>

更多项目原理,请参考[项目文档](https://deepwiki.com/rachelos/we-mp-rss/3.5-notification-system)。

## 安装指南

# 二次开发
## 环境需求
- Python>=3.13.1
- Node>=20.18.3
### 后端服务

1. 克隆项目
```bash
git clone https://github.com/rachelos/we-mp-rss.git
cd we-mp-rss
```

2. 安装Python依赖
```bash
pip install -r requirements.txt
```

3. 配置数据库
复制并修改配置文件:
```bash
cp config.example.yaml config.yaml
copy config.example.yaml config.yaml
```
3. 启动服务
```bash
python main.py -job True -init True
```

## 前端开发
1. 安装前端依赖
```bash
cd we-mp-rss/web_ui
yarn install
```

2. 启动前端服务
```bash
yarn dev
```
3. 访问前端页面
```
http://localhost:3000
```

# 环境变量配置

以下是 `config.yaml` 中支持的环境变量配置:

| 环境变量 | 默认值 | 描述 |
|----------|--------|------|
| `APP_NAME` | `we-mp-rss` | 应用名称 |
| `SERVER_NAME` | `we-mp-rss` | 服务名称 |
| `WEB_NAME` | `WeRSS微信公众号订阅助手` | 前端显示名称 |
| `WERSS_AUTH_WEB` | `False` | 通过web方式授权 |
| `BROWSER_TYPE` | `firefox` | 浏览器类型默认firefox |
| `SEND_CODE` | `True` | 是否发送授权二维码通知 |
| `CODE_TITLE` | `WeRSS授权二维码` | 二维码通知标题 |
| `ENABLE_JOB` | `True` | 是否启用定时任务 |
| `AUTO_RELOAD` | `False` | 代码修改自动重启服务 |
| `THREADS` | `2` | 最大线程数 |
| `DB` | `sqlite:///data/db.db` | 数据库连接字符串 |
| `DINGDING_WEBHOOK` | 空 | 钉钉通知Webhook地址 |
| `WECHAT_WEBHOOK` | 空 | 微信通知Webhook地址 |
| `FEISHU_WEBHOOK` | 空 | 飞书通知Webhook地址 |
| `CUSTOM_WEBHOOK` | 空 | 自定义通知Webhook地址 |
| `SECRET_KEY` | `we-mp-rss` | 密钥 |
| `USER_AGENT` | `Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36/WeRss` | 用户代理 |
| `SPAN_INTERVAL` | `10` | 定时任务执行间隔(秒) |
| `WEBHOOK.CONTENT_FORMAT` | `html` | 文章内容发送格式 |
| `PORT` | `8001` | API服务端口 |
| `DEBUG` | `False` | 调试模式 |
| `MAX_PAGE` | `5` | 最大采集页数 |
| `RSS_BASE_URL` | 空 | RSS域名地址 |
| `RSS_LOCAL` | `False` | 是否为本地RSS链接 |
| `RSS_TITLE` | 空 | RSS标题 |
| `RSS_DESCRIPTION` | 空 | RSS描述 |
| `RSS_COVER` | 空 | RSS封面 |
| `RSS_FULL_CONTEXT` | `True` | 是否显示全文 |
| `RSS_ADD_COVER` | `True` | 是否添加封面图片 |
| `RSS_CDATA` | `False` | 是否启用CDATA |
| `RSS_PAGE_SIZE` | `30` | RSS分页大小 |
| `TOKEN_EXPIRE_MINUTES` | `4320` | 登录会话有效时长(分钟) |
| `CACHE.DIR` | `./data/cache` | 缓存目录 |
| `ARTICLE.TRUE_DELETE` | `False` | 是否真实删除文章 |
| `GATHER.CONTENT` | `True` | 是否采集内容 |
| `GATHER.MODEL` | `app` | 采集模式 |
| `GATHER.CONTENT_AUTO_CHECK` | `False` | 是否自动检查未采集文章内容 |
| `GATHER.CONTENT_AUTO_INTERVAL` | `59` | 自动检查未采集文章内容的时间间隔(分钟) |
| `GATHER.CONTENT_MODE` | `web` | 内容修正模式 |
| `SAFE_HIDE_CONFIG` | `db,secret,token,notice.wechat,notice.feishu,notice.dingding` | 需要隐藏的配置信息 |
| `SAFE_LIC_KEY` | `RACHELOS` | 授权加密KEY |
| `LOG_FILE` | 空 | 日志文件路径 |
| `LOG_LEVEL` | `INFO` | 日志级别 |
| `EXPORT_PDF` | `False` | 是否启用PDF导出功能 |
| `EXPORT_PDF_DIR` | `./data/pdf` | PDF导出目录 |
| `EXPORT_MARKDOWN` | `False` | 是否启用markdown导出功能 |
| `EXPORT_MARKDOWN_DIR` | `./data/markdown` | markdown导出目录 |

# 使用说明

1. 启动服务后,访问 `http://<您的IP>:8001` 进入管理界面。
2. 使用微信扫码授权后,即可添加和管理订阅。
3. 定时任务会自动更新内容,并生成RSS订阅链接。

## Access Key 认证

WeRSS 支持使用 Access Key (AK) 进行 API 认证,适用于程序化访问和自动化脚本。

### 创建 Access Key

1. 登录 WeRSS 管理界面
2. 进入"Access Key 管理"页面
3. 点击"创建 Access Key"按钮
4. 填写名称、描述、权限和过期时间
5. 创建成功后,妥善保存 Access Key 和 Secret Key(Secret Key 只显示一次)

### 使用 Access Key 调用 API

在请求头中添加 `Authorization` 字段,格式为 `AK-SK {access_key}:{secret_key}`:

```bash
curl -H "Authorization: AK-SK your_access_key:your_secret_key" \
     http://localhost:8001/api/feeds
```

#### Python 示例

```python
import requests

access_key = "your_access_key"
secret_key = "your_secret_key"
base_url = "http://localhost:8001"

headers = {
    "Authorization": f"AK-SK {access_key}:{secret_key}"
}

# 获取订阅列表
response = requests.get(f"{base_url}/api/feeds", headers=headers)
print(response.json())
```

#### JavaScript 示例

```javascript
const accessKey = "your_access_key";
const secretKey = "your_secret_key";
const baseUrl = "http://localhost:8001";

const headers = {
  "Authorization": `AK-SK ${accessKey}:${secretKey}`
};

// 获取订阅列表
fetch(`${baseUrl}/api/feeds`, { headers })
  .then(res => res.json())
  .then(data => console.log(data));
```

详细文档请参考:[AK 认证指南](docs/AK_Authentication_Guide.md)

# 常见问题

- **如何修改数据库连接?**
  在 `config.yaml` 中修改 `db` 配置项,或通过环境变量 `DB` 覆盖。

- **如何启用钉钉通知?**
  在 `config.yaml` 中填写 `notice.dingding` 或通过环境变量 `DINGDING_WEBHOOK` 设置。

- **如何调整定时任务间隔?**
  修改 `config.yaml` 中的
A
agent15:32

This is a very comprehensive project. Let me get the directory structure to understand it better and compare the two projects.

A
agent15:32

Command:

curl -sL "https://api.github.com/repos/rachelos/we-mp-rss/contents/core" | python3 -c "import sys,json; d=json.load(sys.stdin); [print(f['name']) for f in d]"

article_content.py
article_lax.py
auth.py
base.py
cache.py
cascade.py
common
config.py
content_format.py
database.py
db.py
file.py
lax
log.py
models
notice
print.py
queue
redis_client.py
res
resource.py
rss.py
task
thread.py
ver.py
wait.py
webhook
wx
yaml_db
A
agent15:32

This is a much larger project. Let me summarize the comparison between the two projects.

A
agent15:32

Command:

curl -sL "https://api.github.com/repos/rachelos/we-mp-rss/contents/apis" | python3 -c "import sys,json; d=json.load(sys.stdin); [print(f['name']) for f in d]"

article.py
auth.py
base.py
cache.py
cascade.py
config_management.py
env_exception.py
export.py
filter_rule.py
github_update.py
message_task.py
mps.py
res.py
rss.py
sys_info.py
tags.py
tools.py
user.py
ver.py
A
agent15:32

Now I have enough information to compare the two projects. Let me create a comprehensive comparison.

A
agent15:32

📊 微信公众号 RSS 项目对比

项目概况

属性 wechat-download-api we-mp-rss (WeRSS)
Stars 389 ⭐ 2,620 ⭐
Forks 24 455
语言 Python Python + Vue
许可证 AGPL 3.0 MIT
规模 小型 (~800KB) 大型 (~192MB)

功能对比

功能 wechat-download-api we-mp-rss
RSS 订阅 ✅ 支持 ✅ 支持
文章内容获取
公众号搜索
微信扫码登录
Markdown 导出
PDF 导出
图片代理
Webhook 通知 ✅ (企业微信) ✅ (钉钉/飞书/微信)
多数据库 SQLite SQLite + MySQL
AI Agent 接入
Access Key 认证
多公众号管理 ❌ (需多实例)
标签订阅
分页/过滤 基础 高级规则

技术架构对比

┌─────────────────────────────────────────────────────────────────────────┐
│                    wechat-download-api (轻量级)                          │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│   Python + FastAPI                                                      │
│   ├── routes/ (article, rss, search, login)                           │
│   └── utils/ (http_client, proxy_pool, rate_limiter)                   │
│                                                                         │
│   单一 SQLite 数据库                                                    │
│   ├── 反风控: curl_cffi TLS 指纹 + SOCKS5 代理池                       │
│   └── 认证: 扫码登录 → .env 保存 Token/Cookie                          │
│                                                                         │
│   ⚡ 轻量、简单、快速部署                                                │
└─────────────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────────────┐
│                    we-mp-rss / WeRSS (企业级)                          │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│   Python (FastAPI) + Vue 3 (前后端分离)                                │
│                                                                         │
│   ├── core/ (核心逻辑: auth, rss, article, cascade, notice)           │
│   ├── apis/ (REST API: 20+ 端点)                                      │
│   ├── web_ui/ (Vue 3 管理界面)                                         │
│   ├── doc2pdf/ (PDF 导出)                                              │
│   ├── jobs/ (定时任务)                                                  │
│   └── driver/ (浏览器驱动)                                              │
│                                                                         │
│   双数据库: SQLite (默认) / MySQL (生产)                               │
│   ├── 反风控: 多 cascade 账号 + 浏览器指纹                             │
│   ├── 认证: AK-SK Access Key + 扫码登录                                 │
│   └── 通知: 多渠道 Webhook                                              │
│                                                                         │
│   🏢 功能丰富、扩展性强、适合生产环境                                    │
└─────────────────────────────────────────────────────────────────────────┘

反风控对比

方案 wechat-download-api we-mp-rss
TLS 指纹 curl_cffi (Chrome) 浏览器驱动 (Firefox)
代理池 SOCKS5 代理池 (自建) Cascade 多账号轮换
限频 三层限频器 定时任务间隔控制
账号策略 单账号 多 cascade 账号池

部署复杂度

方面 wechat-download-api we-mp-rss
Docker 部署 ⭐ 一行命令 ⭐ 一行命令
配置难度
依赖 多 (Python 3.13+, Node 20+)
资源消耗 低 (~100MB) 高 (~1GB)

适用场景

场景 推荐
个人使用、快速原型 wechat-download-api
多公众号管理、生产环境 we-mp-rss
Markdown/PDF 导出需求 we-mp-rss
AI Agent 集成 we-mp-rss
轻量级 API 服务 wechat-download-api
已有 RSS 阅读器 (Feedly 等) 两者皆可

🏆 总结

项目 优势 劣势
wechat-download-api 轻量、AGPL 开源、反风控强 (SOCKS5) 功能单一、无前端、无多账号
we-mp-rss 功能丰富、前端友好、社区活跃 (2.6k ⭐) 复杂、许可不明确、资源占用高

推荐

  • 简单需求 → wechat-download-api
  • 生产环境 → we-mp-rss