自己写一个本机推文删除脚本:从归档解析到可续跑批处理
删推文这件事有两个现成选项,但都不太顺手。托管服务要你把账号权限交出去,官方界面则基本处理不了几万条的量级。
第三条路是自己写脚本,在本地跑。听起来门槛高,拆开看其实只有四块东西:把归档解析成清单、拿到范围合适的凭据、按批次调用删除接口、把进度落到文件里。四块拼起来,一个能断点续跑的删除器就成型了。
下面按这个顺序讲,每块给出需要决定的点,以及在 接口限流 和失败重试上容易踩空的地方。
什么时候值得自己写
先排除掉不需要写的情况。待删数量在几百条以内,官方界面手动点完也就一两个小时,写脚本的时间成本比手动更高。只需要删几条高风险内容,同样手动更快。
真正值得写脚本的是这三种:待删数量过万,手动不现实;对权限极度敏感,不希望任何第三方持有的凭据能登录账号;或者需要在同样的逻辑上反复跑(比如每季度清一次),写一次省很多次。
| 方案 | 权限留在哪 | 适合的量级 | 失败后可续 |
|---|---|---|---|
| 官方界面手动 | 不涉及 | 几百条以内 | 靠自己记 |
| 托管删除服务 | 第三方持有凭据 | 几千到几万条 | 服务侧支持 |
| 本机脚本 | 只在你自己的机器上 | 几万条以上 | 要自己实现 |
第三行最后那格是全部工作量所在。托管服务帮你兜住了断点续传和错误重试,自己写就得把这两件事显式做出来,否则删到一半断网,下一次运行要么重复调用、要么漏掉一批。
数据从哪来
清单来源应该是你自己下载的账号归档,不要去爬取公开时间线。两个原因。爬取拿不到完整的发帖记录,被删过、被保护过的内容经常漏;而且爬取行为本身在你的账号上留下一串异常请求,跟清理隐私的目标正好相反。
归档里有几个文件值得先认清。tweets.js 存的是你自己的推文,每条带 id、时间戳和正文;like.js 是你点过的赞;direct-messages.js 是私信。删除脚本通常只处理第一种,另两种的处理方式见 归档文件结构说明。
归档里的 id 是字符串,长度超过 JavaScript 安全整数范围,解析时不要顺手 Number() 一下。这个坑在删除阶段表现得特别隐蔽:id 被截断后接口返回成功,删掉的却是另一条推文。
脚本的四个组成部分
| 模块 | 职责 | 关键决定 |
|---|---|---|
| 解析器 | 归档 → 待删清单 | 按什么条件过滤;id 保持字符串 |
| 凭据 | 取得调用权限 | 用哪种授权、要哪个范围 |
| 批次执行器 | 逐条调用删除 | 批次大小、节流、超时 |
| 状态文件 | 记录已处理项 | 写入时机与幂等键 |
四块里最容易写少的是第四块。前三个模块跑通不难,第四块决定了脚本能不能在真实网络环境下跑完。
第一步:归档解析成清单
解析这一步的目标不是把全部内容读进来,而是产出一份稳定的删除清单并落盘。清单一旦生成就不再变动,后面任何一次运行都以这份清单为准,这样中途改了过滤条件也不会导致状态混乱。
- 读取
tweets.js,去掉文件开头那段赋值语句,剩下的才是合法 JSON。 - 提取每条推文的 id、创建时间、正文。正文留一份用于人工抽查。
- 按你的条件过滤:早于某年份、命中某关键词、或来自某个时间区间。过滤逻辑写清楚并保留成参数。
- 输出成一份 JSON 或 CSV,id 一律按字符串处理。
清单生成后先抽样核对二三十条,确认过滤条件符合预期。这一步花五分钟,能避免后面删错东西。
第二步:凭据与权限范围
调用删除接口需要授权,而授权的范围决定了脚本的能力上限。这里有个原则值得坚持:只申请真正需要的范围。读权限和写权限在接口层面是分开的,范围对照见 读写权限的区别。
凭据的两个常见处理方式都不理想。一是把长期有效的密钥硬编码进脚本,脚本一旦被同步到网盘或仓库就等于泄露。二是每次运行手动粘贴,跑批量任务时不现实。
相对稳妥的做法是把凭据放在本机的环境变量或系统凭据存储里,脚本只读取不写入,并且给凭据设置到期时间。个人项目里也建议把密钥单独放一个文件、加上忽略规则,具体做法见 本地密钥管理。
第三步:批次执行与限流
删除接口有频率限制,超了会直接被拒。所以批次执行器要处理三件事:批次大小、请求间隔、以及被拒之后的退避。
批次大小不要一次拉满。按接口的窗口限制留出余量,把每分钟的请求数控制在限制的六到七成,剩下的空间留给重试。间隔固定在某个值也行,但更好的做法是读响应头里的剩余额度动态调整,具体字段见 限流与删除的关系。
单条请求要有超时。没有超时的话,一次卡住的连接会让整个批次挂在那里,看不出进展。超时时间设短一些,失败了交给重试逻辑处理,比让批次整体僵住划算。
并发要不要开?小批量可以,大批量建议先串行跑通,再考虑开两到三个并发。并发一上去,限流窗口的剩余额度会消耗得很快,重试逻辑也变得更难推理。
第四步:状态文件与断点续传
状态文件是让脚本可以随时中断、随时继续的关键。每条推文处理完就落盘,而不是等整批结束再写。落盘的内容至少包含四项:
| 字段 | 作用 |
|---|---|
| 推文 id | 唯一标识,用作幂等键 |
| 处理结果 | 成功、已不存在、失败并附原因 |
| 时间戳 | 判断是否是过期状态、排查异常 |
| 尝试次数 | 限制重试上限,避免死循环 |
启动时的逻辑是:读清单,读状态文件,两者的差集就是本次要处理的部分。这样脚本天然可续跑,重复运行不会重复删除,也不会漏掉未处理的条目。
写入时机值得强调一下。按批写入(比如每 50 条写一次)会丢掉批内进度,中断后重复处理几十条。逐条写入慢一些,但对批量任务来说,写入开销远小于接口调用开销,多出来的那点时间可以忽略。
顺带一个实践细节:状态文件用追加写而不是整体覆盖。追加写在断电时最多丢最后一行,整体覆盖则可能把文件写成半截,导致整个状态不可读。
失败处理:哪些该重试
把错误分成三类,处理方式不同:
- 可重试:限流返回、超时、连接重置。加入退避队列,等待后重试,并累加尝试次数。
- 视为已完成:推文已不存在、无权限删除。这类不是失败,标记为终态即可,重试没有意义。
- 需要人工判断:认证失败、范围不足。继续跑只会一直失败,应该立即停下来检查凭据。
区分第二类和第三类最关键。把认证失败当成可重试错误,脚本会在额度耗尽前一直空转;把已不存在的推文当成失败,脚本则会在同一批条目上反复重试。更细的错误分类见 删除失败重试常见问题。
本机运行的安全边界
自己写脚本的收益,很大一部分来自数据不出本机。这个收益有条件:归档文件、生成的清单、状态文件、以及任何日志,都会落在磁盘上。
- 删除日志里不要写完整正文,写 id 和结果就够。日志经常被随手同步到云盘,正文跟着一起走了。
- 归档和清单放在同一个加密卷里,或者干脆跑完手动清掉,参考 加密保存归档。
- 凭据文件加忽略规则,别跟着项目目录一起进版本库。
- 脚本里不要加任何上报或统计的代码。本机脚本的价值就在于没有出网路径,例外只有删除接口本身。
什么时候该放弃自己写
脚本写到能稳定跑完,通常要花掉一个周末。以下情况建议直接用现成方案:待删数量不大;你不打算以后再跑;账号是多人共用的品牌号或企业号,删除操作需要留痕和审批;或者待删内容里有大量需要逐条判断的边界情况,自动化的收益会被人工复核吃掉。
托管方案与官方工具的对照见 2026 年工具横评。如果你只是想知道自己账号里到底有多少敏感内容、值不值得清,那其实不需要写脚本,先做一次体检就能拿到答案。
关于 digital-footprint-health.shop
digital-footprint-health.shop 做的是脚本之前那一步:在写代码或删任何东西之前,先把归档里的个人数据分布摸清楚。工具在本机解析 X 归档,标出手机号、邮箱、地址等敏感内容的位置与年份,输出 0-100 健康评分和待处理清单,分析全程只读、数据不上传。清单确认之后,删除环节可以按条计费执行并支持暂停恢复,也可以照上面这套思路自己写。从 免费体检 开始,导入方式见 下载 X 数据归档。
常见问题
自己写脚本和用托管服务,删一条的成本差多少?
脚本本身的成本是时间,不按条计费,所以条数越多单条摊得越薄。托管服务按条计价,省下的是开发和维护投入。分界点大致在几千条:低于这个量级,服务更划算;过万条且打算以后再跑,脚本更省。
脚本跑一半断网了会怎样?
取决于状态文件的写入时机。每条处理完就落盘的话,重新运行会从断点继续,既不重复也不遗漏。按批写入则会重跑批内剩下的条目,重复的项目通常会返回已不存在,被归为已完成,不会造成实际破坏。
并发跑是不是能快很多?
收益比想象中小。删除接口的窗口额度是共享的,并发把额度消耗得更快,退避和重试的时序也变得更难推理。大批量任务建议先串行跑通、确保状态写入可靠,再考虑两到三个并发,并且把批次大小相应调小。
归档里的推文 id 为什么要当字符串处理?
推文 id 的数值超过了 JavaScript 能精确表示整数的范围。转成数字后末几位会被抹掉,变成另一个合法的 id。更麻烦的是接口不会报错,它会开心地删掉另一条推文,你在结果里看到的是成功。全程按字符串传递可以完全避开这个问题。
脚本需要申请写权限吗,还是读权限就够?
删除属于写操作,读权限不够。但除了删除,其它环节都不需要写权限。解析归档完全在本地,不碰接口;核对结果也用不到写权限。所以把凭据限制在删除必需的范围,不要因为方便就申请更宽的权限集合。
检查你自己的 X/Twitter 数字足迹
免费本机扫描,你的归档永不离开电脑。
免费开始体检相关阅读
X 接口限流为什么让批量删除变慢:配额机制与排队策略
批量删帖慢,慢的不是网络也不是工具,而是写操作配额的窗口计算方式。理解窗口长度、端点配额和 429 的含义之后,就能把删除从「一次性猛冲」改成「可控排队」,中断也不用从头再来。
在浏览器里解析 200MB 的 X 归档:流式读取、内存与线程安排
不装 Node、不把归档传上服务器,只靠浏览器能不能解析一份 200MB 的 X 归档?可以,但要绕开三个硬限制:主线程阻塞、内存峰值和文件读取方式。本文讲清每个限制的成因和对应的工程做法。
不用写代码:从 tweets.js 里把手机号挑出来
tweets.js 是 X 归档里最核心的文件,10 万条推文全在里面。想快速找出所有含手机号的推文,其实不用学编程。本文讲清原理,再给你两种实操方法。