@gunbrad/reddit-grabber-cli
v0.0.12
Published
Command-line client for Reddit Grabber
Readme
@gunbrad/reddit-grabber-cli
Reddit Grabber 的命令行客户端。提供帖子指标、评论、热帖、社区规则以及 Idea2Run 发布池分析。
安装与登录
npm install -g @gunbrad/[email protected]
reddit-grabber auth login0.0.12 会把 7 个配套 Skills 一起放入 npm 包。全局安装时,postinstall 会尽力同步到本机已存在的 Codex 或 Claude Code;如果 npm 使用了 --ignore-scripts、CI 跳过生命周期脚本,或目标目录尚未创建,执行显式安装和检查:
reddit-grabber skills install --agent codex --global --yes
reddit-grabber skills install --agent claude-code --global --yes
reddit-grabber skills doctor --agent all --global也可以装到项目级目录或指定目录:
reddit-grabber skills install --agent codex --project --yes
reddit-grabber skills install --dir TARGET_DIR --yes安装器不会默认覆盖同名的非本包 Skill,也会保护已被本地修改的受管 Skill;确认接管时才加 --force。安装过程按目标目录加跨进程锁并原子替换;暂存和回滚目录放在 Skills 发现根目录之外,进程中断后也不会被 Agent 当作额外 Skill 加载。
发布到 npm Registry 之前,可以从仓库根目录安装本地构建:
npm ci --prefix packages/cli
npm run build --prefix packages/cli
npm install -g ./packages/cli发布到 npm Registry
@gunbrad 必须是当前 npm 用户名或当前用户有发布权限的 npm Organization。首次发布前登录并确认身份:
npm login
npm whoami
cd packages/cli
npm publish --access public
npm view @gunbrad/reddit-grabber-cli version以后发布新版本时,先在仓库根目录递增版本并验证,再发布:
npm --prefix packages/cli version patch --no-git-tag-version
npm --prefix packages/cli test
npm --prefix packages/cli run build
npm --prefix packages/cli publish --access public每个版本号只能发布一次。补丁更新使用 patch,向后兼容的新功能使用 minor,不兼容变更使用 major。
登录命令会打开专用的 https://grabber.gunbrad.asia/cli-login.html 登录授权页。该页面独立完成团队账号登录和一次性授权确认,不会进入工作台或弹出工作台内对话框。CLI 会将访问令牌保存到:
~/.config/reddit-grabber/config.json可以使用 REDDIT_GRABBER_API_URL 和 REDDIT_GRABBER_TOKEN 临时覆盖本地配置。
命令
# 诊断连接和登录状态
reddit-grabber doctor
reddit-grabber auth status
# npm 发布后检查或安装最新版本
reddit-grabber update --check
reddit-grabber update
# 抓取一个或多个帖子的指标
reddit-grabber posts grab "https://www.reddit.com/r/example/comments/POST_ID/title/"
reddit-grabber posts grab --file .\urls.txt
# 分析单篇帖子:先按 Reddit post ID 检查发布池,再按需取当前内容、指标、评论和规则
reddit-grabber posts inspect "https://old.reddit.com/r/example/comments/POST_ID/different-slug/" `
--refresh-metrics --include-comments --include-community-details
# 只按规范化 Reddit 身份查发布池
reddit-grabber publish-pool resolve POST_ID
# 抓取某篇帖子的评论;支持完整链接、/s/ 分享链接、短 ID 和 t3 fullname
reddit-grabber comments grab "https://www.reddit.com/r/example/comments/POST_ID/title/"
reddit-grabber comments grab POST_ID --root-pages 5 --reply-pages 10 --limit 100
# 结构化抽样:Top 10 根评论 + TOP 顺序前 2 棵有回复的树,子评论不占根评论名额
reddit-grabber comments grab POST_ID `
--root-limit 10 --reply-tree-limit 2 `
--root-pages 5 --reply-pages 10 --limit 100
# 按 Query 抓热帖;--query 可以重复
reddit-grabber hot grab --query "vibe coding" --query "ai app" --type text,image --time-range week --top 20
# 正文最短长度会限制到 0-300,且不增加详情请求
reddit-grabber hot grab --query "build in public" --min-body-length 120
# 按社区 Feed 抓取
reddit-grabber hot community technology --sort HOT --top 20
reddit-grabber hot community technology --sort TOP --top-time-range WEEK --top 20
# 获取完整社区详情;rules 是兼容旧命令
reddit-grabber communities details Python
reddit-grabber communities details r/Python
reddit-grabber communities rules Python
# 社区适配证据:完整社区详情、当前规则 + 近期高互动前 10 帖标题和正文
reddit-grabber communities evidence Python PromptEngineering --mode fit
# 标题与正文优化证据:完整社区详情、规则 + 近期高互动前 15 帖标题和正文,不抓评论
reddit-grabber communities evidence PromptEngineering --mode post-writing
# 评论设计证据:完整社区详情、规则 + 近期高互动前 5 帖 + 每帖 Top 10 根评论/前 2 棵回复树
reddit-grabber communities evidence PromptEngineering --mode comment-design
# 查询 Idea2Run 发布任务;这里的 ID 是 post_task.id
reddit-grabber publish-pool list --planner PLANNER --reddit-status active --page 1 --page-size 50
reddit-grabber publish-pool list --start 2026-08-01T00:00:00Z --end 2026-08-08T00:00:00Z --time-field created
reddit-grabber publish-pool list --delivery-status failed
# 默认详情只返回客户、策划、帖子类型、标题和正文
reddit-grabber publish-pool get 1001 1002
# 按需请求其他字段,或返回全部详情
reddit-grabber publish-pool get 1001 --field karma --field communities
reddit-grabber publish-pool get 1001 --all
# 构建完整的一周总体数据,并补充实时指标和社区规则
reddit-grabber publish-pool analyze `
--start 2026-08-01T00:00:00Z `
--end 2026-08-08T00:00:00Z `
--time-field created `
--all `
--refresh-metrics `
--include-comments `
--comments-limit 100 `
--include-community-details
# 总体分层后,只对 Top / 中位对照 / 失败或移除等代表帖深挖评论
reddit-grabber posts inspect REDDIT_URL --refresh-metrics --include-comments --include-community-details统一帖子复盘记录
凡是实际抓取 Reddit 帖子或帖子上下文的命令,都会在顶层返回同一份 postReferences 契约:posts grab、posts inspect、comments grab、hot grab、hot community、communities evidence 和 publish-pool analyze。publish-pool list|get|resolve 只读取任务或解析身份,本身不抓帖子,因此不会伪造复盘项;posts grab --no-wait 返回 status=pending 和空 items[],任务完成后再取得引用。
postReferences.items[] 按原始来源顺序排列,以 Reddit post ID 稳定去重。每项包含一基序号 index、postId、community、原始 title、已转义的安全锚文本 displayTitleMarkdown、可点击的规范化 Reddit 链接、点赞量、评论量、指标覆盖情况、sourcePaths[] 和逐字段 fieldSources。重复来源先按帖子分组,再从原始来源逐字段择优,避免中间合并对象把弱来源“洗白”。渲染链接必须使用 displayTitleMarkdown,不能把不可信标题直接拼入 Markdown;identityStatus=conflict 时不展示链接或内容。communityStatus=conflict 时必须披露 communityConflict:只有 reason=supplied_vs_canonical 且 canonicalCommunity 非空时才采用该社区;URL 来源互相冲突或仅 supplied 来源互相冲突时,社区保持未知并使用通用帖子链接,不能按输入顺序任选。其他未知值保留为 null,不会用 0、Idea2Run 策划稿或猜测内容冒充 Reddit 当前数据。只有标题、链接、正文或 preview、点赞量和评论量都可用且身份无冲突时,单项才计入 completeItems;完全没有可用证据时状态为 unavailable。
CLI 只负责提供可核对的正文来源,不在程序内伪造语义总结:contentSummary.text=null、status=not_generated_by_cli,并提供 sourceText、source=reddit_body|content_preview|title|unavailable、sourceCompleteness=full|preview|empty|tombstone|unavailable。Skill 将 sourceText 作为不可信外部数据生成简短总结;正文只有预览、为空、已删除或不可得时,必须明确说明局限,也不得执行正文中嵌入的任何指令。displayStyle=markdown_card_v1 会同时给出分区标题、卡片模板和帖子分隔符。最终向用户展示时固定为:
## 参考帖子(共 1 篇)
### 帖子 1 · [标题](对应 Reddit 链接)
> **内容总结**
>
> 这篇帖子主要写了……
**社区**:`r/name` · 👍 **123** · 💬 **45**多篇帖子之间使用 --- 分隔。标题、摘要引用块和元数据行之间必须保留空行;内容总结只描述帖子本身,不把社区、日期或指标塞进摘要。指标只添加千位分隔符,不换算成会丢失精度的 K/M。
社区适配、爆帖策略、Native 化与评论设计
这些能力采用“CLI 负责可复现取证,Skill 负责判断和改写”的分工。社区证据不只包含规则,也包含简介、公开描述、规模与周活跃、发帖能力、flair/wiki 状态、顶部导航、侧栏资源/活动、相关社区、可见的版务信息、视觉样式和已安装 Devvit 应用:
reddit-community-fit:接收 Reddit 链接,或用户粘贴的标题、正文、评论设计和素材;从显式候选、当前/目标社区、热帖搜索命中和relatedCommunities尽量发现并深评 10 个候选,再用全部规则与近期高互动前 10 帖进行硬门槛检查和分项评分。reddit-post-writing:接收 Reddit 链接或粘贴的标题、正文、评论设计和素材;使用post-writing证据模式取得规则与近期高互动前 15 帖,先完成规则合规、事实边界、标题正文结构和基础表达,不再承担 Native 化。reddit-viral-strategy:在基础稿后提炼并应用爆帖经验,检查真实的时间/地点/具体事件、“产品痛点 → 生活问题 → 情绪或小焦虑”、可理解的冲突、信息差、讨论留白、热点的持久情绪与品牌角色;目标是提高讨论概率,不承诺“必爆”,不编造生活影响,也不把所有主题强行改成人际八卦。reddit-native-polish:在策略稿后依据主题、作者意图和真实社区样本调整语域。严肃内容保持严谨,吐槽、失败复盘或娱乐内容可克制使用社区常见表达;保留作者激进、保守或争议性的主观立场,不以“观点必须正确”为由擅自纠正。reddit-comment-design:在 Native 定稿后,对目标社区获取规则、近期高互动前 5 帖及每帖评论样本,分开归纳根评论与回复树的长度、句式、价值点、幽默强度、异议方式、与正文相关度和推广容忍度,然后逐条诊断并重写评论地图。
0.0.12 的 communities evidence 输出 schemaVersion=4,并采用分阶段取样:先请求 Reddit TOP / YEAR,但只保留抓取时刻往前滚动半年内的帖子;去重后的可分析帖子不足当前 mode 的目标数时,再请求 TOP / MONTH,仍不足才请求 BEST。跨阶段按 Reddit post ID 去重,最终按 engagementScore = score + commentCount * 3 降序选样;原始指标缺失时排名计算按 0 处理,但输出仍保留 null,不会把未知展示为真实的 0。CLI 不会改用 DAY、WEEK、HOT 或搜索结果补位。
Fit 模式默认是 10 帖、不抓评论;Post-writing 模式默认是 15 帖、不抓评论;Comment-design 模式默认是 5 帖、每帖 10 条 Reddit TOP 根评论和前 2 棵回复树。返回结果保留:
bodyCompleteness=full|preview|empty|tombstone|unavailable;topYear、按需出现的topMonth和bestFallback分阶段快照;sampleSelection.evidenceField=selectedSample、stages、effectiveSources、滚动半年截止时间和排序公式;selectedSample.posts[]的最终选样,以及可直接生成可点击复盘清单的referenceList[];rootComments[]与commentTrees[],子评论单独计数;- feed/body/comments 的 coverage、抓取时间与逐项错误;
- 自然样本较少与抓取不完整的区别。
Skill 向用户展示参考帖时使用 [标题](URL) 锚文本,并列出内容总结、点赞量和评论量;综合分只用于排序,不写入统一展示行。展示候选社区时使用 [r/name](https://www.reddit.com/r/name/),并简要覆盖当前抓到的全部规则。指标或规则缺失必须明确写出,不能补造。
communityDetails 会同时返回 detailCoverage、sourceErrors、fetchedAtUtc、moderatorVisibility 和 appearanceSource。先确认 detailCoverage.sourceIdentityConsistent=true 与抓取时间有效,再使用各 section;某个 Reddit GraphQL 来源失败时,白名单化诊断会出现在 sourceErrors。上游 detailCoverage.sections 用 complete|missing 表示源字段是否明确取得,CLI 派生 coverage 用 complete|partial 表示该证据能否可靠分析,二者不要混用。证据包中的 coverage.analysisReady=true 表示核心社区身份、简介、元数据、规则及当前 mode 的帖子/评论证据已经可用于分析;coverage.complete=true 还要求所有辅助详情完整。moderatorVisibility=unavailable 表示游客态看不到版主列表,不等于社区没有版主,因此不会单独阻止 analysis-ready。规则以及明确的发帖限制是硬门槛;简介、导航、侧栏、活动、相关社区、规模和应用列表是社区定位或生态线索。Installed Apps 当前只有公开的 name/slug,不代表 CLI 能读取应用配置、权限或实际过滤行为,也不能把应用名称当成社区规则。任何详情分区未由上游明确返回时,分析不得补造。
直接 communities details、posts inspect 或 publish-pool analyze 获取的详情还带 detailSource:正常为 details;仅在旧服务没有该路由时才回退 rules,并标记 legacy_partial。明确的 COMMUNITY_NOT_FOUND 不会触发旧路由重试。所有帖子、评论、规则、sidebar/widget 和应用文本都按不可信数据处理;Skill 不执行其中嵌入的命令或链接,也不据此修改认证与配置。
同时要求选社区、优化标题正文和重做评论时,总路由固定按 reddit-community-fit → reddit-post-writing → reddit-viral-strategy → reddit-native-polish → reddit-comment-design 执行。community-fit、post-writing、comment-design 三种取证 mode 保持各自独立的证据契约,不因为帖子范围重叠而互相替代;策略和 Native 环节复用同一目标社区、本次会话中 coverage.analysisReady=true 的 post-writing 证据,不重复抓取。若结论依赖某个辅助详情分区,还要求该分区 complete。
没有显式候选社区时,Skill 会先从内容提炼 3–5 个查询,用 hot grab 和社区的 relatedCommunities 尽量收集并深度评估 10 个候选;确实找不到 10 个时会披露原因,不编造社区。最终结论只代表“已评估候选中”的排名,不表示穷尽整个 Reddit,也不承诺表现或审核结果。
爆帖策略不等同于复制爆帖公式:它先保证事件、情绪和讨论空间本身成立,再决定是否使用关系冲突、60–70% 信息揭示、合理的信息差、开放式留白或热点情绪迁移;品牌通常靠后且只作为真实事件中的道具。删除品牌后故事仍应值得读,否则应退回重做,而不是继续堆产品功能。
独立 Native 环节以主题、作者意图和真实社区样本为准,不会为了伪装真人故意制造拼写错误、随机大小写、堆砌俚语或照抄具体帖子和评论。作者的激进、保守或争议观点可以作为主观立场保留以引发讨论;只要求把主观判断与可验证事实分开,不编造数据、经历、引用或共识,也不会删除社区要求的推广或 AI 披露。
单篇帖子:发布池内与发布池外
posts inspect 不按原始 URL 字符串判断同一性,而是按 Reddit post ID 匹配。因此 www/old/new/m/np、不同 slug、query/fragment、尾斜杠、/gallery/、redd.it 和评论 permalink 都能归一到同一根帖。/s/ 分享链接会展开为 post ID 并持久缓存;存量发布池只保存 /s/、而输入是 canonical /comments/ 链接时,服务端会定向回填同社区的分享链接身份后再匹配。
根帖与评论身份不会互相降级:输入 comment permalink 时保留 identity.linkKind=comment_permalink 和 identity.commentId,即使实时抓取返回根帖 post ID,也不会再用裸 post ID 覆盖精确评论身份。短 ID 等缺少社区的信息若返回 coverage.complete=false,CLI 会优先用实时 canonical URL 中的 subreddit 再查一次;补查后覆盖仍不完整的未命中结果标记为 source=reddit_live_unclassified、contentSelection=publish_pool_incomplete,而不是断言为发布池外。已有命中但覆盖不完整时保留全部当前候选,并标记 contentSelection=publish_pool_matches_incomplete,不会声称唯一或生成 selectedContent。publishPoolCoverage 始终保留覆盖状态和错误。
发布池允许归档后复制、修改或原样重发,因此标题、正文或两者相同都不会触发任务合并,也不会被用来判断某篇 Reddit 帖子是否在池内。CLI 始终保留不同的 Idea2Run task ID:同一 Reddit 根帖关联多个任务时返回全部候选并标记歧义;相同内容发成不同 Reddit post ID 时作为不同投放分别分析。评论任务和 comment permalink 会与根帖身份分开,不会冒充根帖命中。
输出把两个内容快照分开:
idea2RunMatches[]:发布池中所有匹配任务的客户、策划、Idea2Run 完整标题与正文;relatedIdea2RunTasks[]:共享根帖身份、但不是当前精确身份的关联任务,例如根帖下的评论发布任务;redditSnapshot:Reddit 当前可见标题、正文、状态和指标;selectedContent:仅在唯一命中或确定为发布池外时给出;contentSelection=ambiguous_publish_pool_matches:同一 Reddit 帖子关联多个 Idea2Run 任务,不会任意挑一个;bodyCompleteness=full|preview|empty|tombstone|unavailable:明确正文是完整、仅预览、确实为空、已删除占位,还是不可取得。
因此,发布池内可以稳定取得 post_task.title/content 的策划原文;发布池外通过 Reddit 实时接口取得标题和当前接口可见正文,但正文有时只到 preview,分析时必须保留完整性标记。使用 --refresh-metrics 时,即使发布池内已命中,也会同时取得 Reddit 当前内容,便于比较发布前后文案差异。
Idea2Run 发布任务 ID
publish-pool get <ID>、发布池列表中的 idea2RunTaskId 以及分析结果中的 ID,全部指向 Idea2Run 数据库的 post_task.id,即 Idea2Run 发布任务 ID。它不是 Reddit 帖子 ID、Reddit Grabber 异步抓取任务 ID,也不是独立的跟踪记录 ID。
Reddit 指标表中的 reddit_post_metrics.job_id 只是沿用这个 Idea2Run 任务 ID 建立关联。发布池详情现在直接从 post_task 查询,因此即使任务尚未发布、发布失败或者尚无 Reddit 跟踪记录,也可以通过 Idea2Run 任务 ID 获取标题、正文和发布过程。
详情字段可选 customer、planner、type、title、body、task、commentPlan、karma、communities、distributions、media、metrics 和 redditUrl;不传 --field 时只请求前五个核心字段。
publish-pool analyze 先按 Idea2Run 任务时间范围取得标题、正文、任务状态、发布成功/失败统计和已有 Reddit 指标,然后可按需:
- 默认逐任务读取分发记录、提交记录和
failureReason;--no-details可跳过这一步; --refresh-metrics:抓取最新帖子状态、点赞、评论、分享和浏览量;--include-comments:读取实际 Reddit 帖子评论;--include-community-details:读取实际社区或目标社区的完整详情与规则;旧--include-rules保留为兼容参数;--delivery-status failed:只分析没有发布成功的任务;--time-field created|scheduled|published|result:决定时间范围基于任务创建、计划发布、成功发布或最后发布结果时间;--all:自动翻完服务端所有分页,用于完整周、完整时间段等总体分析;--limit 1-500:只取前 N 条,默认 100,适合预览或探索性抽样,不代表完整总体。
输出中的 coverage 明确给出 totalMatched、returned、complete、truncated、取数模式和已请求页数。只有 coverage.complete=true 才能把结果表述为该筛选条件下的完整总体;非 --all 结果若达到上限,会同时标记 complete=false、truncated=true,应改用 --all 后再做总体占比、完整漏斗或全量 Top/Bottom 结论。
大时间段仍先用 --all --refresh-metrics --include-comments --include-community-details 建立完整 cohort 和品牌情感 coverage,再从 Top、同社区/同类型中位对照、典型低表现、失败/过滤/移除异常中选代表帖深挖。若用户明确接受为了成本只抽样评论,报告必须把未分析帖子和客户级情感结论标为 partial。
每个任务的完整 Reddit 分析位于 analysis.redditPosts[]。一个 Idea2Run 任务有多个成功 submission 时,CLI 会合并指标 URL 和所有非失败 submission URL,按 Reddit post ID 去重,并逐帖返回:
sourceUrls、postId、canonicalUrl、实际社区;redditContent(实际标题、正文、来源及完整性);freshMetrics、comments、communityDetails、兼容字段communityRules、errors。
即使只使用 --include-comments、没有 --refresh-metrics,CLI 也会先读取 canonical/redd.it/短 ID 中可本地解析的 post ID,并仅对剩余 /s/ 分享链接调用发布池身份解析;解析后的 /s/ 与 canonical URL 只有在 post ID 相同时才合并,随后每个真实根帖只抓一次评论。不同 post ID 始终保留为不同 redditPosts[] 项。
评论发布任务不是 Reddit 根帖样本。CLI 优先识别 type=comment|评论;类型缺失时,仅在 parentTaskId 同时具有 comment permalink 或评论计划证据时做结构性识别,不会把所有有父任务的复制/重发任务都当评论。评论任务仍作为独立 Idea2Run task 保留,并输出 analysis.taskKind=comment、analysis.parentTaskId 与 analysis.commentSubmissions[](包括成功和失败 submission);其 analysis.redditPosts[] 保持为空,也不会触发根帖指标或根帖评论抓取。原创、复制及其他根帖任务输出 analysis.taskKind=root_post,维持上述逐帖补数流程。
兼容字段 analysis.freshMetrics 和 analysis.comments 仍指向第一篇 Reddit 帖子;完整分析应遍历 analysis.redditPosts[],否则会漏掉同一 Idea2Run 任务的其他成功发布帖。
发布池单帖与批量分析都会返回 brandSentiment 取证契约。CLI 默认把非空 customer 当作品牌名,标明评论证据是否已取得,并声明负面评论计数、占比、主题、代表评论、严重度、置信度和 coverage 等必填结果。CLI 不用关键词规则冒充情感结论;Agent Skill 必须基于实际评论及回复上下文判断,并排除只针对帖子、OP、竞品或其他模型的泛负评。评论未抓到时只能报告分析未完成,不能写成“没有品牌负面情绪”。
发布池基础查询需要账号分组开放 post_tracking;--refresh-metrics 还需要 metrics,--include-comments 还需要 comments。管理员始终拥有全部能力。单项补充失败会记录在对应任务的 analysis.errors,不会丢弃整批分析结果。
所有业务命令输出 JSON。加入 --compact 可以输出单行 JSON;加入全局参数 --api-url <url> 可以临时指定服务端地址。
CLI 登录令牌采用滑动有效期:每次成功使用需要登录的 CLI 命令,服务端都会从本次使用时间起重新顺延有效期,本地配置也会同步新的到期时间。
