Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
N
news-harvester
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Back End
news-harvester
Commits
757910fe
Commit
757910fe
authored
Jul 30, 2026
by
易初
🖐🏻
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'feat/source-sharing-bundles' into 'main'
Feat/source sharing bundles See merge request
!2
parents
169456dc
6e0d6021
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
50 additions
and
97 deletions
+50
-97
.gitignore
.gitignore
+5
-0
reuters-business.nhsource.json
bundles/reuters-business.nhsource.json
+15
-0
reuters-markets.nhsource.json
bundles/reuters-markets.nhsource.json
+15
-0
reuters-world.nhsource.json
bundles/reuters-world.nhsource.json
+15
-0
reuters-business.md
helpers/reuters-business.md
+0
-31
reuters-markets.md
helpers/reuters-markets.md
+0
-33
reuters-world.md
helpers/reuters-world.md
+0
-33
No files found.
.gitignore
View file @
757910fe
...
...
@@ -12,5 +12,10 @@ node_modules/
*.log
/tmp/
# Local source recipes & fixtures (product files)
# These are installed from shareable bundles (bundles/*.nhsource.json) or
# authored locally — the bundle is the committed unit, not the helper.
helpers/
# IDE / agent workspace files
.zcode/
bundles/reuters-business.nhsource.json
0 → 100644
View file @
757910fe
{
"format"
:
"news-harvester-source"
,
"version"
:
1
,
"exportedAt"
:
"2026-07-30T04:12:38.724Z"
,
"source"
:
{
"id"
:
"reuters-business"
,
"name"
:
"Reuters Business"
,
"homepageUrl"
:
"https://www.reuters.com/business/"
,
"method"
:
"browser"
,
"vaultFolder"
:
"Reuters Business"
},
"files"
:
{
"helpers/reuters-business.md"
:
"---
\n
source: reuters-business
\n
listSelector: 'div[data-testid=
\"
Title
\"
]'
\n
linkSelector: 'a[href]'
\n
urlPattern: 'reuters
\\
.com/.+-
\\
d{4}-
\\
d{2}-
\\
d{2}/?$'
\n
excludeUrlPattern: 'reuters
\\
.com/(podcasts|newsletter)/'
\n
scrollSteps: 3
\n
scrollWaitMs: 2000
\n
waitMs: 15000
\n
validateArticle: true
\n
bodyMinChars: 500
\n
bodySelectors:
\n
- '[data-testid^=
\"
paragraph
\"
]'
\n
- '[class*=
\"
articleBodyContent
\"
] p'
\n
- '[class*=
\"
article-body
\"
] p'
\n
- 'article p'
\n
bodyMinParagraphs: 3
\n
dateSelector: 'time[datetime]'
\n
authorSelector: '[rel=
\"
author
\"
], [class*=
\"
author
\"
] a'
\n
imageSelector: 'img'
\n
imageMinWidth: 200
\n
excludeImage:
\n
- logo
\n
- icon
\n
- avatar
\n
- profile
\n
titleStripSuffix: '
\\
| Reuters$'
\n
maxBodyChars: 15000
\n
---
\n
# Reuters Business 抓取备忘
\n\n
## 列表页链接收集(`/business/`)
\n\n
- **listSelector: `div[data-testid=
\"
Title
\"
]`**。实测全页 20 篇文章链接全部在此容器内(单一容器覆盖全部,无分散问题)。该 data-testid 比 CSS Modules 类名稳定(hash 不变)。
\n
- **urlPattern: `reuters
\\
.com/.+-
\\
d{4}-
\\
d{2}-
\\
d{2}/?$`**。Reuters 文章 URL 以 `-YYYY-MM-DD/` 结尾,日期后缀是极强的文章标识——分类页(`/business/`、`/business/finance/`)无日期后缀。放宽为全站匹配(不限 `/business/`),因为板块页会推荐其他分区的文章(如 `/world/asia-pacific/...`)。
\n
- **excludeUrlPattern** 排除 `/podcasts/`、`/newsletter/`(它们也带日期但非正文报道)。
\n
- `scrollSteps: 3` 触发懒加载拿全当天列表;首屏仅 ~10 篇。
\n\n
## 详情页正文验证
\n\n
`validateArticle: true` 让 fetchPage 用 `og:type` + JSON-LD `@type` + 正文长度剔除分类页。实测信号:
\n
- 文章:`og:type=article`、`@type=NewsArticle`、正文 4000+ 字符
\n
- 分类页 `/business/`:`og:type=website`、`@type=CollectionPage`、正文 0
\n\n
Reuters 的日期后缀 URL 已能区分大部分文章/分类页,validateArticle 作为兜底防止非标准 URL 混入。
\n\n
## 其他
\n\n
- 反爬:headless 会被拦,需 `config.chromium.headless: false`。
\n
- 正文优先 `[data-testid^=
\"
paragraph
\"
]`,旧 `article p` 会被
\"
相关阅读
\"\"
订阅推广
\"
段落污染。
\n
"
}
}
\ No newline at end of file
bundles/reuters-markets.nhsource.json
0 → 100644
View file @
757910fe
{
"format"
:
"news-harvester-source"
,
"version"
:
1
,
"exportedAt"
:
"2026-07-30T04:12:38.760Z"
,
"source"
:
{
"id"
:
"reuters-markets"
,
"name"
:
"Reuters Markets"
,
"homepageUrl"
:
"https://www.reuters.com/markets/"
,
"method"
:
"browser"
,
"vaultFolder"
:
"Reuters Markets"
},
"files"
:
{
"helpers/reuters-markets.md"
:
"---
\n
source: reuters-markets
\n
listSelector: '[data-testid=
\"
MediaStoryCard
\"
], [data-testid=
\"
BasicCard
\"
], [data-testid=
\"
HeroCard
\"
], [data-testid=
\"
HubCard
\"
], [data-testid=
\"
AuthorCard
\"
], [data-testid=
\"
OurColumnists
\"
]'
\n
linkSelector: 'a[href]'
\n
urlPattern: 'reuters
\\
.com/.+-
\\
d{4}-
\\
d{2}-
\\
d{2}/?$'
\n
excludeUrlPattern: 'reuters
\\
.com/(podcasts|newsletter)/'
\n
scrollSteps: 3
\n
scrollWaitMs: 2000
\n
waitMs: 15000
\n
validateArticle: true
\n
bodyMinChars: 500
\n
bodySelectors:
\n
- '[data-testid^=
\"
paragraph
\"
]'
\n
- '[class*=
\"
articleBodyContent
\"
] p'
\n
- '[class*=
\"
article-body
\"
] p'
\n
- 'article p'
\n
bodyMinParagraphs: 3
\n
dateSelector: 'time[datetime]'
\n
authorSelector: '[rel=
\"
author
\"
], [class*=
\"
author
\"
] a'
\n
imageSelector: 'img'
\n
imageMinWidth: 200
\n
excludeImage:
\n
- logo
\n
- icon
\n
- avatar
\n
- profile
\n
titleStripSuffix: '
\\
| Reuters$'
\n
maxBodyChars: 15000
\n
---
\n
# Reuters Markets 抓取备忘
\n\n
## 列表页链接收集(`/markets/`)
\n\n
- **listSelector 用复合 `data-testid` 选择器**:`MediaStoryCard`、`BasicCard`、`HeroCard`、`HubCard`、`AuthorCard`、`OurColumnists` 六类卡片容器。实测全页 20 篇文章链接分散在这六类容器里(`MediaStoryCard` 18 + `BasicCard` 12 + `HeroCard`/`HubCard`/`AuthorCard`/`OurColumnists` 各 2-3,去重后 20)。
\n
- **为什么不用旧 `div.media-story-card-module__placement-container__1ZSB1`**:旧选择器依赖带 hash 的 CSS Modules 类名,hash 随构建变化 → 过期后只匹配 9 篇,漏掉 11 篇。`data-testid` 无 hash,稳定得多。Markets 页面布局与 Business/World 不同(`div[data-testid=
\"
Title
\"
]` 在此页 0 篇),必须用 Markets 专属的复合容器。
\n
- **urlPattern: `reuters
\\
.com/.+-
\\
d{4}-
\\
d{2}-
\\
d{2}/?$`**。Reuters 文章 URL 以 `-YYYY-MM-DD/` 结尾,日期后缀是极强的文章标识——分类页(`/markets/`、`/markets/currencies/`)无日期后缀。放宽为全站匹配,因为 Markets 板块会推荐其他分区文章(如 `/world/asia-pacific/...`、`/business/energy/...`、`/commentary/...`)。
\n
- **excludeUrlPattern** 排除 `/podcasts/`、`/newsletter/`(它们也带日期但非正文报道)。
\n
- `scrollSteps: 3` 触发懒加载拿全当天列表。
\n\n
## 详情页正文验证
\n\n
`validateArticle: true` 让 fetchPage 用 `og:type` + JSON-LD `@type` + 正文长度剔除分类页。实测信号:
\n
- 文章:`og:type=article`、`@type=NewsArticle`、正文 4000+ 字符
\n
- 分类页 `/markets/`:`og:type=website`、正文 0
\n\n
Reuters 的日期后缀 URL 已能区分大部分文章/分类页,validateArticle 作为兜底防止非标准 URL 混入。
\n\n
## 其他
\n\n
- 反爬:headless 会被拦,需 `config.chromium.headless: false`。
\n
- 正文优先 `[data-testid^=
\"
paragraph
\"
]`,旧 `article p` 会被
\"
相关阅读
\"\"
订阅推广
\"
段落污染。
\n
"
}
}
\ No newline at end of file
bundles/reuters-world.nhsource.json
0 → 100644
View file @
757910fe
{
"format"
:
"news-harvester-source"
,
"version"
:
1
,
"exportedAt"
:
"2026-07-30T04:12:38.797Z"
,
"source"
:
{
"id"
:
"reuters-world"
,
"name"
:
"路透社 World"
,
"homepageUrl"
:
"https://www.reuters.com/world/"
,
"method"
:
"browser"
,
"vaultFolder"
:
"路透社 World"
},
"files"
:
{
"helpers/reuters-world.md"
:
"---
\n
source: reuters-world
\n
listSelector: 'div[data-testid=
\"
Title
\"
]'
\n
linkSelector: 'a[href]'
\n
urlPattern: 'reuters
\\
.com/.+-
\\
d{4}-
\\
d{2}-
\\
d{2}/?$'
\n
excludeUrlPattern: 'reuters
\\
.com/(podcasts|newsletter)/'
\n
scrollSteps: 3
\n
scrollWaitMs: 2000
\n
waitMs: 15000
\n
validateArticle: true
\n
bodyMinChars: 500
\n
bodySelectors:
\n
- '[data-testid^=
\"
paragraph
\"
]'
\n
- '[class*=
\"
articleBodyContent
\"
] p'
\n
- '[class*=
\"
article-body
\"
] p'
\n
- 'article p'
\n
bodyMinParagraphs: 3
\n
dateSelector: 'time[datetime]'
\n
authorSelector: '[rel=
\"
author
\"
], [class*=
\"
author
\"
] a'
\n
imageSelector: 'img'
\n
imageMinWidth: 200
\n
excludeImage:
\n
- logo
\n
- icon
\n
- avatar
\n
- profile
\n
titleStripSuffix: '
\\
| Reuters$'
\n
maxBodyChars: 15000
\n
---
\n
# 路透社 World 抓取备忘
\n\n
## 列表页链接收集(`/world/`)
\n\n
- **listSelector: `div[data-testid=
\"
Title
\"
]`**。实测全页 19 篇文章链接全部在此容器内(单一容器覆盖全部,无分散问题)。该 data-testid 比 CSS Modules 类名稳定。
\n
- **urlPattern: `reuters
\\
.com/.+-
\\
d{4}-
\\
d{2}-
\\
d{2}/?$`**。Reuters 文章 URL 以 `-YYYY-MM-DD/` 结尾,日期后缀是极强的文章标识——分类页(`/world/`、`/world/asia-pacific/`)无日期后缀。放宽为全站匹配(不限 `/world/`),因为板块页会推荐其他分区的文章(如 `/business/environment/...`、`/legal/government/...`)。
\n
- **excludeUrlPattern** 排除 `/podcasts/`、`/newsletter/`(它们也带日期但非正文报道)。
\n
- `scrollSteps: 3` 触发懒加载拿全当天列表。
\n\n
## 详情页正文验证
\n\n
`validateArticle: true` 让 fetchPage 用 `og:type` + JSON-LD `@type` + 正文长度剔除分类页。实测信号:
\n
- 文章:`og:type=article`、`@type=NewsArticle`、正文 6000+ 字符
\n
- 分类页 `/world/`:`og:type=website`、正文 0
\n\n
Reuters 的日期后缀 URL 已能区分大部分文章/分类页,validateArticle 作为兜底防止非标准 URL 混入。
\n\n
## 其他
\n\n
- 反爬:headless 会被拦,需 `config.chromium.headless: false`。
\n
- 正文优先 `[data-testid^=
\"
paragraph
\"
]`,旧 `article p` 会被
\"
相关阅读
\"\"
订阅推广
\"
段落污染。
\n
"
}
}
\ No newline at end of file
helpers/reuters-business.md
deleted
100644 → 0
View file @
169456dc
---
source
:
reuters-business
listSelector
:
null
linkSelector
:
'
a[href]'
urlPattern
:
'
reuters\.com/business/(?:[^/]+/)*[\w-]+-\d{4}-\d{2}-\d{2}/'
excludeUrlPattern
:
null
scrollSteps
:
3
scrollWaitMs
:
1500
waitMs
:
12000
bodySelectors
:
-
'
[data-testid^="paragraph"]'
-
'
[class*="article-body"]
p'
-
'
article
p'
bodyMinParagraphs
:
3
dateSelector
:
'
time[datetime]'
authorSelector
:
'
[rel="author"],
[class*="author"]
a'
imageSelector
:
'
img'
imageMinWidth
:
200
excludeImage
:
-
logo
-
icon
-
avatar
-
profile
titleStripSuffix
:
'
'
maxBodyChars
:
15000
---
# Reuters Business 抓取备忘
-
Reuters Business 首页的文章链接位于页面主体
`div[data-testid="Title"]`
,但使用全页扫描配合严格 URL 过滤可避免依赖动态 CSS 类名。
-
文章 URL 形如
`/business/<可选分区>/<slug>-YYYY-MM-DD/`
;日期后缀用于排除导航、专题页和分区页。
-
`scrollSteps: 3`
触发首页懒加载,正文优先使用段落测试选择器。
helpers/reuters-markets.md
deleted
100644 → 0
View file @
169456dc
---
source
:
reuters-markets
listSelector
:
"
div.media-story-card-module__placement-container__1ZSB1"
linkSelector
:
'
a[href]'
urlPattern
:
'
reuters\.com/.+-\d{4}-\d{2}-\d{2}'
excludeUrlPattern
:
null
scrollSteps
:
3
scrollWaitMs
:
2000
waitMs
:
15000
bodySelectors
:
-
'
[data-testid^="paragraph"]'
-
'
[class*="articleBodyContent"]
p'
-
'
[class*="article-body"]
p'
-
'
article
p'
bodyMinParagraphs
:
3
dateSelector
:
'
time[datetime]'
authorSelector
:
'
[rel="author"],
[class*="author"]
a'
imageSelector
:
'
img'
imageMinWidth
:
200
excludeImage
:
-
logo
-
icon
-
avatar
-
profile
titleStripSuffix
:
'
\|
Reuters$'
maxBodyChars
:
15000
---
# Reuters Markets 抓取备忘
-
主文章流容器
`div.media-story-card-module__placement-container__1ZSB1`
实测 6 个候选链接(inspect 自动生成)。
-
urlPattern
`reuters\.com/.+-\d{4}-\d{2}-\d{2}`
由样本 URL 推断,如 preview 漏抓/误抓请手编收紧。
-
首屏可能不全,scrollSteps=0 触发懒加载;反爬严重时调高 waitMs。
-
验证: node scripts/harvest.js reuters-markets 3 --preview(链接为真实文章且 charCount>500 即通过)
\ No newline at end of file
helpers/reuters-world.md
deleted
100644 → 0
View file @
169456dc
---
source
:
reuters-world
listSelector
:
'
div[data-testid="Title"]'
linkSelector
:
'
a[href]'
urlPattern
:
'
www\.reuters\.com/(world|business|markets|technology|sustainability)/.+-\d{4}-\d{2}-\d{2}/'
excludeUrlPattern
:
null
scrollSteps
:
3
scrollWaitMs
:
2000
waitMs
:
15000
bodySelectors
:
-
'
[data-testid^="paragraph"]'
-
'
[class*="articleBodyContent"]
p'
-
'
[class*="article-body"]
p'
-
'
article
p'
bodyMinParagraphs
:
3
dateSelector
:
'
time[datetime]'
authorSelector
:
'
[rel="author"],
[class*="author"]
a'
imageSelector
:
'
img'
imageMinWidth
:
200
excludeImage
:
-
logo
-
icon
-
avatar
-
profile
titleStripSuffix
:
'
'
maxBodyChars
:
15000
---
# 路透社 World 抓取备忘
-
主文章流容器
`li.link-group-module__item__Za3t6`
实测 30 个候选链接(inspect 自动生成)。
-
urlPattern
`www\.reuters\.com/sitemap/.+`
由样本 URL 推断,如 preview 漏抓/误抓请手编收紧。
-
首屏可能不全,scrollSteps=3 触发懒加载;反爬严重时调高 waitMs。
-
验证: node scripts/harvest.js reuters-world 3 --preview(链接为真实文章且 charCount>500 即通过)
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment