1. 项目起因:一条被“自见”暴露的点赞记录
最近Vibe Coding的热度几乎是席卷了所有技术社区,从“用AI写个爬虫”到“用AI产出一个完整App”,大家都在用自然语言指挥AI写代码,人只负责把需求说清楚然后验收结果。我一开始是当个热闹看,直到某个周末的晚上,我刷微博时发现——自己在两年前点赞过的一条创业鸡汤微博,不仅静静躺在我主页的“赞”列表里,还因为我手滑点进那个博主的互动记录,把我的账号暴露在了对方的“最近赞过的人”一栏。
那一刻的尴尬程度,大概等于你在会议室投屏时不小心打开了历史搜索记录。
我立刻手动去取消那个赞,点完发现我主页里的自见还没消失,再往下翻:2418条历史点赞,从大学时代的转发送Kindle,到前几年的数码评测,密密麻麻排在“赞”列表里。如果靠手动一条条点取消,按单条3秒计算,全清完得连续点上两个小时,中间还要不断处理验证码和页面卡顿。
这个项目就这么诞生的:用Vibe Coding的方式,让AI帮我写一个批量隐藏微博自见的工具,把历史点赞全部清掉。整个项目从需求描述到跑完清理,耗时约一个小时。本文会把完整的过程拆开讲清楚,包括Vibe Coding工具的选择、需求描述怎么写才高效、微博点赞接口的原理、踩过的坑,以及这种“AI代写代码”的工作流到底靠谱在哪里。
2. Vibe Coding工具选型:不是选最强大的,而是选能看到我屏幕的
先交代一下我的技术背景,免得后面看得一头雾水。我日常工作是做后端接口开发的,写Python没有问题,但前端、网页自动化、移动端H5调试这些领域属于“知道有这回事,但真要下手就头皮发麻”。微博的点赞列表页面涉及大量的动态渲染、xhr异步请求、cookie鉴权,如果单靠我自己开着开发者工具一点点抠接口,没有两三个小时下不来。而这恰好是Vibe Coding最典型的适用场景——需求边界清晰、AI擅长快速产出可运行脚本、我可以负责验证和兜底。
2.1 为什么选Cline而不是直接用ChatGPT网页版
之前我也尝试过纯粹把问题丢给ChatGPT网页版,让它“帮我写一个批量取消微博点赞的脚本”。但遇到的情况基本都在线复现了:AI会给一份看似完整的代码,实际上接口路径、请求参数、页面结构全是它凭经验猜的,真实环境一跑就崩。原因很简单,ChatGPT网页版看不见我的浏览器,看不见真实的接口返回数据,也没有能力自己运行代码看报错。
这次我用的方案是Cline加DeepSeek的API,安装在VS Code里,原因有三点:
- 它有“读浏览器抓包数据”的能力,只要我在开发者工具里把点赞列表的请求复制成curl命令,贴给Cline,它就能精准解析出接口路径和参数结构,而不是瞎猜。
- 它可以自己执行代码。生成脚本后我直接在VS Code里跑,报错信息会自动回传给AI,形成“写代码-改代码-再跑”的闭环,跟我传统上自己调试的效率差不多,但省掉了手动理解堆栈的功夫。
- 上下文记忆做得比较稳。在同一个会话里处理翻页逻辑、断点续传、限流这些一连串问题时,它不会像网页版那样动不动就“忘记前面在干什么”。
如果不想折腾本地环境,用Cursor或Windsurf也能达到类似效果,核心逻辑是一样的:让AI能看到真实运行环境,而不是凭空生成代码。我个人建议是,不要在纯聊天的网页版里让AI写这种带完整运行链路的脚本,它一次最多给你一个片段,改错三次之后你大概率会放弃。
2.2 AIGC工作流的最短闭环
整个Vibe Coding工作流,说白了就是四步循环:
- 描述需求:把“我要干什么”“我遇到了什么限制”用大白话讲清楚。
- 喂给上下文:把浏览器里的真实请求、真实页面结构截图扔给AI。
- 让AI写并运行:它负责产出代码、跑起来,再把报错告诉我。
- 我验收结果:验证数据是否符合预期,不符合就让AI继续修。
四步循环是快节奏的,关键是你作为人类不需要掌握所有实现细节,但必须有判断“结果对不对”的能力。拿这个项目来说,我不需要自己背微博的接口参数,但我知道“取消赞之后,我主页列表里那条微博应该消失”,这就是验收标准。有了这个标准,AI就能放手发挥。
3. 需求描述是第一生产力:五段式描述法让AI一次读懂
很多人Vibe Coding翻车,不是AI不行,而是需求描述得像“帮我做一个批量隐藏微博自见的项目”这种一句话需求。这种描述的问题在于:漏掉了关键约束,比如用什么语言、登录态从哪来、是否需要断点续传、跑挂了怎么办。AI只能给你一个看起来华丽但完全不能用的模板。
我把完整的需求描述拆成五段,给Cline一次性喂完,它产出的第一版脚本就已经能跑了:
3.1 五段式需求模板
- 背景与目标:我的微博账号有2000多条历史点赞,我想全部批量取消,隐藏我的微博自见。自见的意思是我自己登录后在我的主页“赞”标签页看到的记录,别人看不到。
- 技术边界:用Python脚本,在本地运行,不走模拟点击,优先通过微博m站的接口实现。我先登录网页版微博拿到cookie,后面脚本复用这个cookie。
- 关键入参:我的微博uid和cookie会写在config里。接口参数如果不确定,我提供浏览器开发者工具里的真实请求curl。
- 运行模式:要求脚本支持翻页拉取点赞列表,每拉取一页就对这一页的微博批量取消赞,并打印当前进度。因为点赞太多,要支持中断后从上次位置继续。
- 约束规避:每请求一次之后sleep 0.5到1秒,避免请求频率过高。错误处理要健壮,网络超时直接重试,不要抛异常退出。
这段话我不超过100个字,但该有的信息全都有了。省掉这些约束,AI大概率会给你一个跑起来两分钟就被微博风控的脚本。所以做Vibe Coding项目,你的核心工作是当“需求分析师”,而不是当“打字员”。
3.2 截图和curl才是真正的上下文
光凭文字描述,AI还是无法精确知道接口长什么样。最稳的办法是用浏览器开发者工具,手动触发一次点赞列表的加载和一次取消赞的操作,把对应的网络请求复制为cURL格式,然后贴给Cline。cURL里面包含了完整的URL、请求头、cookie、POST参数,AI看完直接就能解析出代码怎么写,连猜都不用猜。
我这里提一个容易忽略的操作细节:粘贴cURL时最好先删掉里面的浏览器指纹头(比如sec-ch-ua-platform、sec-fetch-dest这些),只保留User-Agent、Cookie、Referer、X-Requested-With这几个关键请求头,不然拿Python的requests库复现时容易踩到“多了一个头导致请求被拒”的坑。
这一步做完之后,Cline帮我自动归纳出的接口结构相当清晰,下一章节我会把这套链路的核心逻辑展开讲,因为理解了它,你就知道为什么这个项目能在1小时内稳稳跑完。
4. 链路与代码实现:挖掘“赞列表—取消赞”的完整请求逻辑
很多人对网页自动化或者接口操作有恐惧感,觉得必须得完全弄懂前后端才知道怎么写。实际上,Vibe Coding的一个极大优势,就是AI可以帮你把一条模糊的链路掰开揉碎成一段段可执行的逻辑。但是,你也不能完全看不懂它在做什么。下面把这条链路的原理讲清楚,你就能像验收代码一样验收AI的产出。
4.1 点赞列表的获取原理
微博的“赞”列表,本质上是一个由uid决定的容器页面。在手机上打开m.weibo.cn,进入自己的主页,点“赞”标签,页面会通过xhr请求拿到一组containerid,这个id编码了你自己的uid和“赞”这个标签。在脚本里,构造这个containerid的规则就是:
container_id = f"230283{uid}_-_赞"然后用这个container_id请求下面的接口:
import requests import time import json from typing import List, Optional class WeiboLikeCleaner: def __init__(self, cookie: str, uid: str): self.session = requests.Session() self.session.headers.update({ "User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148", "Cookie": cookie, "Referer": "https://m.weibo.cn/" }) self.uid = uid self.container_id = f"230283{uid}_-_赞" self.processed_file = "processed_mids.txt" def get_like_page(self, page: int) -> Optional[dict]: """拉取指定页码的点赞列表,返回JSON数据""" url = "https://m.weibo.cn/api/container/getIndex" params = { "type": "1", "containerid": self.container_id, "page": page } resp = self.session.get(url, params=params, timeout=10) if resp.status_code != 200: print(f"第{page}页请求失败:HTTP {resp.status_code}") return None data = resp.json() if data.get("ok") != 1: print(f"第{page}页返回异常:{json.dumps(data, ensure_ascii=False)[:200]}") return None return data你可能注意到了,这里用的是m.weibo.cn的接口,而不是pc端微博。原因是m站的接口返回的是干净的JSON数据,而且不需要额外的加密签名参数,对脚本友好得多。这个选择也是我在贴cURL时,AI从请求的域名推断出来的。Vibe Coding不是让AI拍脑袋选方案,而是让它根据你提供的真实抓包来选择最合理的路径。
4.2 从返回数据中提取微博ID
点赞列表的返回结构是一个层层嵌套的cards数组,每条点赞记录都对应一个微博ID,也就是mid。提取逻辑需要同时兼容两种结构,一种是外层直接带mblog字段的卡片,另一种是嵌套在card_group里的卡片。让AI写这部分时,我特别强调了一句:“解析时不要假设结构是固定的,写成遍历寻找的模式,兼容不同层级”。
def extract_mids_from_page(self, data: dict) -> List[str]: """从返回的页面数据中提取微博mid列表""" mids: List[str] = [] cards = data.get("data", {}).get("cards", []) if not isinstance(cards, list): return mids for card in cards: # 兼容外层直接是mblog结构 mblog = card.get("mblog") if mblog and mblog.get("mid"): mids.append(str(mblog["mid"])) continue # 兼容card_group里嵌套的mblog结构 card_group = card.get("card_group") if isinstance(card_group, list): for sub_card in card_group: sub_mblog = sub_card.get("mblog") if sub_mblog and sub_mblog.get("mid"): mids.append(str(sub_mblog["mid"])) return mids这一层代码没什么技术难度,但对页面的json层级要摸得比较透。Vibe Coding中AI能快速处理这种“脏数据”结构,是因为它能从我的cURL返回样例里自动识别层级关系。如果换成我自己打开JSON看到一屏的嵌套字段,光确认结构就得花不少时间。
4.3 取消赞的操作接口
拿到mid之后,取消赞就简单了。微博m站提供一个操作态接口,直接POST这个微博的id即可:
def cancel_like(self, mid: str) -> bool: """取消对某条微博的赞""" url = "https://m.weibo.cn/api/attitudes/destroy" resp = self.session.post(url, data={"id": mid}, timeout=10) try: data = resp.json() except json.JSONDecodeError: print(f"取消赞 {mid} 响应解析失败,原文:{resp.text[:100]}") return False if data.get("ok") == 1: return True else: print(f"取消赞 {mid} 失败:{json.dumps(data, ensure_ascii=False)[:200]}") return False这里面的核心逻辑是“取消赞”会把这条微博从自身点赞列表中移出,从而让“赞”标签页不再显示它,自见自然被隐藏。这里顺带提醒一句:很多人误以为“隐藏自见”需要进入隐私设置里操作,实际上微博并没有一个官方开关能一键隐藏历史点赞,你能做的只有取消赞这一条路。这也是为什么这个需求只能靠批处理解决。
4.4 主循环:翻页、取消、断点续传
主循环的设计是保证运行稳定性的关键。我让AI实现了这么几个能力:
- 每次拉取一页,间隔1秒;
- 每取消一条赞间隔0.6秒到1秒;
- 记录已经处理过的mid到一个文件里,避免重复请求;
- 如果某一页拉取失败或返回空列表,连续失败3次就自动终止。
断点续传是最有价值的设计。因为2000多条数据跑下来,中途网络波动、cookie过期、电脑休眠都是很正常的事情。如果没有断点续传,从头再跑一次就要多花好几十分钟。实现思路非常朴素,但很实用:
def load_processed(self) -> set: try: with open(self.processed_file, "r", encoding="utf-8") as f: return set(line.strip() for line in f if line.strip()) except FileNotFoundError: return set() def save_processed(self, mid: str) -> None: with open(self.processed_file, "a", encoding="utf-8") as f: f.write(mid + "\n")每次成功取消一条赞,就把mid追加写入文件。重新跑的时候先读这个集合,遇到已经存在的mid就跳过。这种设计让整个脚本变得非常耐操,哪怕跑到一半被我强制中断,捡起来还能继续。
写到这里,你可能会觉得这个项目本质上是一个普通的接口调用脚本,和Vibe Coding有什么关系?其实关系恰恰在于:这些碎片代码并非由我手写,而是由AI根据真实抓包和我的口头约束自动生成的。我的任务仅仅是描述清楚“我要什么”以及“我能接受什么样的代价”,这是Vibe Coding和传统编程最大的分野。
5. 实战踩坑:一小时里的五个拦路鬼
讲道理,如果一切顺利,这个项目甚至用不了20分钟。但真实世界的状况从不会让你好过,我在那一个小时里踩了五个坑,每一个都是典型问题。把它们记下来,能帮你在做类似Vibe项目时少走很多弯路。
5.1 坑一:cookie失效和白屏页面
第一次跑通脚本后,我兴奋地看着它开始一条条取消赞。大约跑了100条左右,日志开始频繁出现“第3页返回异常”。我打开浏览器手动访问微博,发现页面提示需要重新登录,m站的前端session已经过期了。原因是我在抓cookie的时候用的是手机浏览器的无痕模式,那个session的有效期很短,一旦过期,服务端直接返回一个登录跳转的JSON,而不是正常的卡片数据。
解决办法很简单:换成用电脑端网页版微博登录,从开发者工具的Application面板里拷贝完整的cookie字符串,有效期大概能撑一整天,足够跑完2000多条。如果你也遇到cookie经常失效的问题,优先检查是不是用了无痕模式或者小号被风控了。
5.2 坑二:请求频率过高被风控
跑出来的脚本一开始没有加限流,我用requests库连发了几十条请求,结果所有后续请求全部返回“操作过于频繁”。这个风控其实不算严格,但对高频请求很敏感。后来我在请求循环里硬编码了time.sleep(0.8),取消赞接口之间也加了time.sleep(1),直到跑完整批都没有再触发风控。
Vibe Coding这一点特别有意思:AI在写代码时默认不会考虑“平台风控”这种现实约束,所以我必须在需求描述阶段就主动说清楚“请降低请求频率”,否则它生成的代码就像一个想全速踩油门的赛车手,在限速路段必翻车。
5.3 坑三:接口返回结构不是固定的
拉取点赞列表时,我以为所有的卡片都会是同一个结构。跑了十几页后发现,有些页面的cards里嵌套了card_group,而card_group里面才挂真正的mblog字段。如果解析函数只处理了外层结构,就会漏掉一大半微博。AI第一次生成的代码就犯了这个问题,它只处理了最外层。
这种情况特别能体现Vibe Coding的调试优势:我把报错日志和一小段JSON结构截取贴回Cline,告诉它“这种结构下你漏了”,它马上就改成了递归寻找mblog字段的写法,还顺手兼容了mblog为空的边界情况。要是传统手工调试,我还得自己打开JSON看层级,再改代码,再跑,循环很多次。
5.4 坑四:中途中断后的“假恢复”
断点续传功能第一次上线后,我发现它并不完美。因为我是按“页”去拉取数据,如果程序在某一页的中途崩溃,比如这一页拉出了20条微博,但只取消了12条,这时记录文件里只存了那12条。下次恢复时,脚本会重新拉那一页,然后把剩下8条正常取消——逻辑上没问题。但如果你把断点记录设计成了按页跳过,那就麻烦了:中断重跑时如果直接跳过这一页,那8条就是漏网之鱼,永远留在你的点赞列表里。
这个真实的坑让我意识到,Vibe Coding生成的代码你一定要自己抓“业务逻辑漏洞”,AI很难主动感知这种状态不一致的问题。好在我的验收标准足够明确,最后跑完以后专门去翻了一遍“赞”列表的末尾几页,确认没有漏网的,才算放心。
5.5 坑五:微博特殊字符和emoji导致的控制台乱码
最后一个小问题,很多微博正文里带了emoji或者生僻字,Python在Windows终端下打印进度日志时直接UnicodeEncodeError,脚本崩溃。这个坑在开发阶段通常发现不了,要跑到特定条目才会触发。解决办法也简单,设置sys.stdout.reconfigure(encoding="utf-8"),或者干脆日志里不打印微博正文,只打印mid和序号。这些都是小细节,但小细节往往是绊倒新手的最大原因。
6. 实测结果:2418条清理完毕,Vibe Coding的真正体验
最终脚本跑完后,我打开微博手机端,进入我的主页,点开“赞”标签:干干净净,一条不剩。有两条中途漏掉的老微博也在断点续传修复后清理掉了。整个项目从打开VS Code到全部跑完,正好用了一个小时出头,其中真正花在运行脚本上的时间大约40分钟,剩余时间全部在和AI讨论需求边界和调试上述的几个坑。
一些实测数据列在下面供参考:
| 指标 | 数值 |
|---|---|
| 历史点赞总数 | 2418条 |
| 清理完成数 | 2418条 |
| 脚本总运行时长 | 约38分钟 |
| 平均每条耗时 | 约0.94秒 |
| 触发风控次数 | 0次 |
| 断点续传次数 | 2次 |
关于Vibe Coding到底是一种什么体验,我的结论很明确:它不是让程序员失业的魔法,而是把“动手写代码”的成本压缩到了原来的十分之一,转而把“说清楚要什么”的成本提高了。在这个项目里,我并没有写出每一行代码,但我承担了需求描述、验收标准、异常处理思路这些更重要的工作。AI负责快,我负责对。
6.1 Vibe Coding的适用边界
这个项目属于典型的“脚本型Vibe Coding”——目标单一、逻辑线性、接口明确、验收简单。这种场景AI几乎是降维打击。但如果你的项目是一个包含复杂状态管理、多角色权限、复杂数据库设计的应用,建议不要指望一次对话就能搞定。AI可以生成骨架和模块,但整体架构设计、业务建模这些还是得由你来把握。
怎么判断一个项目适不适合Vibe Coding?我自己的经验是看一个问题模型:如果项目能被拆成“输入-处理-输出”的管道型结构,且每一步的边界可以被自然语言描述清楚,那它大概率适合。反之,如果项目里有大量的隐式状态流转和不可逆操作,你最好先在纸上画清楚架构流程图再动手。
6.2 给还想继续折腾的人一些方向
跑批完成之后肯定不会就此打住,还有几个可以继续延展的方向:
- 做成定时任务:把脚本挂到家里的NAS或云函数上,定期检查新增的点赞并清理,保持自见始终是空的。
- 增加筛选能力:只取消某类微博的赞,比如关键词匹配、博主的清洗,而不用一锅清空。
- 加一个观看模式:跑之前打印每个博主的名字和微博摘要,让你能先看看哪些赞真的要留下,哪些只是手滑。
我的建议是第一轮先做“无脑全清”,因为你不需要在功能上追求完美,先把链路跑通。确认稳定之后再加筛选,避免一开始就陷入复杂业务逻辑里,半天写不出一个能跑的东西。
6.3 最后说点心里话
整个项目做完后,我感觉Vibe Coding给我最大的启发其实是:我敢把那些“有点想法但不想花太多时间”的边角需求真正落地了。换作以前,像这种“想清空微博点赞”的念头,我会花三分钟搜索有没有现成工具,发现没有,然后放弃。但现在,我可以花一小时让AI帮我做出来,而且整个过程还挺开心的——因为它不只是把我的想法翻译成代码,还在这个过程中逼着我把需求、边界、验收标准一点点想清楚。
如果你也想试一次Vibe Coding,我的建议是从这种不起眼的小工具开始。挑一个你生活或工作里具体到“如果有一脚本,我就可以怎么怎么样”的需求,按上面的五段式描述法写清楚,选一个能看到上下文的工具,剩下的就交给AI,你来负责验收和踩坑。你会发现,它可能比你想的更靠谱,也可能比你想的更容易翻车,但不管结果如何,你都会收获一个亲手搞定问题的踏实感。
最后分享一个小技巧:跑完批量操作后,记得清理一下浏览器和脚本里留下的登录态和中间文件,避免敏感信息泄露。老话说得好,代码可以随时重写,但微博账号里面存着的,可都是十几年的黑历史。