首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >每天发文章要填十几个框,我让电脑自己干了 #WorkBuddy#

每天发文章要填十几个框,我让电脑自己干了 #WorkBuddy#

原创
作者头像
真的就是初学者
发布2026-09-02 12:38:12
发布2026-09-02 12:38:12
230
举报

我 60 岁,退休了,电脑水平一般,属于「会用不会写」那一档。代码是让 AI 写的,我只负责把需求说清楚,然后把跑不通的地方骂回去让它改。

去年开始用 WorkBuddy,用着用着上了瘾,开始在腾讯云开发者社区写文章。写得多了就发现一件很烦的事:写文章一小时,发文章十分钟,这十分钟全是机械劳动。

有多机械?我数过,手动发一篇要点的位置十几处:切到 Markdown 编辑器、填标题、粘正文、一个一个敲标签、填关键词、往下拉到底、关掉那个「自动给关键词加超链接」的开关、最后点确认发布。中间漏一步,发出来就是残次品。

我这人手慢眼也花,连着干几天就烦了。跟 AI 说了一句:这活能不能让机器干。

然后就掉坑里了。这篇是完整踩坑记录,代码都是我本机真跑过的。

先说结论:三条路,我走了第三条

动手之前,AI 给我列了三条路。我挨个试,前两条都有硬伤,最后走通的是第三条。

坐标点击:算出按钮在屏幕上的像素位置,直接点过去。问题是窗口一挪位置就全废。我这台笔记本外接显示器,窗口位置天天变,这条路第一个排除。

截图识别(OCR):先截一张图,再认字找按钮。能扛住窗口移动,但得额外装识别模型,跑起来也慢。更要命的是它只告诉你「这儿有这几个字」,不知道那个开关现在是开着还是关着。

UI Automation(简称 UIA):直接读 Windows 的控件树。这套接口本来是给读屏软件用的——屏幕阅读器要把界面念给视障用户听,就得知道每个控件是什么。既然它能把界面「讲」出来,那它肯定知道每个控件叫什么、在哪、现在什么状态。

关键的发现在这儿:浏览器会把网页内容也映射成控件树。 也就是说,网页上的按钮和输入框,在系统眼里跟桌面软件的按钮是一回事,一样有名字、有类型、有坐标、有状态。既然是网页,那就是浏览器说了算,跟网页用什么框架打包没关系。

三种方案摆一起看:

方案

靠什么定位

窗口挪位置

页面改版

能不能读到状态

UIA 控件树

控件的 Name / 类型 / 坐标

不受影响

按文字找,改版影响小

能,开关的开合、输入框的值都能读

坐标点击

写死的像素坐标

一挪就废

一改就废

不能

OCR 截图识别

截图里认字

不受影响

影响小

不能,还要额外装模型

一句话:能用 UIA 就别用坐标点击。 坐标点击是「我猜那儿有个按钮」,UIA 是「它告诉我它叫什么、在哪、现在什么状态」。

环境准备

就一个库,Python 自带的 pip 装上就行:

代码语言:bash
复制
pip install uiautomation

我本机装的是 2.0.29,Windows 10/11 都能跑,不需要管理员权限。打开你要自动化的页面(我用的是 Edge),保持窗口可见,别最小化——UIA 要拿真实控件,最小化的窗口控件是不渲染的。

第一步:先把窗口抓住

所有脚本开头都是同一个动作:遍历桌面根控件,按窗口标题找到目标窗口。

代码语言:python
复制
import uiautomation as auto

def find_edge():
    for w in auto.GetRootControl().GetChildren():
        try:
            nm = w.Name or ''
            if ('写文章' in nm or '编辑文章' in nm) and 'Edge' in nm:
                return w
        except Exception:
            pass
    return None

win = find_edge()
win.SetActive()   # 提到前台

注意 'Edge' in nm:Edge 的窗口标题末尾会带「- Microsoft Edge」,用它把 Edge 和其他浏览器区分开。找到窗口后一定要 SetActive(),否则后面的点击可能落在别的窗口上。

第二步:探测控件(这里有个大坑)

抓到窗口,按理说该遍历控件树找按钮了。我一开始就是这么干的,然后撞墙:

