@geoly-ai/social-hub-cli 0.3.43 → 0.3.44

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geoly-ai/social-hub-cli",
3
- "version": "0.3.43",
3
+ "version": "0.3.44",
4
4
  "type": "module",
5
5
  "description": "social-hub CLI for Social Ops Hub",
6
6
  "repository": {
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "version": 1,
3
3
  "algorithm": "sha256",
4
- "fileCount": 1656,
4
+ "fileCount": 1657,
5
5
  "files": {
6
6
  "README.md": "5246d4ae2712e3e656b101041929183d7ae7f8ea487dacf5854187826ab7c335",
7
- "manifest.json": "aa878b3b0abb3e120e88d54f293f7ca30157e9fd4467ce26e148976d26e31952",
8
- "reddit-answers-research/SKILL.md": "ab6fd12eeb2fef4dc31a6f3c21a84810d6b5bdb309f130bcdc9eb902f075294a",
7
+ "manifest.json": "333b605af67607055adc717b4a1da318a07fea8b0a0f30e4f1aa86ac3cf03384",
8
+ "reddit-answers-research/SKILL.md": "8936215363b5b222f4010fd18349cb2c56b473ce659bfeb21116ad5448faa640",
9
9
  "reddit-answers-research/references/browser-playbook.md": "a8f61d3d43ca93d46dadc8a092a515ddcd32df12fb1d08d334cce2e02709d915",
10
10
  "reddit-answers-research/references/report-template.md": "9aa9acf555ba8b2ca503bdbdf5750a5f53c66e19989bf6807fa6200c7317e306",
11
11
  "reddit-brand-risk-response/SKILL.md": "590ff3254f3c027bd300f422ef5f9c36b05ef0e1cc470655f5705855911b54bf",
@@ -26,13 +26,13 @@
26
26
  "reddit-delivery-check/references/phase5-delivery.md": "50abd9f6d1a433d52d915221aca17f4f279d9de62190442437c9b92056efcd8a",
27
27
  "reddit-ext-post-audit/SKILL.md": "3cd4310d810eabb58c64116aafa6e373a2da49dc5dfaeaea96f3d1c8af629341",
28
28
  "reddit-ext-post-audit/references/ext-post-audit.md": "0d2fc69ca38b84520409cf866284803ceacbceb82dcdea0df3ed52ad8183a2b6",
29
- "reddit-matrix.lock.json": "ff956c114dd941ef18aa1364f8871657d343a44366e5b78049c40479ca2ae6df",
29
+ "reddit-matrix.lock.json": "5e76c65a6236c9455d6af8b423647ab3f2094127f1b9fc3e5c5fd808175796c4",
30
30
  "reddit-monthly-iteration/SKILL.md": "cb13d1bd821c3361c3bc557beedd78f17d6278cdfbe4dd171d1a6d3b1aa19069",
31
31
  "reddit-monthly-iteration/references/monthly-iteration.md": "fcaf88824e1f7cf80a446919edbcb3685954d31c5606d53836e00589e9524524",
32
32
  "reddit-phase-brief/SKILL.md": "7b4ba2b0aab929ef01c6b07ccbc390f744e08a1acc03d04a969d296a77c2f8f8",
33
33
  "reddit-phase-brief/agents/openai.yaml": "f4605dd61a02068df4e68e018e41a6606dbea70f6dd94a6224b6b01eddb4325a",
34
34
  "reddit-phase-brief/references/brand-SKU-PGC-rules.md": "6a95ea7a13ccccb8efebb143d1791663831a6260fbda69d462d1a1e9c1937253",
35
- "reddit-phase-brief/references/phase4-brief-workflow.md": "fe1a9b969de759a546aa60425a140002aebe73e656da10ce68a58a57517b1ad5",
35
+ "reddit-phase-brief/references/phase4-brief-workflow.md": "fdea7a48519b2882be91857e4efa2dd8bd1aaeaddd551e1b66efd6cd7961a4eb",
36
36
  "reddit-phase-planning/SKILL.md": "798635e05fc39adf713b451e0017a68d067dcffb931fcea31ef64cef320ba519",
37
37
  "reddit-phase-planning/references/phase3-master-canvas.md": "bb00e6071ffad451c0219e111876ef22195e37df154f89d8d763db82a17948b5",
38
38
  "reddit-phase-planning/references/phase4-execution-table.md": "0c0be440255cd69438aaf985f20799aa36a403a92ca08c44844c85c23a92bb55",
@@ -41,7 +41,7 @@
41
41
  "reddit-phase-planning/scripts/phase406_verify.py": "0150e61cc52581f9f7bf304a22429a2efd10e8c1887a9642401509709abc6907",
42
42
  "reddit-phase-research/SKILL.md": "ead16c114cefedd25001bfd337b02c2c35a0ee9b3b865164cff9f620e54e8094",
43
43
  "reddit-phase-research/references/kg-reddit-check.md": "436c364d55279985b25e84c55a922b2dfcc70f81a7b6751748cb32102a1cdb3c",
44
- "reddit-phase-research/references/phase01-research.md": "51586951c0e6a481f9103b5c98d229fe9157dcef6f2dc89d81dbbf22e55d6da8",
44
+ "reddit-phase-research/references/phase01-research.md": "033ade25b7fd021c621c369ced8c9d465b97573ba0e0d0a87c816b622dbbd5ea",
45
45
  "reddit-strategy-orchestrator/SKILL.md": "ca036619a0cddc64a37b071d651d171b745ab59275efe2ce378394ef500f53ff",
46
46
  "reddit-strategy-shared/SKILL.md": "616a84a88b2cbf2ecd4eb6707edfa0d11df901b4041c3eec1891c14bc5f05811",
47
47
  "reddit-strategy-shared/references/content-diversity-contract.md": "c67658d732f4da603786688a13b31783d7a54c2a82d1500c12037118f550ffcb",
@@ -61,17 +61,17 @@
61
61
  "reddit-strategy-shared/references/routing.md": "6a3c5505b96974b1d6406f6c12ca092e65bb6e94496bf3d71a67d1618798d419",
62
62
  "reddit-strategy-shared/references/safety-rules.md": "c8f983f08a5efcfceac5bba6b4e8d1120f32296bfbb2c510f8cbdf9d06b2723d",
63
63
  "reddit-strategy-shared/references/subreddit-research-profile.md": "c5da8d28722c53f2fee0e27f4baf34ac237e7196db045f02fd7df76e3aad31b1",
64
- "reddit-strategy-shared/references/version-manifest.md": "00231d1743addca63eee855e657510b81d70f8a409205a7a0f5b247ea84fe08f",
64
+ "reddit-strategy-shared/references/version-manifest.md": "50d961b1e39ffd1d339cf54725efb3e40a7bb302f14f46c0bcfdebfaf59bcbcf",
65
65
  "reddit-subreddit-compliance/SKILL.md": "12333387bf618e3b1304f5b21a32712a3101c80bcf3daac18754b0bff4129cd5",
66
66
  "reddit-subreddit-compliance/matrix-contract.md": "94cc3eab9133354c58283b4f11f72fc3fdd6e95b9b40b6d250dda86581e452ce",
67
67
  "reddit-subreddit-compliance/references/output-templates.md": "589f44c9544c72e72dcfe8c1a06ec67690214964d0394c652781e469fb9b2fe1",
68
- "reddit-voc-volume/SKILL.md": "fcd15fa5e70d6a1e59a0388f8bbfd9bfe2f89ef4cef0000e938ba17370c3b5e0",
69
- "reddit-voc-volume/matrix-contract.md": "d1a9447c8c7210588a392ab9c04a7c26d4179ab86ca023f6a2b351d622e49b0f",
70
- "reddit-voc-volume/references/arctic-shift.md": "1d8ef84db8bf1106318e588d1def743165c7df8fe110f1529df3de0f8804c64c",
71
- "reddit-voc-volume/references/browser-fallback.md": "d69458ad6708a3b2ea6ae23f7a25b45037e27f888206900c25098f83eb470332",
68
+ "reddit-voc-volume/SKILL.md": "edbe500db0397240867a8d7a44b1bb973dcb6865a8b82ee5ba98ce43f973db87",
69
+ "reddit-voc-volume/matrix-contract.md": "5676c3a847c35062e8432538e0beb98015dfae4a8144da9d437080211a384b11",
70
+ "reddit-voc-volume/references/arctic-shift.md": "c4cec5a64b72e9d528a085d92330833afd175a673310c63968d3b0d4b60f4131",
71
+ "reddit-voc-volume/references/browser-fallback.md": "aa68e38b2fb3026034b8df0e2fcfa950f23b6b235b23df66f68062771f1531c9",
72
72
  "reddit-voc-volume/references/hub-first.md": "36d178bc848ab2a507afdb1feacdf22e67ae775b8d221d50cb700ee2d088d547",
73
- "reddit-voc-volume/requirements.txt": "d4d9b88c7088aa966405d4bf8bf424b4644ccd6ddd59cf62469e008095f7ab8c",
74
- "reddit-voc-volume/scripts/reddit_voc_volume.py": "da0c563771d0895db15d82580da4849ab8d4d150903750c4333c43d620e5441c",
73
+ "reddit-voc-volume/requirements.txt": "91f21d1e6a42dc29db733a5914288ba3f74f3d65d33d49a966fdb60eebd435cc",
74
+ "reddit-voc-volume/scripts/reddit_voc_volume.py": "daf5df32c632b139c2944748b2b31610bd42ba2a578c8aa6a16659e674d4ecda",
75
75
  "reddit-voc-volume/scripts/setup_env.sh": "2e9de90f1a8985953d161beda490c34b4cb5867a2d2d217766d97fd6fe373ec4",
76
76
  "reddit-voc-volume/scripts/setup_firecrawl_service.py": "8d25d38761d9db169bf403a49afdc7892bc5df09910d6d44a073082fbc29967c",
77
77
  "reddit-voc-volume/services/firecrawl/.gitattributes": "1a1dbe176bc233b499d35a57db7513f2941c99ab9759f177830c9149be99005b",
@@ -1633,27 +1633,28 @@
1633
1633
  "reddit-voc-volume/services/firecrawl/img/firecrawl_logo_v1.png": "40b85912f49f4a1b45f42b85bbb39150fb7c0823c1c4ecadaa82860a988fa884",
1634
1634
  "reddit-voc-volume/services/firecrawl/img/open-source-cloud.png": "3d49d98b06dc91e829c9ea2410ad10aaddc0b8b7d7e2a133e061daaff6429895",
1635
1635
  "reddit-voc-volume/tests/test_archived_comments.py": "81fd6da65498f5cca81a10bae28bd6a9164efee1be4545dcab8d99984780a54e",
1636
+ "reddit-voc-volume/tests/test_links_fallback.py": "0b6756cbef92567c680fe56525f89ca791502d6173414f833b50e305ef56c65a",
1636
1637
  "social-hub-accounts/SKILL.md": "096f7969f572a0cecbf244d814ba43422b8b556a98b751dc1ece7f9066864e4d",
1637
1638
  "social-hub-admin/SKILL.md": "f8f9ef070a1bbe62018bbbb362101deccafd4eb76c2dbd192321cc2226e15497",
1638
1639
  "social-hub-calendar-directives/SKILL.md": "f544586b6474f07d072fc0666bd4969492dd6557794b2bb1495e497699d60a84",
1639
1640
  "social-hub-calendar-jobs/SKILL.md": "7b300722376b6652f214ecb41ff77c36f65e28a13846b61c99c44042dfdde1f0",
1640
1641
  "social-hub-cli/SKILL.md": "256b848caaf25399accc4290dd07fc4bf2f06a4e5de080d92d7c144ee51d22f9",
1641
1642
  "social-hub-cli/evals/evals.json": "ba4851f8bce01c2ee4128ef224c6bcc284f5d8f2058c90bad0f7156596e5cf28",
1642
- "social-hub-content-classification/SKILL.md": "15b625290ffe134934eed0d5a9c85983ddca8b24d8261b36da9da3594836e39e",
1643
+ "social-hub-content-classification/SKILL.md": "400c1fa5940337a5930334ce809f0673e98e36f5279a0bfb1b3279da2a48d9dc",
1643
1644
  "social-hub-content-review/SKILL.md": "6d10a84ab56552fd953863b97978bddc0e925e3a2667d64a7a4c51e33a3ddb58",
1644
1645
  "social-hub-events-observability/SKILL.md": "f4c17487c64bb1f48381d8d60e97cfa160a94a0f120153b1c0e798a0c7ee7ebe",
1645
1646
  "social-hub-graph-compliance/SKILL.md": "2270aeb321733f0318f75da4838ca1ca03996c6cac59e5a12f7152bd1ecdfa26",
1646
- "social-hub-intelligence/SKILL.md": "69f4a3d97b36e13f8ee594708f84e268996559ace86982194dbc23d353cc2923",
1647
+ "social-hub-intelligence/SKILL.md": "4c59d8b0f05668f97c40bf7e80b8cd9a992bb892846fedd2b15954f887923240",
1647
1648
  "social-hub-migration/SKILL.md": "1c13f231bb81ae8d242c834eec93a499830481804c66f6dba95922972f56f9ce",
1648
1649
  "social-hub-notifications/SKILL.md": "f80f4cf2f9ef0dbf60bd6e8bb4ad7e27dc0ff1fe59f4c7e79e49cc691ed4be6a",
1649
- "social-hub-openclaw-context/SKILL.md": "97c48f38f1f1a206c3af2af49fcd445a1cd5b78d4a9c805c2456de4ce98fec09",
1650
+ "social-hub-openclaw-context/SKILL.md": "8592c4d04987f54ead6f171b1b251233b776469ee6c12a7c97c9dc71df46e6ad",
1650
1651
  "social-hub-ops-runtime/SKILL.md": "2fcf257f9c2a36236564fc9056605f2df1d706e0a6f290de68b05ac44890ae3e",
1651
1652
  "social-hub-post-review/SKILL.md": "20a0d4886d1fc70397f9f3e5e25672e69608b1cce56971e1b2401e817fbf3cb6",
1652
1653
  "social-hub-posts/SKILL.md": "e4b501f521cb36448e3f49313e47855b93dc4f2ad7772e55309e6a680890c3ee",
1653
1654
  "social-hub-posts/evals/evals.json": "af4add3e4edcdf148c1594fbc1b33b90e13d144029aa0f8094b3cda05c95f1f1",
1654
1655
  "social-hub-publishing/SKILL.md": "6fac6b40d1379a98c718a2acd1a1564352f56e13cc48593d9ff3f8d657d7df18",
1655
1656
  "social-hub-publishing/evals/evals.json": "e75719b796d83ec2dac8d0cac9dc38060faebfe88711d3255243a90afa0125ba",
1656
- "social-hub-scrape/SKILL.md": "fbe393c01195aea3b9899e017bc53ea07cef95c1868983a39a74d04031a2face",
1657
+ "social-hub-scrape/SKILL.md": "b6d35f950010cbbe31fa78ba5c32be834b509fef8ab1411bfae58bfec2992339",
1657
1658
  "social-hub-shared/SKILL.md": "a99afb2455df96906aeb36b59e8470c3e711904923cc10a539a40e667459f116",
1658
1659
  "social-hub-shared/evals/evals.json": "fb9c4ed6211c17e80212ccdfaba1641e900ccc44eb144e00aa311a29d5aa9186",
1659
1660
  "social-hub-style-curator/SKILL.md": "80f9a50897f1d92a5086abda745865a378553190a0ceaf5c91f8c6093fa484fd",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 1,
3
3
  "package": "social-ops-hub",
4
- "cliVersion": "0.3.43",
4
+ "cliVersion": "0.3.44",
5
5
  "repository": "social-ops-hub",
6
6
  "publish": {
7
7
  "registry": "https://skill.sh",
@@ -102,7 +102,7 @@
102
102
  {
103
103
  "id": "social-hub-scrape",
104
104
  "path": "social-hub-scrape",
105
- "description": "通用网页抓取:HTML/普通网页经 Firecrawl(markdown/html/links),Reddit .json 走直连 curl_cffi+住宅代理"
105
+ "description": "通用网页抓取:HTML/普通网页经 Firecrawl(markdown/html/links);⛔ Reddit 两条路径均已被拦,取 Reddit 数据走 social-hub-intelligence"
106
106
  },
107
107
  {
108
108
  "id": "social-hub-migration",
@@ -168,7 +168,7 @@ python3 "$VOC" keyword "<english query>" --limit 10 --sleep-sec 6 --pretty
168
168
  python3 "$VOC" subreddit "<keywords>" -r "<subreddit>" --limit 10 --sleep-sec 6 --pretty
169
169
  ```
170
170
 
171
- 把 VOC 输出的 `title`、`url`、`subreddit`、`score`、`num_comments`、`upvote_ratio`、`flair_text` 写入证据表;不要用浏览器滚动搜索页来替代这些字段。若 VOC 因 Reddit JSON/403 失败,记录 `errors` 和 `request_identity`;必要时再用浏览器 MCP 做少量人工验证。
171
+ 把 VOC 输出的 `title`、`url`、`subreddit`、`num_comments`、`upvote_ratio`、`flair_text` 写入证据表;`score` 必须同时记录 `score_status`,Arctic 归档只有 `Backfilled` 可用于声量判断。不要用浏览器滚动搜索页来替代这些字段。若 Arctic / Hub / 渲染页取证失败,记录 `errors`、`provenance` 和来源状态;必要时再用浏览器做少量公开页面人工验证,不处理验证码。
172
172
 
173
173
  若当前机器没有安装 `reddit-voc-volume`,先提醒用户安装/更新本矩阵包里的对应 skill,并完成 `reddit-voc-volume` 的 Python 依赖 setup;不要直接降级成浏览器批量爬取。
174
174
 
@@ -7,16 +7,16 @@
7
7
  "contentSha256": "9a4fa3944ec3913a4e68cb1faf4d4a32ca04131fa4b0c37e054065f4e2c1a1ed"
8
8
  },
9
9
  "reddit-strategy-shared": {
10
- "contentSha256": "bba5c177a4af9bab0f2d9c227993862629e82ec9747cd2788e4874d058da3c89"
10
+ "contentSha256": "ee4a7e485c026d1fba34b40265ad0ce669c8e840a9e7ed8c2cfcf7fc6ded0aa7"
11
11
  },
12
12
  "reddit-phase-research": {
13
- "contentSha256": "9f47b8eb0d1c1c194c685856242c9b22d190dfa8c6f572869e964239215795fe"
13
+ "contentSha256": "679c8f75c0e8cd1f5bcab9dd669183fa5ee886718ea16c4c1494e91819b559df"
14
14
  },
15
15
  "reddit-phase-planning": {
16
16
  "contentSha256": "8080adce62b6db65be3dbc0f37f162a81e382d6b64108f7352ec83c356664659"
17
17
  },
18
18
  "reddit-phase-brief": {
19
- "contentSha256": "3475bf4c4aa4796db1c99a3bd527c52dc8488f71db01753da0325e924d552b99"
19
+ "contentSha256": "9bb338fd7ea6f7dc22fe2576d441b07be5f216d0eb1a44e6b3cac931eb023b5e"
20
20
  },
21
21
  "reddit-content-writing": {
22
22
  "contentSha256": "08023a5dfa6cc2f3ffc3f1a551479c645ddcfc8cc775f88cd2d245c067829482"
@@ -28,7 +28,7 @@
28
28
  "contentSha256": "9231ff9ae5d950bc2fb87e45bee05e793b3ff9c37bee45e8444059a8b698e4a9"
29
29
  },
30
30
  "reddit-voc-volume": {
31
- "contentSha256": "496c0d57af7507d86a16bd4d06f3a5a017ca10b3dc4e3564d82b0c988e1c87ac"
31
+ "contentSha256": "7b068ab2fb50627978ec54bea3c76d12333b5438dd40f16204d1982ae5e9d95c"
32
32
  },
33
33
  "reddit-brand-risk-response": {
34
34
  "contentSha256": "dbba80345ebe68818a25e7604dfaa6951c6bf0e4d785d5013be7a06b22ec5b7c"
@@ -37,7 +37,7 @@
37
37
  "contentSha256": "3cab43d1c70d511212f3684929a8d7da73c11d3ae34563f31d1eebe04a6ecd8b"
38
38
  },
39
39
  "reddit-answers-research": {
40
- "contentSha256": "eb132d81021f0a24619d9b576a287f722cf61c24422874d5be86cd4be2c392df"
40
+ "contentSha256": "47358e4233c015aa341e2295721f59af679756923b172b12772b6b5540293a3c"
41
41
  },
42
42
  "reddit-monthly-iteration": {
43
43
  "contentSha256": "808659c48e546e8ce35e32ec42c68d35e3f843ec41d4974ea8eabd1da1dac7ce"
@@ -241,8 +241,8 @@ exact)。仍不足时二分:flair 决定资格 / 披露 / 帖型 / 上下文
241
241
  | 来源 | 判据 | 备注 |
242
242
  |---|---|---|
243
243
  | Hub | `selftextCompleteness: full` | Hub 已取消截断;`unknown` / 无声明仍是 `null` |
244
- | Arctic Shift | `history` 模式或 `--backend arctic-shift` | 归档全文,覆盖 2005 起 |
245
- | reddit `.json` | `--backend reddit-json` | 多数网络环境已被 Reddit 拦截 |
244
+ | Arctic Shift | `history` / `comments` 模式,或 `keyword` / `subreddit` 的 Emergency Acquisition | 归档全文,覆盖 2005 起;后端固定,无 `--backend` 参数 |
245
+ | reddit `.json` | —— | **v2.12.28 起已从采集器移除**(2026-09-18 实测:住宅代理同样 403)。存量样本保持原判定,不再产生新样本 |
246
246
 
247
247
  > **dispatch 路径注意:** Hub 的 dispatch run `resultPayload` **不携带正文字段**,
248
248
  > 脚本会从 `intelligence hot-posts` 回填。回填不到的条目保持 `null`,仍按截断
@@ -260,8 +260,8 @@ python3 "$VOC" flair-filters -r "<subreddit>" \
260
260
 
261
261
  - `wiki/rules/flairs` 属于 skill 支持但旧清单未强制的发帖规范证据;本版本起必须补抓。
262
262
  - Reddit flair template API 通常返回 `USER_REQUIRED`,默认不能作为公开采集能力;只能用 flair wiki、`subreddit_about` 的 flair 开关、`flair-filters` 的公开 filter 链接和帖子样本中的实际 flair 辅助判断。
263
- - `stickies` 只能抓公开 hot listing 里的 `stickied=true` 帖子;拿不到登录后个性化内容、App-only 展示或隐藏置顶。
264
- - Social Hub / Firecrawl fallback 只提供公开 HTML/Markdown/page_signals 页面证据,不能替代 Reddit JSON 的可靠 score/comment/upvote/flair/stickied 结构化字段。
263
+ - 当前置顶只能用 Hub 的 live 证据;`stickies` 本地兜底已不产出 `pinned_post`。取不到时标 NotVisible / NeedsAcquisition,不拿归档 `stickied` 代替。
264
+ - Social Hub / Firecrawl fallback 只提供公开 HTML/Markdown/page_signals 页面证据,不能单凭它证明实时 score/comment/current-pinned。Arctic 帖子的 `score` 须按 `score_status` 判断,不能把归档值直接当实时热度。
265
265
  - `about-page` 只能抓公开渲染 About 页;能抓到页面显示的 weekly visitors、weekly contributions、公开 Installed Apps。若没有单独 active users 文案,`weekly_active_users` 是 `weekly_contributions` 的兼容映射,不能说成 Reddit 独立公开活跃用户字段。
266
266
  - AutoModerator 配置通常不是公开数据;只能来自用户提供的 bot 回复/删帖提示、置顶帖文字、sidebar/wiki 明文或发帖后证据。
267
267
  - Installed Apps / mod apps 不在任何结构化数据源中;只能看 `about-page.installed_apps[]`。公开渲染页未看到时写 `InstalledAppsStatus: NotVisible / NeedsAcquisition`,不能写“没有 Installed Apps”。
@@ -176,8 +176,8 @@ may **only** be derived from bodies whose provenance declares completeness.
176
176
  | Producer | `selftext_truncated` | Usable for length |
177
177
  |---|---|---|
178
178
  | Hub record with `selftextCompleteness: full` | `false` | yes |
179
- | Arctic Shift (`history` / `--backend arctic-shift`) | `false` | yes |
180
- | reddit `.json` (`--backend reddit-json`) | `false` | yes |
179
+ | Arctic Shift (`history` / `comments` / Emergency Acquisition) | `false` | yes |
180
+ | reddit `.json` | — | **removed in v2.12.28** — the collector no longer fetches reddit.com `.json` (2026-09-18: 403 even through residential proxies). Existing samples already tagged `false` stay usable; no new ones are produced. |
181
181
  | Hub record with `unknown` / no declaration | `null` | **no** |
182
182
  | Hub dispatch `resultPayload` (carries no body field) | `null` until backfilled | **no** |
183
183
  | any v2.12.25-or-earlier sample | `null` | **no** |
@@ -10,8 +10,8 @@ description: |
10
10
 
11
11
  ## Arctic Shift 归档后端(v2.12.27)
12
12
 
13
- `history` / `comments` 模式与缺省的 `--backend arctic-shift` 走 Arctic Shift 归档 API,不经
14
- reddit.com。**使用前读 [references/arctic-shift.md](references/arctic-shift.md)**,
13
+ `history` / `comments` 模式与 `keyword` / `subreddit` 的 Emergency Acquisition 都走 Arctic Shift
14
+ 归档 API,不经 reddit.com(v2.12.28 起后端固定,**没有** `--backend` 参数)。**使用前读 [references/arctic-shift.md](references/arctic-shift.md)**,
15
15
  尤其是「能力边界」表:正文 / `num_comments` / `upvote_ratio` / 版规 / wiki 可用;
16
16
  **`score` 不可信**(实测约 1/3 归档行是发帖瞬间的陈旧值,逐条标 `score_status`,
17
17
  只有 `Backfilled` 允许用于声量);此刻置顶、当前 hot、About 页周指标是 live 语义,
@@ -46,7 +46,8 @@ reddit.com。**使用前读 [references/arctic-shift.md](references/arctic-shift
46
46
 
47
47
 
48
48
 
49
- Python 3.10+;可选 curl、curl_cffi、browser_cookie3;网络可访问 reddit.com;建议配置 HTTPS_PROXY。
49
+ Python 3.10+;网络可访问 **arctic-shift.photon-reddit.com**(历史/评论/版规/wiki/about)与 Social Hub / 本机 Firecrawl(渲染页证据);建议配置 HTTPS_PROXY。
50
+ **本机不直连 reddit.com**:渲染页由 Hub / Firecrawl 代为访问。`curl`、`curl_cffi`、`browser_cookie3` 与 `--via-curl` 均为 v2.12.28 前的遗留物,当前代码路径用不到(见下节「请求身份」)。
50
51
 
51
52
  ## 何时用 / 不用
52
53
 
@@ -55,9 +56,9 @@ Python 3.10+;可选 curl、curl_cffi、browser_cookie3;网络可访问 reddi
55
56
  | 品牌词/关键词 Reddit 声量 | 单条链接只要 score → `reddit-link-engagement` |
56
57
  | 指定 r/xxx 内关键词扫描 | 大规模全站监控、分钟级轮询 |
57
58
  | 批量 Reddit URL 汇总:帖子 permalink、`/about`、`/about/rules`、`/wiki/*` | 绕过私密版/验证码/登录墙 |
58
- | subreddit hot listing 里的置顶帖 / pinned / stickied / megathread 公开采样 | 读取 AutoModerator 配置或 mod apps 后台 |
59
+ | 通过 Social Hub 取得当前置顶帖 / pinned / stickied / megathread 公开证据;Hub 不可用时标 NotVisible | 读取 AutoModerator 配置或 mod apps 后台 |
59
60
  | 公开渲染 About 页里的周访客/周贡献/每周活跃用户兼容字段、可见 Installed Apps、公开 flair filter / page signals | 保证完整后台 Installed Apps 或 flair template 列表 |
60
- | JSON 失败后的 Social Hub / Firecrawl / 浏览器低频兜底采样 | 并发刷搜索页 |
61
+ | Hub / Arctic 取不到时的 Social Hub / Firecrawl / 浏览器低频兜底采样 | 并发刷搜索页 |
61
62
 
62
63
  ## 一步执行(Emergency Acquisition——仅四级链路 L3 时使用,默认先走 Hub,见上节)
63
64
 
@@ -123,9 +124,9 @@ python3 "$VOC" comments t3_abc123 --source search --body "battery life" \
123
124
  # 按评论 ID 批查(最多 500;空格或逗号分隔)
124
125
  python3 "$VOC" comments --ids t1_def456 ghi789 --pretty
125
126
 
126
- # Emergency Acquisition 后端切换(缺省已是 arctic-shift)
127
- python3 "$VOC" keyword "PLAUD recorder" --backend arctic-shift --pretty
128
- python3 "$VOC" keyword "PLAUD recorder" --backend reddit-json --pretty
127
+ # ⛔ 没有 --backend 这个参数(v2.12.28 起后端固定 Arctic Shift)。
128
+ # 传它会被 argparse 直接拒掉:error: unrecognized arguments: --backend
129
+ # 旧文档里的 `--backend arctic-shift` / `--backend reddit-json` 两条都跑不了,别照抄。
129
130
 
130
131
  # 检查 Social Hub scrape fallback
131
132
  python3 "$VOC" social-hub-check --pretty
@@ -136,7 +137,7 @@ python3 "$VOC" firecrawl-check --pretty
136
137
  # 检查 skill 内置的 Firecrawl 自托管源码快照
137
138
  python3 "$HOME/.cursor/skills/reddit-voc-volume/scripts/setup_firecrawl_service.py" --check --pretty
138
139
 
139
- # 仅在 Reddit JSON 失败时启用 Social Hub 页面 fallback
140
+ # 渲染页证据:显式启用 Social Hub 页面 fallback(Arctic 不提供渲染页信号时)
140
141
  python3 "$VOC" links \
141
142
  "https://www.reddit.com/r/espresso/wiki/rules" \
142
143
  --fallback social-hub \
@@ -162,7 +163,7 @@ python3 "$VOC" links \
162
163
  | `subreddit` | Hub-First 子版内关键词 VOC | `-r/--subreddit` 可重复;同上 acquisition-policy/sort/time |
163
164
  | `links` | 批量 Reddit URL;支持帖子 permalink、subreddit about、about/rules、wiki 页面;可显式启用 Social Hub / Firecrawl 页面 fallback | URL 列表或 `--file`;`--fallback social-hub/firecrawl/auto` |
164
165
  | `comments` | **v2.12.31 新增。** 从 Arctic Shift 读取帖子历史评论正文;默认树模式,另有筛选搜索和评论 ID 批查 | positional 帖子 URL/ID;`--source tree/search`;`--body` / `--author` / `--after` / `--before` / `--parent-id`;`--ids` |
165
- | `stickies` | 从 subreddit hot listing 低频读取 `stickied=true` 置顶帖 | `-r/--subreddit` 可重复;`--limit` 控制 hot listing 读取数量 |
166
+ | `stickies` | Hub-First 读取当前置顶证据;本地无有效兜底,取不到标 NotVisible | `-r/--subreddit` 可重复;`--limit` 为历史兼容参数 |
166
167
  | `about-page` | 用 Social Hub 或自托管 Firecrawl 渲染公开 subreddit About 页,提取 weekly visitors、weekly contributions、weekly active users 兼容字段、公开 Installed Apps | `-r/--subreddit` 可重复;`--provider social-hub/firecrawl/auto`;`--firecrawl-base-url` |
167
168
  | `page-signals` | 用 Social Hub 或自托管 Firecrawl 渲染任意公开 Reddit 页,统一解析页面 links/Markdown 里的公开信号 | URL 列表或 `--file`;`--provider social-hub/firecrawl/auto` |
168
169
  | `flair-filters` | 渲染 subreddit home/hot/new/top,合并公开可见 flair filter 链接 | `-r/--subreddit` 可重复;`--provider social-hub/firecrawl/auto` |
@@ -272,7 +273,7 @@ python3 "$VOC" page-signals "https://www.reddit.com/r/espresso/" \
272
273
 
273
274
  ### Social Hub / Firecrawl 页面 fallback(可选)
274
275
 
275
- 页面 fallback 只在 `links` 模式显式开启;当 Reddit JSON 抓取失败,或 JSON 成功但结构化解析不到目标内容(如非帖子页面被帖子解析器返回 `no_post_in_listing`)时触发。`social-hub` 需要 Social Hub CLI 已登录且 `social-hub scrape status` 可用;`firecrawl` 需要本机自托管 Firecrawl 服务。
276
+ 页面 fallback 只在 `links` 模式按 `--fallback` 开启;当 Arctic 归档查询失败或未返回可解析的目标内容时触发。`social-hub` 需要 Social Hub CLI 已登录且 `social-hub scrape status` 可用;`firecrawl` 需要本机自托管 Firecrawl 服务。当前已验证出口上,Social Hub scrape 的 Reddit 渲染页也可能返回 captcha;`auto` 会接着尝试本机 Firecrawl,两者都失败时标 NeedsAcquisition,不把页面缺口判作内容不存在。
276
277
 
277
278
  ```bash
278
279
  python3 "$VOC" links "https://www.reddit.com/r/espresso/wiki/rules" \
@@ -374,7 +375,7 @@ Installed Apps 只代表公开渲染 About 页可见的 app 链接,例如页
374
375
 
375
376
  若页面 provider 可达但 Reddit 返回空壳页或 anti-bot 内容,`about-page` 会输出 `ok=false`、`about_page_failed: ... about_page_empty_rendered_content`。这时不要写 `NotVisible` 或“没有数据”,而是在 Phase 0.5 报告里标 `AboutPageEvidenceStatus: NeedsAcquisition`,可低频稍后重试,或要求用户提供 About 页截图/文本。
376
377
 
377
- Social Hub / Firecrawl 只能提供公开 HTML/Markdown 页面证据;不要把它们当成 Reddit JSON 替代品。帖子 `score`、`num_comments`、`upvote_ratio`、`stickied=true`、flair 结构化字段仍以 JSON 成功输出为准。
378
+ Social Hub / Firecrawl 只能提供公开 HTML/Markdown 页面证据;不要把渲染页信号当成完整结构化数据。帖子 `num_comments`、`upvote_ratio` 与 flair 字段可来自 Hub 或 Arctic 归档;Arctic `score` 仅在 `score_status=Backfilled` 时可用于声量,`VerifiedLive` 则以实时核验值为准。归档 `stickied` 不证明当前置顶;当前置顶只用 Hub 的 live 证据。
378
379
 
379
380
  ## 风控(默认严格,勿随意放宽)
380
381
 
@@ -385,24 +386,30 @@ Social Hub / Firecrawl 只能提供公开 HTML/Markdown 页面证据;不要把
385
386
  - 默认 `--sleep-sec 6`,每次请求后 **+1.5–4.5s** 随机抖动
386
387
  - 默认 `--max-pages 1`,单次运行最多 **20** 个 HTTP 请求
387
388
  - 遇 **429** → 立即熔断,输出 `rate_limited: true`
388
- - 遇 **403/HTML challenge** → 停止扩量,见 [`references/browser-fallback.md`](references/browser-fallback.md)
389
+ - 渲染页(Social Hub / Firecrawl)遇 **403/captcha/HTML challenge** → 停止扩量,见 [`references/browser-fallback.md`](references/browser-fallback.md);reddit.com `.json` 已不在采集路径内(见下节)
389
390
 
390
391
  长期监控:按**小时/天**排程、缓存结果、只增量查询;勿同一 IP 高频轮询。
391
392
 
392
393
  v2.12.23 沿用 v2.12.12 引入的安全默认采样:`limit=10 / sleep=6`,目的是降低单次误触发风控的概率。Phase 0.5 / Phase 1 如需更大样本,应在命令中显式传 `--limit` 和 `--sleep-sec`,不要依赖默认值。
393
394
 
394
- ## JSON 请求身份
395
+ ## 请求身份(v2.12.28 起不再打 reddit.com `.json`)
395
396
 
396
- Reddit `.json` 常对非浏览器请求 403。脚本默认:
397
+ 🔴 **本脚本已不向 reddit.com 发 `.json` 请求。** v2.12.28 把 `search.json` / `<permalink>.json` /
398
+ `about.json` / `rules.json` / `wiki/*.json` 全部换成 Arctic Shift 端点(对照表见
399
+ [`references/arctic-shift.md`](references/arctic-shift.md) §「v2.12.28:reddit `.json` 直采已全部移除」),
400
+ 渲染页证据走 Social Hub / Firecrawl。**2026-09-18 实测:`.json` 对住宅代理同样 403**,
401
+ Reddit 侧封控已不是「换个指纹/加 cookie 就能过」的问题,别再把它当可选通道。
397
402
 
398
- 1. Chrome UA + 完整浏览器请求头
399
- 2. `curl_cffi` Chrome TLS 指纹(`impersonate=chrome131`)
400
- 3. 可选 cookie:`REDDIT_COOKIES_JSON` 或 `REDDIT_USE_BROWSER_COOKIES=1`(`browser_cookie3` 读本机浏览器)
401
- 4. 降级:`curl` → `urllib`;代理:`HTTPS_PROXY` / `REDDIT_SYNC_HTTP_PROXY`
403
+ 遗留物盘点:`RedditHttpClient` / `CookieStore` 仍有定义,但主流程不再实例化客户端,也不会读取浏览器 cookie;
404
+ `--via-curl` 是保留的空开关;`fetch_via_curl_cffi` / `http_get_json_via_curl` 只有定义没有调用。
405
+ `requirements.txt` 的 `curl_cffi`、`browser_cookie3` 当前路径用不到。输出信封里的
406
+ `request_identity.*` 是兼容字段,**不表示真的打过 reddit.com**。
402
407
 
403
- **Cookie 单次加载**:进程启动时读一次 cookie(或 `REDDIT_COOKIES_JSON`),整次运行复用;`curl_cffi` Session 也复用,避免重复弹钥匙串。输出 `request_identity.cookie_cache_reused` 表示多请求复用。
408
+ `links` 模式四种目标现在全部走 Arctic:帖子 permalink → `arctic_post_by_permalink`,
409
+ about / rules / wiki → 对应的 `arctic_*_as_reddit_payload`;取不到才按 `--fallback` 走 Hub / Firecrawl 渲染页。
404
410
 
405
- Cookie **仅**用于减少公开页误判,不用于私密版/验证码。输出 `request_identity` 不含 cookie 值。
411
+ 出站身份现在只剩两类:Arctic Shift 归档 API(普通 HTTPS,可用 `HTTPS_PROXY`)与
412
+ Social Hub / Firecrawl 渲染页。
406
413
 
407
414
  ## 输出 JSON 结构
408
415
 
@@ -485,8 +492,8 @@ Cookie **仅**用于减少公开页误判,不用于私密版/验证码。输
485
492
  > | `selftext_chars` / `selftext_words` | 正文真实长度(截断前) |
486
493
  > | `selftext_truncated` | `false`=全文可信;`true`=被截断;**`null`=来源未声明(Hub 的 `selftextExcerpt` 即为此类),下游须按已截断处理** |
487
494
  >
488
- > **v2.12.27:`selftext_truncated=false` 的三个合法来源** —— Hub 记录声明
489
- > `selftextCompleteness: full`;Arctic Shift 归档;reddit `.json` 直采。
495
+ > **`selftext_truncated=false` 的合法来源** —— Hub 记录声明 `selftextCompleteness: full`;
496
+ > Arctic Shift 归档。(v2.12.27 原列的第三项「reddit `.json` 直采」自 v2.12.28 起已不存在。)
490
497
  > Hub 的 `unknown` / 无声明仍是 `null`。Hub dispatch run 的 `resultPayload`
491
498
  > **不带正文字段**,脚本会从 `intelligence hot-posts` 回填,回填不到保持 `null`。
492
499
  >
@@ -507,13 +514,13 @@ Cookie **仅**用于减少公开页误判,不用于私密版/验证码。输
507
514
 
508
515
 
509
516
  - `score` 是 Reddit 展示分,≠ 纯点赞数;`upvote_ratio` 更有参考价值。
510
- - `flair_*` 来自 Reddit post JSON 的 `link_flair_*` 字段;无 flair 时字段保持 `null` 或空数组。帖子 item 还包含公开 JSON 中可见的 `flair_template_id`、`flair_filter_query`、`author_flair_text`、`author_flair_type`、NSFW/spoiler/gallery/video 等辅助字段。
517
+ - `flair_*` 从 Hub 或 Arctic 帖子记录的 `link_flair_*` 字段映射;无 flair 时字段保持 `null` 或空数组。帖子 item 还包含来源记录中可见的 `flair_template_id`、`flair_filter_query`、`author_flair_text`、`author_flair_type`、NSFW/spoiler/gallery/video 等辅助字段。
511
518
  - `item_type=post` 是帖子;`item_type=subreddit_about` / `subreddit_rules` / `wiki_page` 是非帖子公开页面证据,`score` / `num_comments` 置 0 仅为 schema 兼容。
512
519
  - `item_type=comment` 来自 `comments`,`body` 为不截断的归档评论正文;`parent_id` 加树坐标可还原层级。其 `score_status=ArchivedSnapshot`、`score_realtime=false`,不得当实时热度。
513
- - `item_type=pinned_post` 来自 `stickies` 模式,只代表 hot listing 中公开可见的 `stickied=true` 帖子;可作为 Pinned/Sticky/Megathread 证据输入 `reddit-subreddit-compliance`。
514
- - `item_type=firecrawl_page` 是 Social Hub / Firecrawl 页面 fallback 结果,含 `markdown_excerpt`、`html_excerpt`、`metadata`、`page_provider` 和 `page_signals`;只在 `--fallback social-hub|firecrawl|auto` 且 JSON 抓取失败或解析不到目标内容时出现。
520
+ - `item_type=pinned_post` 只能来自 Hub 的当前置顶证据;`stickies` 的本地 Emergency Acquisition 不再产出它。Hub 取不到时标 NotVisible / NeedsAcquisition,不用归档 `stickied` 冒充。
521
+ - `item_type=firecrawl_page` 是 Social Hub / Firecrawl 页面 fallback 结果,含 `markdown_excerpt`、`html_excerpt`、`metadata`、`page_provider` 和 `page_signals`;只在 `--fallback social-hub|firecrawl|auto` 且 Arctic 查询失败或未返回可解析目标时出现。
515
522
  - `item_type=subreddit_about_page` 是 `about-page` 的 Social Hub / Firecrawl 渲染结果,含 `weekly_visitors`、`weekly_contributions`、`weekly_active_users`、`weekly_active_users_source`、`installed_apps`、`installed_apps_status`、`flair_filters`、`page_signals`、`page_provider`,只能作为公开渲染 About 页证据。
516
- - `item_type=reddit_page_signals` / `subreddit_flair_filters` 来自 `page-signals` / `flair-filters`,只表示公开渲染页可见链接和正文信号;不能替代 `.json` 的 score/comment/stickied,也不能证明后台 flair template 或 Installed Apps 完整列表。
523
+ - `item_type=reddit_page_signals` / `subreddit_flair_filters` 来自 `page-signals` / `flair-filters`,只表示公开渲染页可见链接和正文信号;不能单凭它们证明实时 score/comment/current-pinned,也不能证明后台 flair template 或 Installed Apps 完整列表。
517
524
  - `subreddit_rules` items 含 `rules[]`、`rule_count`、`rules_text_excerpt`;`wiki_page` items 含 `wiki_page`、`content_md_excerpt`;`subreddit_about` items 含 `public_description`、`description_excerpt`、`submit_text_excerpt`、`allow_images/videos/polls/galleries`、`link_flair_enabled`、`user_flair_enabled_in_sr`、`wiki_enabled`、banner/sidebar 元数据。
518
525
  - `subreddit_metrics` 是 best-effort 板块公开指标。v2.12.28 起 `subscribers` 等来自 **Arctic Shift 的 subreddit 元数据**,`metrics_status=ArchivedSnapshot` —— Arctic 的 subreddit 列表更新不频繁,这是**快照值,不是实时订阅数**。另附 `num_posts` / `num_comments` / `metrics_updated_at`(来自 `_meta`,刷新更勤)。取不到时字段为 `null` 且 `metrics_status=Unavailable`。要实时规模指标走 `about-page` 渲染页或 Hub。
519
526
  - `subreddit_metrics.weekly_visitors` / `subreddit_metrics.weekly_active_users` 不是稳定公开 JSON 字段,默认输出 `null`;需要周访客/周贡献时运行 `about-page`,并在报告中标注来源为 `public_rendered_about_page`。
@@ -522,7 +529,7 @@ Cookie **仅**用于减少公开页误判,不用于私密版/验证码。输
522
529
 
523
530
  ## 浏览器兜底
524
531
 
525
- JSON 连续失败时,优先考虑显式 `--fallback social-hub` 或 `--fallback auto`;若 Social Hub 和本地 Firecrawl 都不可用,再读 [`references/browser-fallback.md`](references/browser-fallback.md):低频打开搜索页/子版页,只读首屏,回填同一 schema(`fetch_mode: browser_fallback`,`confidence: sampled`)。
532
+ Arctic 查询缺口或渲染页取不到时,先按 Hub-First 决策表处理;`links` 可显式启用 `--fallback auto`。若 Social Hub 和本地 Firecrawl 都不可用,再读 [`references/browser-fallback.md`](references/browser-fallback.md):低频打开搜索页/子版页,只读首屏,回填同一 schema(`fetch_mode: browser_fallback`,`confidence: sampled`)。
526
533
 
527
534
  ## 安装与依赖
528
535
 
@@ -19,7 +19,7 @@
19
19
  - archived comment bodies and reconstructable thread hierarchy from Arctic Shift
20
20
  (`comments`; `parent_id` plus tree coordinates; archive score is not live)
21
21
  - public subreddit rules/wiki/about/submit-text evidence
22
- - public pinned/stickied/megathread evidence from subreddit hot listings
22
+ - current pinned/stickied/megathread evidence from Social Hub (no local archive substitute)
23
23
 
24
24
  ## Evidence Role
25
25
 
@@ -1,8 +1,8 @@
1
1
  # Arctic Shift 归档后端(v2.12.27;v2.12.31 增加评论正文)
2
2
 
3
- > **何时读本文件:** 使用 `history` / `comments` 模式,或 Emergency Acquisition 落到
4
- > `--backend arctic-shift`(缺省)时。判断某个字段能不能用,以本文件的
5
- > 「能力边界」表为准。
3
+ > **何时读本文件:** 使用 `history` / `comments` 模式,或 Emergency Acquisition 取数时
4
+ > (v2.12.28 起后端固定 Arctic Shift,**没有** `--backend` 参数可选)。判断某个字段能不能用,
5
+ > 以本文件的「能力边界」表为准。
6
6
 
7
7
  上游项目:<https://github.com/ArthurHeitmann/arctic_shift>
8
8
  Base URL:`https://arctic-shift.photon-reddit.com`
@@ -130,12 +130,13 @@ python3 "$VOC" comments "https://www.reddit.com/r/example/comments/abc123/slug/"
130
130
  python3 "$VOC" comments abc123 --source search --body "battery life" --parent-id top --pretty
131
131
  python3 "$VOC" comments --ids t1_def456 ghi789 --pretty
132
132
 
133
- # Emergency Acquisition 显式指定后端(缺省已是 arctic-shift)
134
- python3 "$VOC" keyword "PLAUD recorder" --backend arctic-shift --pretty
135
- python3 "$VOC" keyword "PLAUD recorder" --backend reddit-json --pretty # 旧的 .json + curl
133
+ # Emergency Acquisition:后端固定 Arctic Shift,直接跑即可
134
+ python3 "$VOC" keyword "PLAUD recorder" --pretty
135
+ # ⛔ 没有 --backend 参数。旧文档里的 `--backend arctic-shift` / `--backend reddit-json`
136
+ # 都会被 argparse 拒掉:error: unrecognized arguments: --backend
136
137
  ```
137
138
 
138
- 环境变量 `REDDIT_VOC_BACKEND` 可改缺省后端。
139
+ 后端不可切换:v2.12.28 起固定 Arctic Shift。(旧文档提到的 `REDDIT_VOC_BACKEND` 环境变量脚本里并不存在,设了也没有任何效果。)
139
140
 
140
141
  ## 输出信封新增字段
141
142
 
@@ -1,6 +1,11 @@
1
- # 浏览器低频兜底(JSON 不可用时)
1
+ # 浏览器低频兜底(渲染页也取不到时)
2
2
 
3
- 当 `reddit_voc_volume.py` 返回 `403`、`reddit_returned_html_not_json`、连续 `429` 熔断后,才考虑浏览器兜底。**不是**默认路径。
3
+ > **v2.12.28 起的前提变化**:主路径已不打 reddit.com `.json`(历史走 Arctic Shift,证据走
4
+ > Social Hub / Firecrawl 渲染页)。**2026-09-18 实测 `.json` 对住宅代理同样 403**,所以这里的
5
+ > 触发条件应读作「Hub 与 Firecrawl 渲染页都取不到」,而不是「JSON 挂了」。
6
+
7
+ 当 Arctic / Hub 无法提供所需证据,且 Social Hub / Firecrawl 渲染页返回 `403` / captcha
8
+ 或连续 `429` 熔断后,才考虑浏览器兜底。**不是**默认路径;验证码或登录墙必须停止,不得绕过。
4
9
 
5
10
  ## 原则
6
11
 
@@ -8,7 +13,7 @@
8
13
  - 只读 **首屏/少量可见** 帖子,不自动滚动扫全量
9
14
  - 页面间等待 **≥10–20s**,加随机停顿;不连续刷新同一 URL
10
15
  - 不用登录态绕过私密/受限内容;不处理验证码;不自动换 IP
11
- - 输出必须复用与 JSON 模式相同的 schema,并标记:
16
+ - 输出必须复用 VOC 的结构化 schema,并标记:
12
17
  - `fetch_mode: "browser_fallback"`
13
18
  - `confidence: "sampled"`
14
19
  - `notes`: 说明为浏览器首屏采样,非完整结果
@@ -25,7 +30,7 @@ https://www.reddit.com/r/SUBREDDIT/search/?q=QUERY&restrict_sr=1&sort=relevance&
25
30
  1. 先读 `browser-element-finder` skill 的连接规范(profile + targetId)
26
31
  2. `browser(action="open", url=<search_url>, profile=...)`
27
32
  3. `browser(action="snapshot", ...)` 读取可见帖子标题、链接、score、评论数(若 snapshot 含)
28
- 4. 手动解析为 `items[]`,字段对齐 JSON 模式
33
+ 4. 手动解析为 `items[]`,字段对齐 VOC 输出 schema
29
34
  5. 等待 ≥10s 再开下一页(通常本次任务只开一页)
30
35
 
31
36
  ## 回填 JSON 示例片段
@@ -1,3 +1,5 @@
1
- # Reddit VOC volume — Python dependencies (optional but recommended)
1
+ # Reddit VOC volume — Python dependencies
2
+ # 以下两项仅供未调用的旧 Reddit HTTP 函数使用。主流程不实例化旧客户端,
3
+ # 不读取浏览器 cookie;不安装也不影响当前模式。
2
4
  curl_cffi>=0.7.0
3
5
  browser_cookie3>=0.19.0
@@ -3078,9 +3078,7 @@ def collect_subreddit_metrics(
3078
3078
  subreddit_names: list[str],
3079
3079
  *,
3080
3080
  user_agent: str,
3081
- force_curl: bool,
3082
3081
  tracker: RequestTracker,
3083
- http: RedditHttpClient,
3084
3082
  notes: list[str],
3085
3083
  errors: list[str],
3086
3084
  ) -> list[dict[str, Any]]:
@@ -4008,9 +4006,7 @@ def run_stickies_mode(
4008
4006
  limit: int,
4009
4007
  sleep_sec: float,
4010
4008
  user_agent: str,
4011
- force_curl: bool,
4012
4009
  tracker: RequestTracker,
4013
- http: RedditHttpClient,
4014
4010
  ) -> tuple[list[dict[str, Any]], list[str], list[str]]:
4015
4011
  notes: list[str] = []
4016
4012
  errors: list[str] = []
@@ -4071,9 +4067,7 @@ def run_links_mode(
4071
4067
  *,
4072
4068
  sleep_sec: float,
4073
4069
  user_agent: str,
4074
- force_curl: bool,
4075
4070
  tracker: RequestTracker,
4076
- http: RedditHttpClient,
4077
4071
  fallback: str = "none",
4078
4072
  firecrawl_base_url: str | None = None,
4079
4073
  verify_rules: bool = False,
@@ -4243,7 +4237,7 @@ def run_links_mode(
4243
4237
  else:
4244
4238
  errors.append(f"{url}: {msg}")
4245
4239
  notes.append(
4246
- "JSON fetch failed. To try page fallback, rerun links with "
4240
+ "Arctic lookup failed. To try page fallback, rerun links with "
4247
4241
  "--fallback social-hub, --fallback firecrawl, or --fallback auto."
4248
4242
  )
4249
4243
  except Exception as e:
@@ -4253,7 +4247,7 @@ def run_links_mode(
4253
4247
  else:
4254
4248
  errors.append(f"{url}: {e}")
4255
4249
  notes.append(
4256
- "JSON fetch failed. To try page fallback, rerun links with "
4250
+ "Arctic lookup failed. To try page fallback, rerun links with "
4257
4251
  "--fallback social-hub, --fallback firecrawl, or --fallback auto."
4258
4252
  )
4259
4253
  jitter = sleep_with_jitter(sleep_sec)
@@ -4941,7 +4935,7 @@ def main() -> int:
4941
4935
  if _env_truthy("REDDIT_SOCIAL_HUB_ENABLED")
4942
4936
  else "none"
4943
4937
  ),
4944
- help="Optional page fallback when Reddit JSON fetch fails. auto tries social-hub first, then local Firecrawl.",
4938
+ help="Optional page fallback when the Arctic archive lookup fails or returns nothing. auto tries social-hub first, then local Firecrawl.",
4945
4939
  )
4946
4940
  pl.add_argument(
4947
4941
  "--firecrawl-base-url",
@@ -5346,7 +5340,6 @@ def main() -> int:
5346
5340
 
5347
5341
  tracker = RequestTracker()
5348
5342
  mode_acquisition: dict[str, Any] | None = None
5349
- http = RedditHttpClient(args.user_agent if hasattr(args, "user_agent") else DEFAULT_UA, force_curl=getattr(args, "via_curl", False))
5350
5343
 
5351
5344
  if args.mode in ("keyword", "subreddit"):
5352
5345
  effective_limit, limit_truncated = clamp_limit(args.limit)
@@ -5413,9 +5406,7 @@ def main() -> int:
5413
5406
  subreddit_metrics = collect_subreddit_metrics(
5414
5407
  metric_subreddits,
5415
5408
  user_agent=args.user_agent,
5416
- force_curl=args.via_curl,
5417
5409
  tracker=tracker,
5418
- http=http,
5419
5410
  notes=notes,
5420
5411
  errors=errors,
5421
5412
  )
@@ -5474,9 +5465,7 @@ def main() -> int:
5474
5465
  limit=effective_limit,
5475
5466
  sleep_sec=args.sleep_sec,
5476
5467
  user_agent=args.user_agent,
5477
- force_curl=args.via_curl,
5478
5468
  tracker=tracker,
5479
- http=http,
5480
5469
  )
5481
5470
  notes.extend(local_notes)
5482
5471
  errors.extend(local_errors)
@@ -5488,9 +5477,7 @@ def main() -> int:
5488
5477
  subreddit_metrics = collect_subreddit_metrics(
5489
5478
  subreddits,
5490
5479
  user_agent=args.user_agent,
5491
- force_curl=args.via_curl,
5492
5480
  tracker=tracker,
5493
- http=http,
5494
5481
  notes=notes,
5495
5482
  errors=errors,
5496
5483
  )
@@ -5688,9 +5675,7 @@ def main() -> int:
5688
5675
  urls,
5689
5676
  sleep_sec=args.sleep_sec,
5690
5677
  user_agent=args.user_agent,
5691
- force_curl=args.via_curl,
5692
5678
  tracker=tracker,
5693
- http=http,
5694
5679
  fallback=args.fallback,
5695
5680
  firecrawl_base_url=args.firecrawl_base_url,
5696
5681
  verify_rules=getattr(args, "verify_rules", False),
@@ -5702,9 +5687,7 @@ def main() -> int:
5702
5687
  subreddit_metrics = collect_subreddit_metrics(
5703
5688
  [str(item.get("subreddit") or "") for item in items],
5704
5689
  user_agent=args.user_agent,
5705
- force_curl=args.via_curl,
5706
5690
  tracker=tracker,
5707
- http=http,
5708
5691
  notes=notes,
5709
5692
  errors=errors,
5710
5693
  )