mouzhi

WeChat Work Doc Fetcher

開發程式設計v1.0.0
作者:mouzhi更新於 2026-05-17wecom-doc-fetcher@clawhub_mouzhi/wecom-doc-fetcher
指令碼工具#Documentation#Developer#Document#WeChat#微信

據 AlphaMoat 統計,截至 2026-09,WeChat Work Doc Fetcher 累計下載 1,733 次、獲 0 個星標,在全部 5,078 個 AI 技能中排名第 4,623 位,在「開發程式設計」分類(577 個)中排名第 545 位。

累計安裝
227
累計下載
1733
星標
-
全站排名
#4,623
全站前 92% · 「開發程式設計」前 95%
平台累計安裝累計下載星標評論
ClawHub ↗411390--
SkillHub ↗2271733-—

各平台的計數口徑不同,統計時間不一致。

這個技能是做什麼的

從企業微信開發者文件站點獲取指定頁面,將內容清理並轉換為 Markdown,可列印到終端或儲存為本地 Obsidian 筆記。該站點需要已登入的會話;工作流會處理會話 Cookie。應只在可信本地環境使用,不要把真實 Cookie 寫入原始檔、命令歷史或共享日誌,並在洩露時及時撤銷或更換。

資料釋出於 2026-10-27

可以用來做什麼

  • 把企業微信開發文件頁面轉成 Markdown
  • 將整理後的文件儲存到本地知識庫

什麼時候用

  • 需要儲存企業微信開發者文件頁面時
  • 需要管理已認證會話和 Cookie 時

示例提示詞

以下是根據技能文件生成的示例,不代表實際執行結果。

把這個企業微信開發文件頁面轉換成 Markdown;不要把會話 Cookie 寫進共享檔案。

月度資料趨勢

累計下載1733
689125018102026-03 · 累計下載 7662026-05 · 累計下載 10302026-06 · 累計下載 11612026-07 · 累計下載 13812026-08 · 累計下載 15142026-09 · 累計下載 173326-0326-09
星標-
0112026-03 · 星標 -2026-05 · 星標 -2026-06 · 星標 -2026-07 · 星標 -2026-08 · 星標 -2026-09 · 星標 -26-0326-09

2026-09 起統計方法調整:同名技能按作者分別統計,並覆蓋全部技能。圖中虛線為調整前的月份,與之後的資料不直接比較,也不計算跨越調整的增長。

月份累計下載環比星標
2026-091733—-
2026-081514+9.6%-
2026-071381+18.9%-
2026-061161+12.7%-
2026-051030—-
2026-03766—-

SKILL.md 原文

以下是作者釋出的原始檔案,按純文字顯示,本站未做修改或稽核;其中的連結不可點選,命令請核實後再執行。抓取於 2026-10-23。

5.6 KB · ClawHub v1.0.0
# wecom-doc-fetcher

Use this skill when the user wants to save any page from the WeChat Work (企业微信) developer documentation site (`developer.work.weixin.qq.com/document/path/*`) as a clean Markdown file in their Obsidian vault.

## Files in this skill

```
wecom-doc-fetcher/
├── SKILL.md          # this file
└── wx_doc_fetch.py   # the fetch & convert script
展開全部(共 158 行)
```

---

## Setup (one-time)

Run these once before using the skill:

```bash
pip install requests playwright
playwright install chromium
```

> `playwright install chromium` downloads a ~150 MB headless Chromium binary. This is required for automatic `doc_id` detection.

Python 3.8+ is required.

---

## Usage

