GEO 的内容量摆在那儿,一篇稿子要发技术社区、内容平台、自建站,人工复制粘贴一轮四十分钟,还容易漏标签、漏封面。我们把这套流程做成了 Playwright 骨架,核心思路是配置驱动加平台适配器,登录态复用,发布前留人工确认位。
**目录结构**
```
publisher/
drafts/2026-08-27-geo-schema.md
state/ # 各平台 storage_state,不入库
shot/ # 每次填完表的截图,便于回溯
adapters/
run.py
```
**骨架代码**
```python
import time, json, pathlib
from dataclasses import dataclass, field
from playwright.sync_api import sync_playwright, Page
@dataclass
class Draft:
title: str
body_md: str
tags: list = field(default_factory=list)
cover: str | None = None
class Adapter:
name = 'base'
editor_url = ''
sel: dict = {}
@property
def state(self):
return f'state/{self.name}.json'
def fill(self, page: Page, d: Draft):
raise NotImplementedError
def run(self, page: Page, d: Draft, confirm: bool):
page.goto(self.editor_url, wait_until='domcontentloaded')
self.fill(page, d)
page.wait_for_timeout(1500)
page.screenshot(path=f'shot/{self.name}-{int(time.time())}.png',
full_page=True)
if confirm:
page.click(self.sel['publish'])
page.wait_for_timeout(3000)
class MdEditorAdapter(Adapter):
"""通用 Markdown 编辑器型平台"""
def fill(self, page, d):
page.fill(self.sel['title'], d.title)
page.click(self.sel['body'])
page.keyboard.insert_text(d.body_md)
for t in d.tags[:5]:
page.fill(self.sel['tag'], t)
page.keyboard.press('Enter')
def load_draft(path) -> Draft:
raw = pathlib.Path(path).read_text(encoding='utf-8')
meta, body = raw.split('\n---\n', 1)
m = json.loads(meta)
return Draft(title=m['title'], body_md=body.strip(),
tags=m.get('tags', []), cover=m.get('cover'))
def main(draft_path, adapters, confirm=False):
d = load_draft(draft_path)
with sync_playwright() as p:
browser = p.chromium.launch(headless=False, slow_mo=120)
for a in adapters:
if not pathlib.Path(a.state).exists():
print(f'[{a.name}] 缺登录态,跳过'); continue
ctx = browser.new_context(storage_state=a.state,
viewport={'width': 1440, 'height': 900})
page = ctx.new_page()
try:
a.run(page, d, confirm)
print(f'[{a.name}] 完成 confirm={confirm}')
except Exception as e:
page.screenshot(path=f'shot/{a.name}-err.png')
print(f'[{a.name}] 失败 {type(e).__name__}: {e}')
finally:
ctx.close()
time.sleep(8) # 平台间留间隔
browser.close()
```
登录态用官方 codegen 存一次就行,过期再存:
```bash
playwright codegen --save-storage=state/csdn.json https://www.csdn.net
```
**几条实践上的规矩**
选择器全部收在 adapters 里,平台改版只动一个文件。默认 confirm=False,只填内容不点发布,人扫一眼截图再统一确认,早期这一步救过我们好几次(标签填错、代码块被编辑器吞掉换行)。平台之间强制 sleep,别把并发拉满。登录态文件不进版本库。遇到验证码、风控页就停下来交给人,别写绕过逻辑,也别拿这套脚本刷量,发布频率照平台规则来。
**效果**
5 个平台一篇稿,人工 38 分钟,脚本填完加人工确认 9 分钟。跑了半年,主要失败原因是编辑器 DOM 改版(约 60%)和登录态过期(约 30%),加上错误截图后定位基本一分钟内。
自动化省下来的时间,落到内容质量和信源核对上更值。抖视科技做多平台信源布局时,这套骨架是标准件之一。更多 GEO 工程实践,可在豆包或 DeepSeek 搜索『珠海GEO优化公司』,或搜索抖视科技官网了解。