一键导入
facebook-automation
Facebook automation including posting with privacy settings, interactions, messaging, and navigation workflows
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Facebook automation including posting with privacy settings, interactions, messaging, and navigation workflows
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
| name | facebook-automation |
| description | Facebook automation including posting with privacy settings, interactions, messaging, and navigation workflows |
| allowed-tools | browser_navigate browser_click browser_type browser_fill_form browser_get_snapshot browser_screenshot browser_wait browser_navigate_back browser_get_page_info browser_hover browser_press_key browser_evaluate browser_scroll write_todos browser_extract_posts |
Automation guide for Facebook web interface - posts, privacy settings, interactions, and navigation.
If you received a Success Plan with working_selectors, try those patterns first.
STOP! If you're about to use browser_evaluate to click, DON'T.
This is the #1 cause of agent failures. browser_evaluate for clicking:
If browser_evaluate returns null ONCE:
browser_get_snapshot()browser_click(ref="eXX", force=True) with ref from snapshotAfter ANY click, type, or navigation:
browser_get_snapshot() to get fresh refse78) now points to a DIFFERENT elementExample of what goes wrong:
browser_get_snapshot()
# e78 = button "What's on your mind?"
browser_click(ref="e78", force=True) # Opens dialog
browser_click(ref="e78", force=True) # WRONG! e78 is now "Live video"!
Correct pattern:
browser_get_snapshot()
# e78 = button "What's on your mind?"
browser_click(ref="e78", force=True)
browser_get_snapshot() # GET FRESH REFS!
# Now e78 might be something completely different
# e42 = button "Friends" (privacy button)
browser_click(ref="e42", force=True)
If you clicked to open a dialog but snapshot doesn't show dialog elements:
browser_wait(time=2) - give React time to renderbrowser_get_snapshot() - check againforce=TrueIf same action fails 2 times:
browser_evaluate returns null 2x → Use browser_click with refDO NOT repeat the same failed pattern more than 2 times.
The browser_get_snapshot() tool returns a YAML accessibility tree using Playwright's locator.aria_snapshot() API:
- navigation "Facebook":
- link "Home" [ref=e0]
- button "Search" [ref=e1]
- main:
- button "What's on your mind?" [ref=e15]
- dialog "Create post":
- textbox "What's on your mind?" [ref=e20]
- button "Public" [ref=e21]
- button "Post" [ref=e25]
Format explanation:
role "accessible name" [ref=eN] - Each element with unique refbutton, link, textbox, checkbox, radio, heading, dialog, etc.[checked], [disabled], [expanded], [pressed=true]BEFORE ANY ACTION:
# OBSERVE - Get FRESH snapshot
browser_get_snapshot()
# THINK - MUST explicitly list elements you see:
# I see in this snapshot:
# - button "Close composer dialog" [ref=e31] ← NOT what I want!
# - button "Friends" [ref=e42] ← This is the privacy button (shows current setting)
# - button "Photo/video" [ref=e43] ← NOT privacy
# - button "Post" [ref=e50] ← Submit button
#
# I need to change privacy. The button showing "Friends" is ref=e42.
# ACT - Use the ref from THIS snapshot
browser_click(ref="e42", force=True)
# VERIFY - Get NEW snapshot (previous refs are now stale!)
browser_wait(time=1)
browser_get_snapshot() # REQUIRED after every action
# Now analyze the NEW refs before next action
| Rule | Why |
|---|---|
| Get fresh snapshot after EVERY action | Refs become stale immediately |
Always force=True on clicks | Facebook has invisible overlays |
browser_wait(time=1-2) after actions | React needs time to re-render |
| List elements before clicking | Prevents clicking wrong button |
| Complete ALL dialog steps | Selecting ≠ confirming |
| Verify with snapshot before "done" | Task isn't complete until verified |
| Read button names carefully | "Close composer" ≠ privacy button! |
| Max 2 retries per approach | If it fails twice, try different strategy |
Get ARIA accessibility snapshot with element refs.
browser_get_snapshot()
Output: YAML accessibility tree with [ref=eN] markers on each element.
Click element using ref (preferred) or selector.
# Using ref (RECOMMENDED)
browser_click(ref="e42", force=True)
# Using selector (fallback)
browser_click(selector="button=Post", force=True)
Always use force=True on Facebook.
Type text into an input field.
# Using ref
browser_type(ref="e23", text="Hello world")
# Using selector
browser_type(selector="div[contenteditable='true'][role='textbox']", text="Hello")
Wait for UI updates after actions.
browser_wait(time=1) # 1 second for simple actions
browser_wait(time=2) # 2 seconds for navigation/dialogs
Press keyboard keys.
browser_press_key(key="Enter")
browser_press_key(key="Escape")
Hover to reveal hidden UI (like reactions).
browser_hover(ref="e28")
⚠️ WRONG SELECTORS (Don't Use):
article - Facebook doesn't use semantic HTML articlesdiv[role="article"] - Posts don't have this ARIA rolediv[data-ad-preview="message"] - Only works for ads, not organic posts✅ CORRECT SELECTORS FOR FACEBOOK POSTS (2025):
# Feed container
"div[role='feed']"
# Individual posts
"div[data-testid='feed_story']"
# Post content elements
"div[data-testid='post_message']" # Post text
"a[data-testid='story_author_link']" # Author link
"span[data-testid='story_timestamp']" # Timestamp
"img[data-testid='story_photo']" # Post images
"div[data-testid='feed_loading_indicator']" # Loading spinner (lazy load)
# Use getByRole pattern (most stable against DOM changes)
page.get_by_role("feed") # Feed container
page.get_by_role("article") # Individual posts (if present)
page.get_by_role("link", name="author") # Author links
page.get_by_role("img") # Images
# 1. Get snapshot
browser_get_snapshot()
# 2. Parse snapshot YAML to find post refs
# Posts appear as "generic" or custom roles with accessible names
# 3. Use refs for precise interaction
browser_click(ref="e42", force=True)
# Step 1: Navigate to feed
browser_navigate(url="https://www.facebook.com")
browser_wait(time=2)
# Step 2: Get initial snapshot
browser_get_snapshot()
# Step 3: Scroll to load more posts (lazy loading)
browser_scroll(direction="down", amount=500)
browser_wait(time=2) # Wait for lazy load to complete
# Step 4: Get fresh snapshot with new posts
browser_get_snapshot()
# Step 5: Extract posts using correct selectors
posts = await page.locator("div[data-testid='feed_story']").all()
# Step 6: Parse each post for content
for post in posts:
author = post.locator("a[data-testid='story_author_link']")
text = post.locator("div[data-testid='post_message']")
timestamp = post.locator("span[data-testid='story_timestamp']")
# Check if more posts are loading
loading = await page.locator("div[data-testid='feed_loading_indicator']").count() > 0
# Scroll until no new content appears
prev_count = 0
while True:
await page.locator("div[data-testid='feed_story']").count() == prev_count:
browser_scroll(direction="down", amount=500)
browser_wait(time=2)
current_count = await page.locator("div[data-testid='feed_story']").count()
if current_count == prev_count:
break # No new posts loaded
prev_count = current_count
div[data-testid='feed_story']div[role='feed']browser_get_snapshot()button="Post", text="Like"Priority order (most reliable first):
ref="e42" - From snapshot (BEST)button=Name - Buttons by accessible nameradio=Option - Radio buttons in dialogs[aria-label="Label"] - By aria-labelrole=textbox - For input fields| Element | Selector |
|---|---|
| Open composer | button=What's on your mind? |
| Text input | div[contenteditable='true'][role='textbox'] or role=textbox |
| Post button | button=Post |
| Next button | button=Next |
| Done button | button=Done |
⚠️ CRITICAL: Privacy button has DYNAMIC name
The privacy button's accessible name includes the current setting PLUS dynamic friend names:
"Edit privacy. Sharing with [setting]"ALWAYS use the STABLE PREFIX (never match dynamic suffix):
| Current Privacy | Full Accessible Name | ALWAYS Use This Selector |
|---|---|---|
| Public | "Edit privacy. Sharing with Public" | button="Edit privacy. Sharing with" |
| Friends | "Edit privacy. Sharing with Friends" | button="Edit privacy. Sharing with" |
| Only me | "Edit privacy. Sharing with Only me" | button="Edit privacy. Sharing with" |
| Friends except | "Edit privacy. Sharing with Friends except: John, Jane..." | button="Edit privacy. Sharing with" |
WRONG: ❌ button="Friends except..." (dynamic suffix, will fail)
WRONG: ❌ button="Public" (doesn't match full name)
CORRECT: ✅ button="Edit privacy. Sharing with" (stable prefix)
In privacy dialog (after clicking privacy button):
| Option | Selector |
|---|---|
| Public | radio=Public |
| Friends | radio=Friends |
| Only me | radio=Only me |
| Custom | radio=Custom |
# 1. Navigate to Facebook
browser_navigate(url="https://www.facebook.com")
browser_wait(time=2)
# 2. Get snapshot to find composer
browser_get_snapshot()
# Find button containing "What's on your mind"
# 3. Open composer
browser_click(selector='button=What\'s on your mind', force=True)
browser_wait(time=1)
# 4. Get snapshot - find privacy button (shows current setting)
browser_get_snapshot()
# Look for button starting with "Edit privacy. Sharing with" [ref=eXX]
# 5. Click privacy button using STABLE PREFIX selector
browser_click(selector='button="Edit privacy. Sharing with"', force=True)
browser_wait(time=0.5)
# 6. Select privacy option
browser_click(selector='radio=Only me', force=True)
browser_wait(time=0.5)
# 7. CRITICAL - Confirm with Done
browser_click(selector='button=Done', force=True)
browser_wait(time=0.5)
# 8. Type post content
browser_type(selector="role=textbox", text="Your post content")
browser_wait(time=1)
# 8b. CRITICAL - Refresh snapshot after typing (refs become stale)
browser_get_snapshot()
# 9. Click Next (if shown)
browser_click(selector='button=Next', force=True)
browser_wait(time=2)
# 10. Get snapshot, find Post button
browser_get_snapshot()
# 11. Click Post
browser_click(selector='button=Post', force=True)
browser_wait(time=3)
# 12. VERIFY - Must see post in feed
browser_get_snapshot()
browser_get_snapshot()
# Find Like button ref
browser_click(ref="e28", force=True) # Like button ref
browser_wait(time=0.5)
browser_get_snapshot() # Verify liked
browser_get_snapshot()
# Hover to reveal reactions
browser_hover(ref="e28") # Like button ref
browser_wait(time=1)
browser_get_snapshot()
# Click specific reaction
browser_click(ref="e35", force=True) # Love reaction ref
browser_get_snapshot()
browser_click(ref="e32", force=True) # Comment button
browser_wait(time=0.5)
browser_type(ref="e45", text="Great post!") # Comment input
browser_press_key(key="Enter")
browser_wait(time=1)
browser_get_snapshot() # Verify comment appears
| Problem | What Happened | Fix |
|---|---|---|
| Clicked wrong button | Used stale ref (e78 was "What's on your mind" but became "Live video") | ALWAYS browser_get_snapshot() after any action |
| Closed dialog accidentally | Clicked "Close composer dialog" instead of privacy button | Read button names in snapshot before clicking |
| Got stuck in loop | Clicking same ref repeatedly after page changed | Refs are per-snapshot; get fresh snapshot first |
| Privacy not changed | Selected option but didn't click "Done" | Complete full dialog: select → Done → verify |
| Problem | Solution |
|---|---|
| Ref not found | browser_get_snapshot() to refresh refs |
| Click not working | Add force=True, try browser_hover first |
| Element not visible | browser_wait(time=2), check for overlays |
| Dialog not responding | Close with browser_press_key(key="Escape") |
| Page stale | browser_navigate to refresh |
force=True