# Lark To Wechat Mp

> Use when syncing a Feishu (Lark) document or Wiki page to a WeChat Official Account (微信公众号) draft box. Handles Feishu CDN image migration to WeChat CDN, Markdown-to-WeChat HTML conversion (inline styles, callout blocks), and cover thumbnail creation. Requires WeChat AppID/AppSecret pre-configured.

- Skill: `cookieshaha/lark-to-wechat-mp` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add cookieshaha/lark-to-wechat-mp`
- Raw SKILL.md: https://api.skillmd.com/api/skills/cookieshaha/lark-to-wechat-mp/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- Author: CookiesHaha (https://skillmd.com/u/cookieshaha)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/cookieshaha/lark-to-wechat-mp

---


# lark-to-wechat-mp

Sync a Feishu doc/wiki → WeChat Official Account draft in one workflow. Images are migrated, formatting is preserved.

## Prerequisites

**CRITICAL — 执行前 MUST 先用 Read 工具读取 [`../lark-shared/SKILL.md`](../lark-shared/SKILL.md)**（lark-cli 认证、权限）

1. lark-cli configured with user identity
2. WeChat config at `~/.claude/wechat-mp.json` (see Setup)
3. Current machine IP in WeChat IP Whitelist

## Setup

### 1. WeChat Config File

```bash
cat > ~/.claude/wechat-mp.json << 'EOF'
{
  "app_id": "wx...",
  "app_secret": "YOUR_APP_SECRET"
}
EOF
chmod 600 ~/.claude/wechat-mp.json
```

### 2. IP Whitelist（首次必做，只做一次）

1. 打开 [微信公众平台](https://mp.weixin.qq.com/) → 设置与开发 → 基本配置
2. **IP白名单** → 添加当前机器 IP
3. 获取当前 IP：`curl -s ifconfig.me`

---

## Workflow（每次同步执行以下步骤）

### Step 1 — 读取配置，获取 Access Token

```bash
APP_ID=$(python3 -c "import json; c=json.load(open(os.path.expanduser('~/.claude/wechat-mp.json'))); print(c['app_id'])" 2>/dev/null || \
  python3 -c "import json,os; c=json.load(open(os.path.expanduser('~/.claude/wechat-mp.json'))); print(c['app_id'])")
APP_SECRET=$(python3 -c "import json,os; c=json.load(open(os.path.expanduser('~/.claude/wechat-mp.json'))); print(c['app_secret'])")
TOKEN=$(curl -s "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${APP_ID}&secret=${APP_SECRET}" | python3 -c "import sys,json; print(json.load(sys.stdin)['access_token'])")
echo "Token OK: ${TOKEN:0:20}..."
```

### Step 2 — 拉取飞书文档（Markdown 格式）

```bash
DOC_URL="https://xxx.feishu.cn/wiki/..."
lark-cli docs +fetch --api-version v2 --doc "$DOC_URL" --doc-format markdown > /tmp/lark_doc.json
```

⚠️ **飞书图片 URL 有时效性，必须立即进行 Step 3，不可搁置。**

### Step 3 — 下载飞书图片 & 上传到微信 CDN

对文档中每个 `![](feishu-url)` 图片：

```bash
mkdir -p /tmp/wx_imgs
# 下载
curl -L -o /tmp/wx_imgs/imgN.png "FEISHU_IMAGE_URL" -s
# 上传到微信（返回 wechat_cdn_url）
curl -s -X POST "https://api.weixin.qq.com/cgi-bin/media/uploadimg?access_token=${TOKEN}" \
  -F "media=@/tmp/wx_imgs/imgN.png;type=image/png"
# → {"url":"http://mmbiz.qpic.cn/..."}
```

记录 `{feishu_url: wechat_cdn_url}` 映射表，后续替换用。

### Step 4 — 制作封面缩略图（首张图片）

```bash
# 缩放为 JPEG，控制在 64KB 以内（微信 thumb 上限）
sips -Z 700 /tmp/wx_imgs/img0.png -s format jpeg -s formatOptions 60 --out /tmp/wx_imgs/thumb.jpg
# 检查大小
wc -c /tmp/wx_imgs/thumb.jpg   # 应 < 64000 bytes，否则降低 formatOptions