这个页面的控件树太大,WalkControl 遍历会卡死或者超时,EditControl(foundIndex=i) 按序号取也很不稳定,同一个输入框今天排第 3 明天排第 7。页面上那些按钮还经常被包在 GroupControl 里,ButtonControl(Name='确认发布') 直接搜搜不到。

我卡了半天,最后换个思路:不去遍历树,改成拿坐标反查控件。

代码语言:python
复制
spots = [("发布按钮区", 1638, 110), ("标题框中心", 960, 225), ("预览区", 1300, 400)]
for label, x, y in spots:
    c = auto.ControlFromPoint(x, y)
    if c:
        print(f"{label} -> {c.ControlTypeName} {(c.Name or '')[:40]!r}")

再配合一个粗网格(横向 150 像素、纵向 80 像素扫一遍),把每格是什么类型打出来,一屏就把页面结构摸清了:

代码语言:python
复制
for y in range(120, 1000, 80):
    row = []
    for x in range(150, 1850, 150):
        c = auto.ControlFromPoint(x, y)
        mark = {'EditControl': 'E', 'ButtonControl': 'B',
                'DocumentControl': 'D', 'TextControl': 'T'}.get(
                c.ControlTypeName if c else '', '.')
        row.append(f" {mark}  ")
    print(f"y={y:4d} |" + "".join(row))

E 是输入框、B 是按钮、D 是正文区、T 是文字。跑一遍,哪块是标题框、哪块是正文、标签框在哪个角落,全出来了。这一步是整件事的地基,别省。

(此处配图:网格探测脚本的输出截图,能看出页面控件的分布)

第三步:填标题,写完必须回读

定位到标题框(EditControl),先试 SetValue,失败再退回 SendKeys 打字:

代码语言:python
复制
try:
    box.GetValuePattern().SetValue(TITLE)
    print("SetValue 写入")
except Exception as e:
    box.Click(simulateMove=False)
    box.SendKeys(TITLE)
    print("SendKeys 兜底")

坑在这儿:写完之后,控件自己的 Name 很可能还是空的,你从 UIA 属性读不出刚写进去的字。 所以必须回读校验:

代码语言:python
复制
box2 = <重新用坐标定位标题框>
cur = (box2.Name or '').strip()
print("回读:", repr(cur[:60]), "一致:", cur == TITLE)

这一步救过我。有次标题里带全角引号,粘进去变成乱码,就是回读对不上才发现的。凡是写进去的东西,都要读回来对一遍,别信「写入成功」这四个字。

第四步:填标签,只点精确匹配的

标签是最容易出错的地方。社区标签框是输入后弹下拉,下拉里可能有一堆长得像的选项。我给自己定的规矩是:没有完全一致的一项,就按 Esc 取消,绝不点「看着像」的。

代码语言:python
复制
box.Click(simulateMove=False)
box.SendKeys(tag)
time.sleep(2.2)                 # 等下拉弹出来

items = []                       # 扫输入框下方的选项
for y in range(b.bottom + 5, min(b.bottom + 260, 1040), 12):
    for x in range(b.left, b.right + 30, 30):
        c = auto.ControlFromPoint(x, y)
        nm = (c.Name or '').strip() if c else ''
        if nm and nm not in [i[0] for i in items] and len(nm) < 40:
            items.append((nm, c, x, y))

exact = [i for i in items if i[0] == tag]   # 严格相等
if exact:
    _, _, x, y = exact[0]
    auto.Click(x, y)
else:
    box.SendKeys('{Escape}')     # 宁可不填,也不填错

我第一版偷懒用了「包含就算匹配」,结果「Python」匹配到了「Python 进阶」这种标签,发出去的文章标签全歪。改成 == 之后一次都没错过。

第五步:粘正文,两个坑

正文是 Markdown 纯文本,用剪贴板搬运。别用 pyperclip 之类的库,ctypes 直接调 Windows API 更省事,也不怕没权限装包:

代码语言:python
复制
import ctypes, time
CF_UNICODETEXT = 13
GMEM_MOVEABLE = 0x0002

def set_clipboard(text):
    k, u = ctypes.windll.kernel32, ctypes.windll.user32
    for _ in range(5):
        if u.OpenClipboard(0):
            break
        time.sleep(0.2)
    u.EmptyClipboard()
    h = k.GlobalAlloc(GMEM_MOVEABLE, (len(text) + 1) * 2)
    ptr = k.GlobalLock(h)
    (ctypes.c_wchar * (len(text) + 1)).from_address(ptr).value = text
    k.GlobalUnlock(h)
    u.SetClipboardData(CF_UNICODETEXT, h)
    u.CloseClipboard()