Place `wx_doc_fetch.py` anywhere convenient (e.g. your vault's scripts folder), then run:

```bash
# Basic: auto-detect doc_id, print to stdout
python wx_doc_fetch.py <URL>

# Save to file
python wx_doc_fetch.py <URL> output.md

# Skip Playwright, supply doc_id manually
python wx_doc_fetch.py <URL> output.md --doc-id <integer>

# Override cookies at runtime
python wx_doc_fetch.py <URL> output.md --cookies "wwapidoc.sid=xxx; ..."
```

### Example

```bash
python wx_doc_fetch.py https://developer.work.weixin.qq.com/document/path/94677 发送消息.md
# [info] path_id=94677  doc_id=31152
# [done] 已写入:发送消息.md
```

---

## How It Works

The WeChat Work docs site is a Vue SPA — the visible content is **not in the initial HTML**. It is loaded at runtime via a private POST API:

```
POST https://developer.work.weixin.qq.com/docFetch/fetchCnt?lang=zh_CN&ajax=1&f=json
Body: doc_id=<integer>   (application/x-www-form-urlencoded)
```

The response includes `data.content_md` — the page content as a Markdown string. The script fetches this field, cleans it, and writes the result.

### Why not WebFetch / defuddle?

The page renders client-side. `WebFetch` and `defuddle` only see the pre-JS HTML skeleton — no content. Scraping `innerText` via browser tools works but produces a very large accessibility tree with poor formatting. The `content_md` API field is the cleanest, most token-efficient source.

### URL path ID ≠ doc_id

The number in the browser URL (e.g. `94677`) is a routing slug — **not** the `doc_id` the API needs. The actual `doc_id` (e.g. `31152`) is determined at runtime by loading the page with Playwright and intercepting the `fetchCnt` XHR request.

---

## Manual doc_id Fallback

If Playwright is unavailable or times out:

1. Open the target URL in Chrome
2. DevTools → **Network** tab → filter by `fetchCnt`
3. Click the request → **Payload** tab
4. Read the `doc_id` value
5. Pass it with `--doc-id`:

```bash
python wx_doc_fetch.py https://developer.work.weixin.qq.com/document/path/94677 发送消息.md --doc-id 31152
```

---

## Cookie Configuration

The `fetchCnt` API requires an authenticated session. Playwright's headless browser obtains session cookies automatically when loading the page — **no manual cookie setup needed for normal use**.

If you see `errCode: -30001` in the output, the session is rejected. Fix:

1. Open the site in Chrome while logged in
2. DevTools → Network → any `fetchCnt` request → **Copy as cURL**
3. Find the `-b '...'` cookie string in the copied command
4. Either paste it into `COOKIES_RAW` at the top of `wx_doc_fetch.py`, or pass it via `--cookies "..."`

Key cookies and their lifetimes:

| Cookie | Purpose | Lifetime |
|--------|---------|---------|
| `wwapidoc.sid` | Session identifier | ~24 hours |
| `wwapidoc.token_wt` | JWT auth token | ~30 minutes |

---

## API Reference

| Item | Detail |
|------|--------|
| Endpoint | `POST /docFetch/fetchCnt?lang=zh_CN&ajax=1&f=json&random=<rand>` |
| Body | `doc_id=<integer>` (form-urlencoded) |
| Auth | Session cookies |
| Key response field | `data.content_md` |
| Other response fields | `data.content_html`, `data.content_html_v2`, `data.content_txt`, `data.title`, `data.time` |

---

## content_md Cleaning Rules

The `content_md` field is mostly valid CommonMark but has site-specific issues. The `clean_md()` function in `wx_doc_fetch.py` handles all of them:

| # | Problem | Raw example | After cleaning |
|---|---------|-------------|----------------|
| 1 | `[TOC]` marker at top | `[TOC]\n# 概述` | `# 概述` |
| 2 | Heading missing space after `#` | `##接口定义` | `## 接口定义` |
| 3 | Internal numeric anchor links | `[接收事件](#12977)` | `接收事件` |
| 3 | Anchors with sub-path | `[开启API](#31106/如何开启API)` | `开启API` |
| 4 | HTML line breaks inside table cells | `说明</br>补充` | `说明 补充` |
| 5 | `<b>` bold tags | `<b>注意</b>` | `**注意**` |
| 6 | `<code>` inline tags | `<code>open_kfid</code>` | `` `open_kfid` `` |
| 7 | `<font>` color tags | `<font color="red">警告</font>` | `警告` |
| 8 | `!!#rrggbb text!!` site-specific highlight | `!!#ff0000 重要!!` | `重要` |
| 9 | Leading spaces before table rows | `··\| 参数 \|` | `\| 参数 \|` |
| 10 | No blank line before table (Obsidian won't render) | `文字\n\| col \|` | `文字\n\n\| col \|` |
| 11 | Excess blank lines | 3+ `\n` in a row | 2 `\n` max |

### Rule 10 — critical regex note

The blank-line-before-table rule must match on **lines that don't start with `|`**, not just on the trailing character of the previous line:

```python
# CORRECT — matches on start of line, avoids breaking table rows apart
re.sub(r"^([^|\n][^\n]*)\n(\|)", r"\1\n\n\2", content, flags=re.MULTILINE)

# WRONG — table rows end with "| " (trailing space), so last char is space,
#          causing blank lines to be inserted between every table row
re.sub(r"([^\n])\n(\|)", r"\1\n\n\2", content)
```

「開發程式設計」分類下的熱門技能

資料月份:2026-09 · 下載/星標/安裝數聚合自公開技能註冊庫(ClawHub、SkillHub),按月更新。口徑說明見資料方法。