# 上传为永久素材（type=thumb），获取 media_id
curl -s -X POST "https://api.weixin.qq.com/cgi-bin/material/add_material?access_token=${TOKEN}&type=thumb" \
  -F "media=@/tmp/wx_imgs/thumb.jpg;type=image/jpeg"
# → {"media_id":"xxx","url":"..."}
```

### Step 5 — 转换 HTML & 创建草稿

使用本 skill 目录的 `draft.py` 脚本一键完成转换 + 创建：

```bash
python3 ~/.claude/skills/lark-to-wechat-mp/draft.py \
  --doc "$DOC_URL" \
  --title "文章标题（可选，自动提取）" \
  --author "" \
  --digest "摘要（可选，自动生成）"
# → ✓ Draft created successfully! media_id: xxx
```

**或手动创建**（当需要精细控制 HTML 时）：见文末「手动创建草稿」。

---

## HTML 格式规范（微信兼容）

微信公众号文章必须使用 **inline style**，class 样式会被过滤。

| 元素 | 样式要点 |
|------|---------|
| 全局容器 `<section>` | `font-family:'PingFang SC',...;line-height:1.8;color:#333;` |
| `<h1>` 一级标题 | `font-size:22px;border-bottom:2px solid #07C160;` |
| `<h2>` 二级标题 | `font-size:18px;border-left:4px solid #07C160;padding-left:10px;` |
| `<p>` 正文 | `margin:12px 0;` |
| `<img>` 图片 | `max-width:100%;display:block;margin:20px auto;` + **必须同时设置 `data-src` 和 `src`** |
| `<a>` 链接 | `color:#07C160;` |
| `<code>` 行内代码 | `background:#f0f0f0;padding:2px 6px;font-family:monospace;color:#e83e8c;` |

### Callout 块（飞书高亮块）→ 黄色信息框

```html
<div style="margin:16px 0;padding:14px 18px;background:#fffbe6;border:1px solid #ffe58f;border-radius:6px;color:#333;">
  <p style="margin:0 0 8px;font-weight:700;">🏖️ 标题</p>
  <ul>...</ul>
</div>
```

### 引用块 `>` → 灰色左边框

```html
<blockquote style="margin:16px 0;padding:14px 18px;background:#f5f5f5;border-left:4px solid #07C160;color:#555;">
  引用内容
</blockquote>
```

---

## 草稿 API 结构

```python
payload = {
  "articles": [{
    "title": "标题",
    "author": "",
    "digest": "摘要（120字内）",
    "content": "<section>...HTML...</section>",
    "content_source_url": "飞书原文链接",
    "thumb_media_id": "封面图 media_id（必填）",
    "need_open_comment": 1,
    "only_fans_can_comment": 0
  }]
}
# POST https://api.weixin.qq.com/cgi-bin/draft/add?access_token=TOKEN
```

---

## 常见错误

| 错误 | 原因 | 解决 |
|------|------|------|
| `errcode:40164 invalid ip` | 当前 IP 未加白名单 | 微信公众平台 → IP白名单 → 添加 `curl ifconfig.me` 返回的 IP |
| `errcode:40001 invalid credential` | Token 过期（有效期 7200s）或凭证错误 | 重新获取 Token |
| Thumb upload: `errcode:40009` | 缩略图超过 64KB 或非 JPEG | 降低 `sips formatOptions`，确认文件格式 |
| 图片显示为空 | 微信 `<img>` 需同时有 `src` 和 `data-src` | 两个属性都填 WeChat CDN URL |
| 飞书图片下载失败 | URL 已过期（搁置太久） | 重新 `docs +fetch` 获取新 URL |

---

## 手动创建草稿（精细控制）

当 draft.py 转换效果不满意时，手动在 Python 中构建 HTML 字符串并 POST：

```python
import json, urllib.request
TOKEN = "..."
payload = {"articles": [{"title": "...", "content": "<section>...</section>", "thumb_media_id": "..."}]}
data = json.dumps(payload, ensure_ascii=False).encode("utf-8")
req = urllib.request.Request(
  f"https://api.weixin.qq.com/cgi-bin/draft/add?access_token={TOKEN}",
  data=data, headers={"Content-Type": "application/json; charset=utf-8"}
)
with urllib.request.urlopen(req) as r:
  print(json.loads(r.read()))
```