OpenClipboard 我加了 5 次重试,因为剪贴板是全局资源,被别的程序占着就会失败。

坑一:粘贴位置不确定。 编辑器分左右两栏(源码区、预览区),点错栏就粘到空气里。我的办法是准备几个候选坐标,挨个试,粘完读页面字数判断成没成功:

代码语言:python
复制
for (x, y) in [(500, 500), (400, 420), (600, 600), (300, 350)]:
    set_clipboard(body)
    auto.Click(x, y); time.sleep(1)
    auto.SendKeys('{Ctrl}a'); time.sleep(0.3)
    auto.SendKeys('{Ctrl}v'); time.sleep(3.5)
    wc = get_wordcount(page_text(win))     # 从页面文本解析「字数: N」
    if wc and wc > 5000:
        print("正文已写入"); break
    print("未写入,换下一个位置")

坑二:这个坑跟股票软件有关,挺离谱的。 我电脑上装着同花顺,它在后台实时监控剪贴板——你一复制,它就弹个「股票复制识别」的窗口抢焦点,粘贴动作当场被打断。我头两回粘贴失败,查了半天才反应过来是这个东西在捣乱。

解决办法有两个:一是自动化跑之前先把同花顺退出;二是去同花顺设置里关掉「复制识别」。如果你也在跑自动化,先检查一遍电脑上有没有这类监控剪贴板的软件(一些翻译软件、截图工具也会干这事)。

第六步:滚到底、复查开关、点发布

发布按钮在页面很下面,不在可视区里的控件,点了是没反应的。所以要先滚,边滚边看按钮的位置,滚进屏幕再点:

代码语言:python
复制
for i in range(8):
    b = btn.BoundingRectangle
    cy = (b.top + b.bottom) // 2
    if cy <= 1030:          # 1030 是我屏幕的可视下边界
        break
    auto.SetCursorPos(1693, 600)
    auto.WheelDown(wheelTimes=3)
    time.sleep(0.9)
    btn = find_btn(win, '确认发布')    # 滚动后要重新找,句柄会失效

点发布之前,我还会复查一遍那个「自动给关键词加超链接」的开关。这开关默认可能是开的,一开它就把正文里的某些词自动变成广告链接,很招人烦。用 UIA 读它的状态最靠谱:

代码语言:python
复制
sw = win.CheckBoxControl(Name='开启产品关键词自动添加超链接', searchDepth=40)
state = sw.GetTogglePattern().ToggleState      # 0=关 1=开
if state == 1:
    sw.Click(simulateMove=False)

这就是 UIA 比坐标点击强的地方:它能告诉你开关现在是开着还是关着。 坐标点击只能闭着眼点一下,天知道点成了什么。

点完之后别急着走,把页面文本读回来验证结果:

代码语言:python
复制
doc = get_doc(win)
t = doc.GetTextPattern().DocumentRange.GetText(-1)
for kw in ['发布成功', '审核中', '提交成功', '驳回', '格式有误']:
    if kw in t:
        print("页面含:", kw)

注意:不要用控件的 Name 属性判断页面内容,Name 经常是空的老数据。 只有 TextPattern.DocumentRange.GetText(-1) 拿到的才是页面上的真实文本。我在这上面吃过亏,明明内容已经变了,Name 还显示旧的。

发布前,先跑一遍自检脚本

内容发到公网就收不回来了,所以我给自己加了一道岗:发布前用脚本扫一遍正文,查四件事。

代码语言:python
复制
import re
t = open(正文路径, encoding='utf-8').read()

# 1. 字数够不够
print("中文字数:", len(re.findall(r'[\u4e00-\u9fff]', t)))

# 2. 代码块围栏配对、语言标识对不对
fences = re.findall(r'^```(\w*)\s*$', t, re.M)
open_f = [f for i, f in enumerate(fences) if i % 2 == 0]
print("围栏总数:", len(fences), "(应为偶数)")
print("开启围栏:", set(open_f), "里有空/错的就要修")

