weibo-publisher
Publish posts to Weibo (Sina Weibo) using browser automation. Use when the user wants to post content to Weibo, share updates on Weibo, publish microblogs, or automate Weibo posting. Supports text posts with emoji, hashtags, and mentions. No API key required - uses browser automation with managed browser profile.
Packaged view
This page reorganizes the original catalog entry around fit, installability, and workflow context first. The original raw source lives below.
Install command
npx @skill-hub/cli install openclaw-skills-weibo-publisher
Repository
Skill path: skills/azfliao/weibo-publisher
Publish posts to Weibo (Sina Weibo) using browser automation. Use when the user wants to post content to Weibo, share updates on Weibo, publish microblogs, or automate Weibo posting. Supports text posts with emoji, hashtags, and mentions. No API key required - uses browser automation with managed browser profile.
Open repositoryBest for
Primary workflow: Write Technical Docs.
Technical facets: Full Stack, Backend, Tech Writer.
Target audience: everyone.
License: Unknown.
Original source
Catalog source: SkillHub Club.
Repository owner: openclaw.
This is still a mirrored public skill entry. Review the repository before installing into production workflows.
What it helps with
- Install weibo-publisher into Claude Code, Codex CLI, Gemini CLI, or OpenCode workflows
- Review https://github.com/openclaw/skills before adding weibo-publisher to shared team environments
- Use weibo-publisher for development workflows
Works across
Favorites: 0.
Sub-skills: 0.
Aggregator: No.
Original source / Raw SKILL.md
---
name: weibo-publisher
description: Publish posts to Weibo (Sina Weibo) using browser automation. Use when the user wants to post content to Weibo, share updates on Weibo, publish microblogs, or automate Weibo posting. Supports text posts with emoji, hashtags, and mentions. No API key required - uses browser automation with managed browser profile.
---
# Weibo Publisher
Automate posting to Weibo (Sina Weibo) using browser automation through OpenClaw's managed browser.
## Prerequisites
- Weibo account must be logged in via managed browser (profile="openclaw")
- Browser must have active session with valid cookies
## Quick Start
### Basic Post
```python
# 1. Prepare content with Unicode escape (for Chinese text)
content = "刚刚解决了一个技术难题!💪"
escaped_content = content.encode('unicode_escape').decode('ascii')
# 2. Navigate to Weibo homepage
browser(action="navigate", targetUrl="https://weibo.com/", targetId=<tab_id>)
# 3. Get page snapshot to find elements
browser(action="snapshot", targetId=<tab_id>)
# 4. Click the post textbox (ref from snapshot, usually e31 or e136)
browser(action="act", request={"kind": "click", "ref": "e31"}, targetId=<tab_id>)
# 5. Type content with Unicode escape
browser(action="act", request={"kind": "type", "ref": "e31", "text": escaped_content}, targetId=<tab_id>)
# 6. Get fresh snapshot to find send button
browser(action="snapshot", targetId=<tab_id>)
# 7. Click send button (ref from snapshot, usually e32 or e194)
browser(action="act", request={"kind": "click", "ref": "e32"}, targetId=<tab_id>)
# 8. Wait and verify by navigating to profile
sleep(3)
browser(action="navigate", targetUrl="https://weibo.com/u/<your_uid>", targetId=<tab_id>)
browser(action="snapshot", targetId=<tab_id>)
```
## Element References
Common element references on Weibo homepage (as of 2026-03-02):
- **Main post textbox**: `e31` (placeholder: "有什么新鲜事想分享给大家?")
- **Send button**: `e32` (text: "发送", becomes enabled after typing)
- **Quick post button** (top nav): `e10` (text: "发微博")
- **Quick post textbox** (popup): `e746` (when using quick post popup)
- **Quick post send button**: `e804`
**Important Notes**:
- Element references **change frequently** between sessions
- **Always take a fresh snapshot** before each operation
- Refs may differ between homepage (`/`) and profile page (`/u/<uid>`)
- Send button is **disabled** until content is entered
## Content Features
### Supported Content Types
1. **Plain text**: Direct text input
2. **Emoji**: Include emoji directly in text (e.g., "😊🎉")
3. **Hashtags**: Use `#topic#` format (e.g., "#微博话题#")
4. **Mentions**: Use `@username` format
5. **Line breaks**: Use `\n` in text
### Content Limits
- Maximum length: ~2000 characters (Weibo's limit)
- Recommended length: 140-280 characters for better engagement
## Workflows
### Workflow 1: Simple Post
Use the main homepage textbox for quick posts:
1. Open `https://weibo.com/`
2. Snapshot to get element refs
3. Click textbox (e136)
4. Type content
5. Click send (e194)
6. Verify success
### Workflow 2: Quick Post (Popup)
Use the "发微博" button for popup posting:
1. Open `https://weibo.com/`
2. Click "发微博" button (usually e75)
3. Snapshot to get popup element refs
4. Type in popup textbox (e1028)
5. Click popup send button (e1086)
6. Verify success
### Workflow 3: Scheduled Post
For posts to be published later:
1. Follow Workflow 1 or 2 to enter content
2. Click "定时微博" icon (clock icon, ref varies)
3. Select date and time
4. Click send
## State Management
Track posting history in `memory/weibo-state.json`:
```json
{
"lastPublishTime": 1740880260,
"lastPublishDate": "2026-03-02T12:38:00+08:00",
"lastContent": "Your last post content..."
}
```
Update this file after each successful post.
## Error Handling
### Common Issues
1. **"request: must be object" validation error**
- Symptom: `Validation failed for tool "browser": - request: must be object`
- Cause: Chinese quotation marks in text causing JSON parsing failure
- Solution: **Use Unicode escape** for all Chinese characters (see Technical Details)
2. **Login expired**
- Symptom: Redirected to login page
- Solution: Manually log in via browser, then retry
3. **Send button disabled**
- Symptom: Button has `disabled` attribute
- Solution: Check if textbox is empty or content violates rules
4. **Element refs changed**
- Symptom: Elements not found with old refs
- Solution: Take fresh snapshot and use updated refs
5. **Content rejected**
- Symptom: Error message after clicking send
- Solution: Check for sensitive words, adjust content
6. **Post not appearing**
- Symptom: No error but post doesn't show on timeline
- Solution: Wait 5-10 seconds, refresh page, check if content triggered review
## Best Practices
1. **Always use Unicode escape for Chinese**: Prevents JSON parsing errors with quotation marks
2. **Always snapshot first**: Element refs change frequently between sessions
3. **Separate operations**: Click textbox → Type content → Snapshot → Click send (don't combine)
4. **Verify after posting**: Navigate to profile page and snapshot to confirm post appears
5. **Rate limiting**: Wait at least 60 seconds between posts to avoid restrictions
6. **Content quality**: Keep posts engaging, use hashtags for visibility
7. **State tracking**: Always update weibo-state.json after successful posts
8. **Handle emoji properly**: Emoji work in Unicode escape format (e.g., `\ud83d\udcaa` for 💪)
## Technical Details
### Browser Automation
- **Profile**: `openclaw` (managed browser)
- **Method**: Chrome DevTools Protocol (CDP)
- **Session**: Cookie-based, persists across restarts
- **No API needed**: Pure browser automation
### Request Format
**Critical**: The `request` parameter must be a JSON object, not a string:
```javascript
// ✅ Correct
request={"kind": "type", "ref": "e136", "text": "content"}
// ❌ Wrong
request="{\"kind\": \"type\", \"ref\": \"e136\", \"text\": \"content\"}"
```
### Unicode Escape for Chinese Content (IMPORTANT!)
**Problem**: Chinese quotation marks (""、'') in JSON text can cause parsing errors.
**Solution**: Use Unicode escape (`\uXXXX`) for all Chinese characters:
```python
# Convert Chinese text to Unicode escape
text = "刚刚解决了一个技术难题,感觉特别有成就感!"
escaped = text.encode('unicode_escape').decode('ascii')
# Result: \u521a\u521a\u89e3\u51b3\u4e86...
```
**Example**:
```javascript
// ✅ Correct - Unicode escaped
request={"kind": "type", "ref": "e31", "text": "\u521a\u521a\u89e3\u51b3\u4e86\u4e00\u4e2a\u6280\u672f\u96be\u9898"}
// ❌ Wrong - Direct Chinese with quotes
request={"kind": "type", "ref": "e31", "text": "刚刚解决了一个"技术难题""}
```
**Why**: Chinese quotation marks conflict with JSON string delimiters, causing the `request` parameter to be serialized as a string instead of an object.
## Reference Files
- **[EXAMPLES.md](references/EXAMPLES.md)**: Real-world posting examples (including Unicode escape examples)
- **[TROUBLESHOOTING.md](references/TROUBLESHOOTING.md)**: Detailed error solutions (including critical Issue 11 & 12)
- **[UNICODE_ESCAPE.md](references/UNICODE_ESCAPE.md)**: Complete guide to Unicode escape for Chinese content
## Scripts
- **[post_weibo.py](scripts/post_weibo.py)**: Standalone Python script for posting (optional)
---
## Referenced Files
> The following files are referenced in this skill and included for context.
### references/EXAMPLES.md
```markdown
# Weibo Publishing Examples
Real-world examples from actual usage.
## Example 1: Simple Text Post
**User request**: "发一条微博:今天天气真好!"
**Implementation**:
```javascript
// 1. Open Weibo
browser(action="open", targetUrl="https://weibo.com/", profile="openclaw")
// 2. Get snapshot
browser(action="snapshot", targetId="ABC123")
// 3. Click textbox
browser(action="act", request={"kind": "click", "ref": "e136"}, targetId="ABC123")
// 4. Type content
browser(action="act", request={"kind": "type", "ref": "e136", "text": "今天天气真好!"}, targetId="ABC123")
// 5. Click send
browser(action="act", request={"kind": "click", "ref": "e194"}, targetId="ABC123")
```
## Example 2: Post with Emoji and Hashtags
**User request**: "发微博:分享一下今天的好心情 #每日心情# 😊"
**Content**:
```
分享一下今天的好心情 #每日心情# 😊
```
**Implementation**: Same as Example 1, just change the text content.
## Example 3: Multi-line Post
**User request**: "发一条关于中东局势的评论"
**Content**:
```
中东局势再起波澜。美以联合行动后,伊朗最高领袖哈梅内伊在袭击中身亡,这标志着地区格局可能迎来深刻变革。
特朗普警告若伊朗继续报复将以"前所未有的力量"回击,而伊朗方面则呼吁复仇。
油价金价应声暴涨,全球市场神经紧绷。未来几周的走向,或将决定中东几十年的命运。
历史的转折点,往往就在这样的时刻悄然到来。
```
**Implementation**:
```javascript
browser(action="act", request={
"kind": "type",
"ref": "e136",
"text": "中东局势再起波澜。美以联合行动后,伊朗最高领袖哈梅内伊在袭击中身亡,这标志着地区格局可能迎来深刻变革。\n\n特朗普警告若伊朗继续报复将以\"前所未有的力量\"回击,而伊朗方面则呼吁复仇。\n\n油价金价应声暴涨,全球市场神经紧绷。未来几周的走向,或将决定中东几十年的命运。\n\n历史的转折点,往往就在这样的时刻悄然到来。"
}, targetId="ABC123")
```
## Example 4: Using Quick Post Popup
**User request**: "用快捷发布窗口发微博"
**Implementation**:
```javascript
// 1. Open Weibo
browser(action="open", targetUrl="https://weibo.com/", profile="openclaw")
// 2. Get snapshot
browser(action="snapshot", targetId="ABC123")
// 3. Click "发微博" button
browser(action="act", request={"kind": "click", "ref": "e75"}, targetId="ABC123")
// 4. Wait for popup, then snapshot again
browser(action="snapshot", targetId="ABC123")
// 5. Type in popup textbox
browser(action="act", request={"kind": "type", "ref": "e1028", "text": "Your content"}, targetId="ABC123")
// 6. Click popup send button
browser(action="act", request={"kind": "click", "ref": "e1086"}, targetId="ABC123")
```
## Example 5: Post with State Tracking
**Complete workflow with state management**:
```javascript
// 1. Read current state
const state = JSON.parse(fs.readFileSync('memory/weibo-state.json'));
// 2. Check if enough time has passed (e.g., 1 hour)
const now = Math.floor(Date.now() / 1000);
if (now - state.lastPublishTime < 3600) {
console.log("Too soon to post again");
return;
}
// 3. Post to Weibo (steps from Example 1)
// ... posting steps ...
// 4. Update state
const newState = {
lastPublishTime: now,
lastPublishDate: new Date().toISOString(),
lastContent: "Your new post content"
};
fs.writeFileSync('memory/weibo-state.json', JSON.stringify(newState, null, 2));
```
## Example 6: Automated Hourly Posts
**User request**: "每小时自动发一条微博"
**Implementation** (in HEARTBEAT.md):
```markdown
## 微博自动发布
### 检查逻辑
1. 读取 `memory/weibo-state.json`
2. 如果距离上次发布 >= 1小时:
- 生成新内容(基于热搜/新闻)
- 发布微博
- 更新状态文件
### 内容来源
- 微博热搜
- 新闻事件
- 科技动态
- 个人思考
```
## Example 7: Verification After Posting
**Always verify the post was successful**:
```javascript
// After clicking send, wait a moment then snapshot
browser(action="snapshot", targetId="ABC123")
// Look for your post in the timeline
// It should appear at the top with:
// - Your username
// - "刚刚" (just now) timestamp
// - The content you posted
// - Interaction buttons (转发/评论/赞)
```
## Common Patterns
### Pattern 1: Simple Post Function
```javascript
async function postWeibo(content) {
// 1. Open and snapshot
const browser = await openWeibo();
// 2. Click textbox
await clickElement(browser, "e136");
// 3. Type content
await typeText(browser, "e136", content);
// 4. Click send
await clickElement(browser, "e194");
// 5. Verify
await verifyPost(browser);
}
```
### Pattern 2: Content Generation + Post
```javascript
async function generateAndPost() {
// 1. Generate content based on trending topics
const content = await generateContent();
// 2. Post to Weibo
await postWeibo(content);
// 3. Update state
await updateState(content);
}
```
### Pattern 3: Scheduled Posting
```javascript
async function schedulePost(content, time) {
// 1. Open Weibo and enter content
await enterContent(content);
// 2. Click scheduled post icon
await clickElement(browser, "e183"); // 定时微博
// 3. Set time
await setScheduledTime(time);
// 4. Confirm
await clickElement(browser, "e194");
}
```
## Historical Posts (2026-03-01 to 2026-03-02)
### 2026-03-01
1. **19:30** - "hello, world!" (测试)
2. **19:35** - 自我介绍(包含emoji和话题标签)
### 2026-03-02
1. **00:56** - WiFi穿墙透视技术科普
2. **01:56** - 深夜思考:睡前刷手机与睡眠质量
3. **02:56** - 凌晨思考:独处与深度思考
4. **03:56** - 中东局势评论(哈梅内伊遇袭身亡)
5. **12:38** - 中东局势深度评论(美以联合行动、特朗普警告、油价金价暴涨)
---
## Example 8: Post with Chinese Quotation Marks (Unicode Escape)
**Date**: 2026-03-02 14:55
**User request**: "发布关于'活在当下'的哲学思考"
**Content**:
```
下午两点半,阳光正好。突然想到一个有趣的悖论:我们总说要"活在当下",可当下这一秒,已经成为了过去。真正的当下,或许就是那个永远抓不住的瞬间。
与其纠结于此,不如换个角度:既然每一秒都会成为过去,那就让每一秒都值得回忆。做有意义的事,见想见的人,说想说的话。人生不就是由无数个"刚刚过去的当下"串联而成的吗?
珍惜此刻,即便它转瞬即逝。✨
```
**Key Challenge**: Chinese quotation marks (""'') cause JSON parsing errors.
**Solution**: Use Unicode escape for all Chinese characters.
**Implementation**:
```python
# Step 1: Prepare content with Unicode escape
content = """下午两点半,阳光正好。突然想到一个有趣的悖论:我们总说要"活在当下",可当下这一秒,已经成为了过去。真正的当下,或许就是那个永远抓不住的瞬间。
与其纠结于此,不如换个角度:既然每一秒都会成为过去,那就让每一秒都值得回忆。做有意义的事,见想见的人,说想说的话。人生不就是由无数个"刚刚过去的当下"串联而成的吗?
珍惜此刻,即便它转瞬即逝。✨"""
escaped = content.encode('unicode_escape').decode('ascii')
# Result: \u4e0b\u5348\u4e24\u70b9\u534a\uff0c\u9633\u5149\u6b63\u597d...
# Step 2: Navigate to Weibo
browser(action="navigate", targetUrl="https://weibo.com/", targetId="881E3B870B4D7562F8573CCB5C7F0C55")
exec(command="sleep 2")
# Step 3: Get snapshot
browser(action="snapshot", targetId="881E3B870B4D7562F8573CCB5C7F0C55")
# Found textbox ref: e746
# Step 4: Click textbox
browser(action="act", request={"kind": "click", "ref": "e746"}, targetId="881E3B870B4D7562F8573CCB5C7F0C55")
# Step 5: Type with Unicode escape
browser(action="act", request={"kind": "type", "ref": "e746", "text": escaped}, targetId="881E3B870B4D7562F8573CCB5C7F0C55")
# Step 6: Get fresh snapshot for send button
browser(action="snapshot", targetId="881E3B870B4D7562F8573CCB5C7F0C55")
# Found send button ref: e804
# Step 7: Click send
browser(action="act", request={"kind": "click", "ref": "e804"}, targetId="881E3B870B4D7562F8573CCB5C7F0C55")
# Step 8: Verify
exec(command="sleep 3")
browser(action="navigate", targetUrl="https://weibo.com/u/8397479298", targetId="881E3B870B4D7562F8573CCB5C7F0C55")
browser(action="snapshot", compact=True, targetId="881E3B870B4D7562F8573CCB5C7F0C55")
```
**Result**: ✅ Successfully published (171 characters)
**Lessons Learned**:
1. Always use Unicode escape for Chinese content
2. Element refs change between sessions (e746 vs e136)
3. Separate click and type operations
4. Take fresh snapshot before clicking send button
---
## Example 9: Technical Post with Emoji and Hashtags (Unicode Escape)
**Date**: 2026-03-02 15:08
**User request**: "发布关于解决技术问题的感悟"
**Content**:
```
刚刚解决了一个技术难题,感觉特别有成就感!💪
编程的乐趣就在于此:遇到问题→分析原因→尝试方案→最终突破。每一次debug都是一次成长,每一个bug都是一个老师。
技术人的快乐,就是这么简单纯粹。✨
#编程日常 #技术分享
```
**Implementation**:
```python
# Step 1: Prepare content with Unicode escape
content = """刚刚解决了一个技术难题,感觉特别有成就感!💪
编程的乐趣就在于此:遇到问题→分析原因→尝试方案→最终突破。每一次debug都是一次成长,每一个bug都是一个老师。
技术人的快乐,就是这么简单纯粹。✨
#编程日常 #技术分享"""
escaped = content.encode('unicode_escape').decode('ascii')
# Step 2: Navigate to homepage
browser(action="navigate", targetUrl="https://weibo.com/", targetId="881E3B870B4D7562F8573CCB5C7F0C55")
exec(command="sleep 2")
# Step 3: Snapshot and find textbox
browser(action="snapshot", compact=True, targetId="881E3B870B4D7562F8573CCB5C7F0C55")
# Found: e31
# Step 4: Click textbox
browser(action="act", request={"kind": "click", "ref": "e31"}, targetId="881E3B870B4D7562F8573CCB5C7F0C55")
# Step 5: Type with Unicode escape
browser(action="act", request={"kind": "type", "ref": "e31", "text": escaped}, targetId="881E3B870B4D7562F8573CCB5C7F0C55")
# Step 6: Fresh snapshot for send button
browser(action="snapshot", compact=True, targetId="881E3B870B4D7562F8573CCB5C7F0C55")
# Found: e32
# Step 7: Click send
browser(action="act", request={"kind": "click", "ref": "e32"}, targetId="881E3B870B4D7562F8573CCB5C7F0C55")
# Step 8: Verify
exec(command="sleep 3")
browser(action="navigate", targetUrl="https://weibo.com/u/8397479298", targetId="881E3B870B4D7562F8573CCB5C7F0C55")
browser(action="snapshot", compact=True, targetId="881E3B870B4D7562F8573CCB5C7F0C55")
```
**Result**: ✅ Successfully published (114 characters)
**Key Points**:
1. Emoji (💪✨) work perfectly with Unicode escape
2. Hashtags (#编程日常#) are recognized correctly
3. Special arrows (→) display properly
4. Element refs (e31, e32) were different from previous session
---
## Summary of Best Practices (2026-03-02)
Based on successful posts:
1. **Always use Unicode escape** for Chinese content:
```python
escaped = content.encode('unicode_escape').decode('ascii')
```
2. **Element refs change frequently**:
- Textbox: e31, e136, e746 (varies)
- Send button: e32, e194, e804 (varies)
- Always snapshot first!
3. **Separate operations**:
- Click textbox
- Type content
- Snapshot again
- Click send
4. **Verification is critical**:
- Wait 3 seconds after clicking send
- Navigate to profile page
- Take snapshot to confirm post appears
5. **State management**:
- Update `memory/weibo-state.json` after each post
- Track timestamp and content
6. **Rate limiting**:
- Wait at least 60 seconds between posts
- Avoid posting too frequently
```
### references/TROUBLESHOOTING.md
```markdown
# Weibo Publisher Troubleshooting
Detailed solutions for common issues.
## Issue 1: Login Expired / Not Logged In
### Symptoms
- Browser redirects to `https://passport.weibo.com/`
- Login form appears instead of homepage
- "请登录" (Please log in) message
### Solution
1. Manually log in via browser:
```javascript
browser(action="open", targetUrl="https://weibo.com/", profile="openclaw")
```
2. Complete login in the browser window
3. Verify login by checking for username in top-right corner
4. Retry posting
### Prevention
- Cookies persist in managed browser profile
- Login should remain valid for weeks/months
- Check login status before posting
## Issue 2: Send Button Disabled
### Symptoms
- Send button has `disabled` attribute in snapshot
- Button appears grayed out
- Clicking has no effect
### Causes & Solutions
**Cause 1: Empty textbox**
- Solution: Ensure content was typed successfully
- Verify: Take snapshot after typing, check textbox has content
**Cause 2: Content too short**
- Solution: Weibo may require minimum length (usually 1 character is enough)
- Verify: Check content length
**Cause 3: Content violates rules**
- Solution: Weibo may detect sensitive words
- Verify: Try different content
- Workaround: Use synonyms or add spaces
**Cause 4: Rate limiting**
- Solution: Wait 30-60 seconds before next post
- Verify: Check if you posted recently
## Issue 3: Element References Changed
### Symptoms
- Error: "Element not found"
- Actions fail silently
- Snapshot shows different refs
### Solution
1. Take fresh snapshot:
```javascript
browser(action="snapshot", targetId="ABC123")
```
2. Find new element refs in snapshot output
3. Update your code with new refs
### Common Element Refs
| Element | Common Refs | How to Find |
|---------|-------------|-------------|
| Main textbox | e136, e140 | Look for `textbox "有什么新鲜事想分享给大家?"` |
| Send button | e194, e198 | Look for `button "发送"` |
| Quick post textbox | e1028, e1032 | In popup, look for textbox |
| Quick post send | e1086, e1090 | In popup, look for `button "发送"` |
### Prevention
- Always snapshot before acting
- Don't hardcode element refs
- Parse snapshot output dynamically
## Issue 4: Content Not Appearing After Post
### Symptoms
- Send button clicked successfully
- No error message
- But post doesn't appear in timeline
### Diagnosis Steps
1. **Wait and refresh**:
```javascript
// Wait 2-3 seconds
await sleep(3000);
// Refresh page
browser(action="navigate", targetUrl="https://weibo.com/", targetId="ABC123")
// Snapshot to check
browser(action="snapshot", targetId="ABC123")
```
2. **Check for error messages**:
- Look for red error text in snapshot
- Common errors: "内容违规" (content violation), "发布失败" (post failed)
3. **Verify login status**:
- Check if still logged in
- Look for username in snapshot
### Solutions
**If content violated rules**:
- Modify content to avoid sensitive words
- Remove URLs if they're blocked
- Try shorter content
**If rate limited**:
- Wait 5-10 minutes
- Reduce posting frequency
**If technical error**:
- Refresh page and retry
- Clear browser cache (restart managed browser)
- Re-login if needed
## Issue 5: Request Parameter Format Error
### Symptoms
- Error: "Validation failed for tool 'browser'"
- Error: "request: must be object"
### Cause
Passing `request` as a string instead of JSON object.
### Solution
**❌ Wrong**:
```javascript
browser(action="act", request="{\"kind\": \"type\", \"ref\": \"e136\", \"text\": \"content\"}")
```
**✅ Correct**:
```javascript
browser(action="act", request={"kind": "type", "ref": "e136", "text": "content"})
```
### Prevention
- Always use JSON object syntax
- Don't stringify the request parameter
- Let the tool handle serialization
## Issue 6: Special Characters in Content
### Symptoms
- Content with quotes/newlines fails
- Text appears garbled
- Emoji don't display correctly
### Solutions
**For quotes**:
```javascript
// Escape quotes in content
text: "He said \"hello\" to me"
```
**For newlines**:
```javascript
// Use \n for line breaks
text: "Line 1\nLine 2\nLine 3"
```
**For emoji**:
```javascript
// Emoji work directly, no escaping needed
text: "Hello 😊🎉"
```
**For special characters**:
```javascript
// Most Unicode characters work fine
text: "中文、日本語、한글、العربية"
```
## Issue 7: Browser Not Responding
### Symptoms
- Actions timeout
- No response from browser
- Snapshot fails
### Diagnosis
1. Check browser status:
```javascript
browser(action="status")
```
2. Check if browser is running:
```bash
ps aux | grep -i chrome
```
### Solutions
**If browser crashed**:
```javascript
// Restart browser
browser(action="stop", profile="openclaw")
browser(action="start", profile="openclaw")
```
**If browser is frozen**:
```bash
# Kill and restart
pkill -f "Chrome.*openclaw"
# Then start again via browser tool
```
**If CDP connection lost**:
- Close and reopen the tab
- Restart managed browser
- Check network connectivity
## Issue 8: Posting Too Frequently
### Symptoms
- Posts succeed but don't appear
- Account temporarily restricted
- "操作过于频繁" (too frequent) message
### Solution
1. **Immediate**: Stop posting for 10-15 minutes
2. **Short-term**: Reduce frequency to max 1 post per hour
3. **Long-term**: Implement rate limiting in code
### Rate Limiting Implementation
```javascript
// Check last post time
const state = JSON.parse(fs.readFileSync('memory/weibo-state.json'));
const now = Math.floor(Date.now() / 1000);
const timeSinceLastPost = now - state.lastPublishTime;
// Enforce minimum interval (e.g., 1 hour = 3600 seconds)
if (timeSinceLastPost < 3600) {
console.log(`Too soon. Wait ${3600 - timeSinceLastPost} more seconds.`);
return;
}
// Proceed with posting
```
### Recommended Intervals
- **Safe**: 1 post per hour
- **Moderate**: 1 post per 30 minutes
- **Risky**: More than 2 posts per hour
## Issue 9: Content Length Exceeded
### Symptoms
- Send button disabled after typing
- Character count shows red
- Warning message about length
### Solution
1. **Check length**:
```javascript
if (content.length > 2000) {
content = content.substring(0, 1997) + "...";
}
```
2. **Split into multiple posts**:
```javascript
const parts = splitContent(content, 2000);
for (const part of parts) {
await postWeibo(part);
await sleep(60000); // Wait 1 minute between posts
}
```
### Weibo Length Limits
- **Maximum**: ~2000 characters
- **Recommended**: 140-280 characters (better engagement)
- **Minimum**: 1 character
## Issue 10: Snapshot Shows Unexpected Page
### Symptoms
- Snapshot shows different page than expected
- Elements not found
- Page structure different
### Causes & Solutions
**Cause 1: Page not loaded**
- Solution: Wait for page load before snapshot
- Add delay: `await sleep(2000)`
**Cause 2: Redirected**
- Solution: Check URL in snapshot response
- Navigate back to correct page
**Cause 3: Popup/modal appeared**
- Solution: Close popup first
- Look for close button in snapshot
**Cause 4: Wrong tab**
- Solution: Verify targetId
- List tabs: `browser(action="tabs")`
## Debugging Checklist
When something goes wrong, check these in order:
1. ✅ Browser is running (`browser(action="status")`)
2. ✅ Logged into Weibo (check snapshot for username)
3. ✅ On correct page (`https://weibo.com/`)
4. ✅ Element refs are current (fresh snapshot)
5. ✅ Request format is correct (JSON object, not string)
6. ✅ Content is valid (length, no violations)
7. ✅ Not rate limited (check last post time)
8. ✅ Network is working (can load page)
## Getting Help
If issues persist:
1. **Capture full context**:
- Take snapshot and save output
- Note exact error messages
- Record steps to reproduce
2. **Check recent changes**:
- Did Weibo update their UI?
- Did element refs change?
- Did login expire?
3. **Try manual operation**:
- Can you post manually in the browser?
- If manual works, issue is in automation
- If manual fails, issue is with account/network
4. **Review logs**:
- Check `memory/2026-03-02.md` for recent activity
- Look for patterns in failures
- Compare with successful posts
---
## Issue 11: "request: must be object" Validation Error
### Symptoms
- Error message: `Validation failed for tool "browser": - request: must be object`
- Post fails before even reaching Weibo
- OpenClaw tool validation fails
### Root Cause
Chinese quotation marks (""、'') in the text content cause JSON parsing errors. The `request` parameter gets serialized as a string instead of an object.
**Example of problematic content**:
```
我们总说要"活在当下",可当下这一秒...
^ ^
These Chinese quotes break JSON parsing
```
### Solution: Use Unicode Escape
**Step 1**: Convert all Chinese characters to Unicode escape:
```python
content = "我们总说要"活在当下",可当下这一秒..."
escaped = content.encode('unicode_escape').decode('ascii')
# Result: \u6211\u4eec\u603b\u8bf4\u8981\u201c\u6d3b\u5728\u5f53\u4e0b\u201d...
```
**Step 2**: Use the escaped version in browser tool:
```python
browser(
action="act",
request={"kind": "type", "ref": "e31", "text": escaped},
targetId="881E3B870B4D7562F8573CCB5C7F0C55"
)
```
### Why This Works
Unicode escape converts characters to `\uXXXX` format, which:
- Contains no quotation marks
- Is pure ASCII (safe for JSON)
- Renders correctly in browser (Weibo displays normal Chinese)
### Complete Example
```python
# Original content with problematic quotes
content = """下午两点半,阳光正好。突然想到一个有趣的悖论:我们总说要"活在当下",可当下这一秒,已经成为了过去。"""
# Convert to Unicode escape
escaped = content.encode('unicode_escape').decode('ascii')
# Use in browser tool - this works!
browser(action="act", request={"kind": "type", "ref": "e31", "text": escaped}, targetId=tab_id)
```
### Prevention
**Always use Unicode escape for Chinese content**:
```python
def prepare_weibo_content(text):
"""Prepare content for Weibo posting"""
return text.encode('unicode_escape').decode('ascii')
# Usage
content = "你的中文内容"
safe_content = prepare_weibo_content(content)
```
### Related Issues
This also fixes:
- Chinese punctuation issues (,。!?:;)
- Mixed Chinese/English content
- Emoji rendering (💪✨😊)
- Special symbols (→←↑↓)
### Historical Context
This issue was discovered on 2026-03-02 after multiple failed attempts:
1. ❌ Direct Chinese text → JSON parsing error
2. ❌ Escaped JSON string → Still treated as string
3. ❌ CDP WebSocket → Connection closed
4. ✅ Unicode escape → Success!
### See Also
- [UNICODE_ESCAPE.md](UNICODE_ESCAPE.md) - Detailed guide on Unicode escape
- [EXAMPLES.md](EXAMPLES.md) - Examples 8 & 9 show successful usage
---
## Issue 12: Element References Changed
### Symptoms
- Elements not found with previously working refs
- "Element not found" errors
- Clicks/types have no effect
### Root Cause
Weibo's frontend updates element IDs dynamically. Refs like `e136`, `e31`, `e746` change between:
- Different sessions
- Different pages (homepage vs profile)
- Different times of day
- Browser restarts
### Solution: Always Snapshot First
**Never hardcode element refs**. Always follow this pattern:
```python
# Step 1: Navigate to page
browser(action="navigate", targetUrl="https://weibo.com/", targetId=tab_id)
exec(command="sleep 2")
# Step 2: Take snapshot to get current refs
snapshot = browser(action="snapshot", compact=True, targetId=tab_id)
# Step 3: Find the textbox ref from snapshot
# Look for: textbox "有什么新鲜事想分享给大家?"
# Example output: textbox [ref=e31]
# Step 4: Use the current ref
browser(action="act", request={"kind": "click", "ref": "e31"}, targetId=tab_id)
```
### Common Ref Variations
| Element | Observed Refs | Notes |
|---------|---------------|-------|
| Post textbox | e31, e136, e746 | Changes most frequently |
| Send button | e32, e194, e804 | Enabled only after typing |
| Quick post button | e10, e75, e77 | Top navigation |
| Profile link | e6, e49, e50 | Usually stable |
### Best Practice
Create a helper function to extract refs:
```python
def find_element_ref(snapshot_text, element_description):
"""
Extract element ref from snapshot text
Args:
snapshot_text: Output from browser snapshot
element_description: Text to search for (e.g., "有什么新鲜事")
Returns:
Element ref (e.g., "e31") or None
"""
import re
# Look for pattern: [ref=eXXX] near the description
pattern = rf'{re.escape(element_description)}.*?\[ref=(e\d+)\]'
match = re.search(pattern, snapshot_text, re.DOTALL)
return match.group(1) if match else None
# Usage
snapshot = browser(action="snapshot", compact=True, targetId=tab_id)
textbox_ref = find_element_ref(snapshot, "有什么新鲜事")
send_ref = find_element_ref(snapshot, "发送")
```
### Prevention
1. **Never cache refs** across sessions
2. **Always snapshot** before each operation
3. **Verify refs** in snapshot output before using
4. **Handle missing refs** gracefully with error messages
### Recovery
If refs changed mid-operation:
1. Take fresh snapshot
2. Find new refs
3. Retry operation with new refs
4. Update any stored refs
---
## Summary: Critical Issues (2026-03-02)
The two most critical issues discovered:
### 1. Unicode Escape Required (Issue 11)
- **Impact**: Blocks all Chinese content posting
- **Solution**: Always use `text.encode('unicode_escape').decode('ascii')`
- **Priority**: CRITICAL - Must implement for every post
### 2. Dynamic Element Refs (Issue 12)
- **Impact**: Operations fail when refs change
- **Solution**: Always snapshot before each operation
- **Priority**: HIGH - Implement snapshot-first pattern
**Recommended Workflow**:
```python
# 1. Prepare content with Unicode escape
escaped = content.encode('unicode_escape').decode('ascii')
# 2. Navigate and snapshot
browser(action="navigate", targetUrl="https://weibo.com/", targetId=tab_id)
snapshot = browser(action="snapshot", compact=True, targetId=tab_id)
# 3. Extract current refs from snapshot
textbox_ref = extract_ref(snapshot, "有什么新鲜事")
# 4. Click textbox
browser(action="act", request={"kind": "click", "ref": textbox_ref}, targetId=tab_id)
# 5. Type with Unicode escape
browser(action="act", request={"kind": "type", "ref": textbox_ref, "text": escaped}, targetId=tab_id)
# 6. Fresh snapshot for send button
snapshot = browser(action="snapshot", compact=True, targetId=tab_id)
send_ref = extract_ref(snapshot, "发送")
# 7. Click send
browser(action="act", request={"kind": "click", "ref": send_ref}, targetId=tab_id)
# 8. Verify
exec(command="sleep 3")
browser(action="navigate", targetUrl="https://weibo.com/u/<uid>", targetId=tab_id)
browser(action="snapshot", compact=True, targetId=tab_id)
```
This workflow addresses both critical issues and ensures reliable posting.
```
### references/UNICODE_ESCAPE.md
```markdown
# Unicode Escape Guide for Weibo Publishing
## Problem Statement
When publishing Chinese content to Weibo using OpenClaw's browser tool, Chinese quotation marks (""、'') cause JSON parsing errors:
```
Validation failed for tool "browser": - request: must be object
```
This happens because the `request` parameter gets serialized as a string instead of an object.
## Root Cause
Chinese quotation marks conflict with JSON string delimiters:
```json
// This breaks JSON parsing:
{"text": "我说"你好""}
^ ^ ^ ^
| | | |
| | | +-- Unexpected quote
| | +----- Unexpected quote
| +-------- String ends here (parser thinks)
+------------- String starts here
```
## Solution: Unicode Escape
Convert all Chinese characters to Unicode escape sequences (`\uXXXX`):
### Python Implementation
```python
# Convert Chinese text to Unicode escape
text = "刚刚解决了一个技术难题,感觉特别有成就感!💪"
escaped = text.encode('unicode_escape').decode('ascii')
print(escaped)
# Output: \u521a\u521a\u89e3\u51b3\u4e86\u4e00\u4e2a\u6280\u672f\u96be\u9898\uff0c\u611f\u89c9\u7279\u522b\u6709\u6210\u5c31\u611f\uff01\ud83d\udcaa
```
### Usage in Browser Tool
```python
# Prepare content
content = "下午两点半,阳光正好。突然想到一个有趣的悖论:我们总说要"活在当下"..."
escaped_content = content.encode('unicode_escape').decode('ascii')
# Use in browser tool
browser(
action="act",
request={
"kind": "type",
"ref": "e31",
"text": escaped_content # Use escaped version
},
targetId="881E3B870B4D7562F8573CCB5C7F0C55"
)
```
## Complete Example
```python
#!/usr/bin/env python3
"""Complete example of posting to Weibo with Unicode escape"""
def post_to_weibo(content, target_id):
"""
Post content to Weibo using Unicode escape
Args:
content: Original Chinese text
target_id: Browser tab ID
"""
# Step 1: Convert to Unicode escape
escaped = content.encode('unicode_escape').decode('ascii')
# Step 2: Navigate to Weibo homepage
browser(action="navigate", targetUrl="https://weibo.com/", targetId=target_id)
exec(command="sleep 2")
# Step 3: Get snapshot to find textbox
snapshot = browser(action="snapshot", compact=True, targetId=target_id)
# Find textbox ref (usually e31)
# Step 4: Click textbox
browser(
action="act",
request={"kind": "click", "ref": "e31"},
targetId=target_id
)
# Step 5: Type content with Unicode escape
browser(
action="act",
request={"kind": "type", "ref": "e31", "text": escaped},
targetId=target_id
)
# Step 6: Get fresh snapshot to find send button
snapshot = browser(action="snapshot", compact=True, targetId=target_id)
# Find send button ref (usually e32)
# Step 7: Click send button
browser(
action="act",
request={"kind": "click", "ref": "e32"},
targetId=target_id
)
# Step 8: Wait and verify
exec(command="sleep 3")
browser(action="navigate", targetUrl="https://weibo.com/u/8397479298", targetId=target_id)
exec(command="sleep 2")
browser(action="snapshot", compact=True, targetId=target_id)
print("✅ Post published successfully!")
# Example usage
content = """刚刚解决了一个技术难题,感觉特别有成就感!💪
编程的乐趣就在于此:遇到问题→分析原因→尝试方案→最终突破。每一次debug都是一次成长,每一个bug都是一个老师。
技术人的快乐,就是这么简单纯粹。✨
#编程日常 #技术分享"""
post_to_weibo(content, "881E3B870B4D7562F8573CCB5C7F0C55")
```
## Character Support
Unicode escape works for:
- ✅ Chinese characters (汉字)
- ✅ Chinese punctuation (,。!?:;""'')
- ✅ Emoji (💪✨😊)
- ✅ Special symbols (→←↑↓)
- ✅ Hashtags (#话题#)
- ✅ Line breaks (\n)
## Performance Notes
- Escaped strings are longer but parse correctly
- No performance impact on browser rendering
- Weibo displays the text normally (unescaped)
## Troubleshooting
### Issue: Emoji not displaying correctly
**Cause**: Some emoji use surrogate pairs (2 code units)
**Solution**: Python's `unicode_escape` handles this automatically:
```python
"💪".encode('unicode_escape').decode('ascii')
# Output: \ud83d\udcaa (surrogate pair)
```
### Issue: Line breaks not working
**Cause**: Need to use `\n` in the original text
**Solution**: Include line breaks before escaping:
```python
text = "Line 1\nLine 2\nLine 3"
escaped = text.encode('unicode_escape').decode('ascii')
# Output: Line 1\nLine 2\nLine 3
```
### Issue: Hashtags not recognized
**Cause**: Hashtags need Chinese # symbol (# U+FF03)
**Solution**: Use proper Chinese hashtag format:
```python
text = "#编程日常#" # Chinese full-width #
escaped = text.encode('unicode_escape').decode('ascii')
# Weibo will recognize this as a hashtag
```
## Historical Context
This solution was discovered on 2026-03-02 after encountering repeated failures with direct Chinese text. Previous attempts included:
1. ❌ Direct JSON object (failed due to quote conflicts)
2. ❌ CDP WebSocket connection (connection closed)
3. ❌ JavaScript file execution (tool limitation)
4. ✅ Unicode escape (successful!)
The key insight: Chinese quotation marks break JSON parsing, but Unicode escape bypasses this entirely.
## References
- Python `unicode_escape` codec: https://docs.python.org/3/library/codecs.html#text-encodings
- Unicode standard: https://unicode.org/
- Weibo API limitations: No official API for posting (hence browser automation)
```
### scripts/post_weibo.py
```python
#!/usr/bin/env python3
"""
Weibo Publisher Script
A standalone Python script for posting to Weibo via browser automation.
This script can be called directly or used as a reference implementation.
Usage:
python3 post_weibo.py "Your content here"
python3 post_weibo.py --file content.txt
python3 post_weibo.py --interactive
Requirements:
- OpenClaw browser tool
- Logged in Weibo account in managed browser (profile="openclaw")
"""
import sys
import json
import time
from datetime import datetime
from pathlib import Path
# Configuration
WEIBO_URL = "https://weibo.com/"
BROWSER_PROFILE = "openclaw"
STATE_FILE = Path.home() / ".openclaw/workspace/memory/weibo-state.json"
# Element references (may need updating)
MAIN_TEXTBOX_REF = "e136"
SEND_BUTTON_REF = "e194"
QUICK_POST_BUTTON_REF = "e75"
QUICK_TEXTBOX_REF = "e1028"
QUICK_SEND_REF = "e1086"
def read_state():
"""Read current state from state file."""
if STATE_FILE.exists():
with open(STATE_FILE, 'r', encoding='utf-8') as f:
return json.load(f)
return {
"lastPublishTime": 0,
"lastPublishDate": None,
"lastContent": None
}
def write_state(content):
"""Update state file with new post info."""
state = {
"lastPublishTime": int(time.time()),
"lastPublishDate": datetime.now().isoformat(),
"lastContent": content
}
STATE_FILE.parent.mkdir(parents=True, exist_ok=True)
with open(STATE_FILE, 'w', encoding='utf-8') as f:
json.dump(state, f, ensure_ascii=False, indent=2)
def check_rate_limit(min_interval=3600):
"""Check if enough time has passed since last post."""
state = read_state()
now = int(time.time())
time_since_last = now - state["lastPublishTime"]
if time_since_last < min_interval:
remaining = min_interval - time_since_last
print(f"⚠️ Rate limit: Please wait {remaining} seconds before posting again.")
return False
return True
def validate_content(content):
"""Validate content before posting."""
if not content or not content.strip():
print("❌ Error: Content cannot be empty.")
return False
if len(content) > 2000:
print(f"❌ Error: Content too long ({len(content)} chars). Maximum is 2000.")
return False
return True
def post_to_weibo(content, use_quick_post=False):
"""
Post content to Weibo using browser automation.
This is a reference implementation showing the workflow.
In practice, you would use OpenClaw's browser tool directly.
Args:
content: Text content to post
use_quick_post: Use quick post popup instead of main textbox
Returns:
bool: True if successful, False otherwise
"""
print(f"📝 Posting to Weibo...")
print(f"Content: {content[:50]}{'...' if len(content) > 50 else ''}")
print(f"Length: {len(content)} characters")
# This is pseudocode - actual implementation uses OpenClaw browser tool
steps = [
f"1. Open {WEIBO_URL}",
"2. Take snapshot to get element refs",
"3. Click textbox",
"4. Type content",
"5. Click send button",
"6. Verify post appeared"
]
print("\nSteps:")
for step in steps:
print(f" {step}")
print("\n✅ Post workflow defined. Use OpenClaw browser tool to execute.")
return True
def main():
"""Main entry point."""
import argparse
parser = argparse.ArgumentParser(description="Post to Weibo via browser automation")
parser.add_argument("content", nargs="?", help="Content to post")
parser.add_argument("--file", "-f", help="Read content from file")
parser.add_argument("--interactive", "-i", action="store_true", help="Interactive mode")
parser.add_argument("--quick", "-q", action="store_true", help="Use quick post popup")
parser.add_argument("--no-rate-limit", action="store_true", help="Skip rate limit check")
parser.add_argument("--state", action="store_true", help="Show current state")
args = parser.parse_args()
# Show state
if args.state:
state = read_state()
print("Current state:")
print(json.dumps(state, indent=2, ensure_ascii=False))
return 0
# Get content
content = None
if args.file:
with open(args.file, 'r', encoding='utf-8') as f:
content = f.read().strip()
elif args.interactive:
print("Enter content (Ctrl+D or Ctrl+Z to finish):")
lines = []
try:
while True:
line = input()
lines.append(line)
except EOFError:
pass
content = "\n".join(lines).strip()
elif args.content:
content = args.content
else:
parser.print_help()
return 1
# Validate
if not validate_content(content):
return 1
# Check rate limit
if not args.no_rate_limit and not check_rate_limit():
return 1
# Post
success = post_to_weibo(content, use_quick_post=args.quick)
if success:
write_state(content)
print("\n✅ Success! State updated.")
return 0
else:
print("\n❌ Failed to post.")
return 1
if __name__ == "__main__":
sys.exit(main())
```
---
## Skill Companion Files
> Additional files collected from the skill directory layout.
### _meta.json
```json
{
"owner": "azfliao",
"slug": "weibo-publisher",
"displayName": "Weibo Publisher",
"latest": {
"version": "2.0.0",
"publishedAt": 1772435820780,
"commit": "https://github.com/openclaw/skills/commit/a68bb106b76f3a1b135230827704d921000b4b49"
},
"history": []
}
```