# 3. 有没有泄露隐私
for pat in [r'[A-Za-z]:\\+Users\\+([^\\\s"\']+)',      # 系统用户名路径
            r'(?<!\d)1[3-9]\d{9}(?!\d)',                # 手机号
            r'[\w.+-]+@[\w-]+\.[\w.]+',                 # 邮箱
            r'eyJ[A-Za-z0-9_\-]{20,}']:                 # JWT
    for m in re.finditer(pat, t):
        print("⚠ 疑似敏感:", m.group()[:8] + "...")

# 4. 结尾格式对不对
last = [l for l in t.splitlines() if l.strip()][-1]
print("结尾行:", repr(last))

第 3 条不是形式主义。我有一次贴代码,差点把本机的访问令牌带出去——那东西等同于账号密码,被人拿到就能花你的积分、看你的会话。从那以后,凡是要发到公网的东西,我一律先脚本扫一遍,不靠肉眼。

顺带一句:代码块里的旧实现也要查。我有回正文改干净了,但代码块里还留着一个「只露前 15 后 8」的旧函数,等于在教读者一个错误的脱敏方法。正则扫不到这种,只能人工把代码块通读一遍。

避坑清单

现象

解法

控件树遍历失效

WalkControl 卡死,foundIndex 序号漂移

改用 ControlFromPoint(x, y) 坐标反查 + 网格扫描

按钮被 Group 包住

按 Name 直接搜搜不到

searchDepth=40 加大深度,或坐标反查

控件不在可视区

点了没反应,也不报错

WheelDown 滚进屏幕,再重新查找控件

写进去读不出来

控件 Name 是空的

写入后重新定位并回读;页面文本必须用 TextPattern

下拉选项选错

「Python」选成了「Python 进阶」

严格 == 精确匹配,匹配不上就 Esc 取消

剪贴板被抢

粘贴无效果

OpenClipboard 加重试;关闭同花顺等剪贴板监控软件

窗口不在前台

点击落到别的窗口

操作前 win.SetActive()

开关状态未知

不知道自动超链接开没开

GetTogglePattern().ToggleState 读,别盲点

敏感信息外泄

令牌、手机号、系统用户名进正文

发布前脚本扫 + 人工通读代码块

收益

说点实在的。

手动发一篇,我数过要点的地方十几处,中间还要反复核对标签有没有选对、开关有没有关、正文粘全了没有。我这手速,一遍下来不快,还容易漏。

拆成脚本之后,每个环节单独跑,跑完立刻打印结果:标题写进去了没有、标签选中了几个、正文字数多少、开关现在是开是关。出错了能一秒定位到是哪一步,不用从头再来一遍。 这个价值比省下来的那几分钟大得多。

更省事的是可复用。填标签、粘正文、点发布这几段,换个文章换个标题直接跑,代码不用改。AI 帮我把这些拆成独立脚本之后,我发一篇基本就是看着它跑完,然后瞄一眼最后的验证输出。

小结

回过头看,这件事真正值的不是那几段代码,是两个判断:

第一,先摸清底细再动手。 整个过程中最花时间的不是写代码,是那一步网格探测——把页面上哪块是标题框、哪块是正文、标签框藏在哪搞清楚。我一开始跳过这步,闷头写定位代码,白折腾了两个多小时。磨刀不误砍柴工,这话在自动化上特别灵。

第二,自动化脚本的价值不在「替你点」,在「告诉你点成了没有」。 填完回读、粘完查字数、点之前读开关状态、点之后验证结果——这些校验代码比点击代码重要得多。没有校验的自动化,等于闭着眼睛开车。

我 60 岁,代码一行不会写。但我会提需求、会验证、会骂人。有 AI 帮我写,有脚本替我查,这活就干得下来了。

如果你也要自动化某个网页,我的建议是:先花十分钟做网格探测,把页面结构摸清楚,再动手写。 磨刀不误砍柴工,我在这上面省了至少两个小时的瞎试。

#WorkBuddy#

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 先说结论:三条路,我走了第三条
  • 环境准备
  • 第一步:先把窗口抓住
  • 第二步:探测控件(这里有个大坑)
  • 第三步:填标题,写完必须回读
  • 第四步:填标签,只点精确匹配的
  • 第五步:粘正文,两个坑
  • 第六步:滚到底、复查开关、点发布
  • 发布前,先跑一遍自检脚本
  • 避坑清单
  • 收益
  • 小结
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档