openplanter 0.2.5 → 0.2.7
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/README.md +1 -0
- package/dist/investigation-tools/asic-officer-lookup.d.ts +7 -4
- package/dist/investigation-tools/asic-officer-lookup.d.ts.map +1 -1
- package/dist/investigation-tools/asic-officer-lookup.js +84 -24
- package/dist/investigation-tools/asic-officer-lookup.js.map +1 -1
- package/dist/investigation-tools/asx-reddit-scraper.d.ts +43 -0
- package/dist/investigation-tools/asx-reddit-scraper.d.ts.map +1 -0
- package/dist/investigation-tools/asx-reddit-scraper.js +215 -0
- package/dist/investigation-tools/asx-reddit-scraper.js.map +1 -0
- package/dist/investigation-tools/index.d.ts +5 -0
- package/dist/investigation-tools/index.d.ts.map +1 -1
- package/dist/investigation-tools/index.js +5 -0
- package/dist/investigation-tools/index.js.map +1 -1
- package/dist/investigation-tools/listcorp-scraper.d.ts +41 -0
- package/dist/investigation-tools/listcorp-scraper.d.ts.map +1 -0
- package/dist/investigation-tools/listcorp-scraper.js +204 -0
- package/dist/investigation-tools/listcorp-scraper.js.map +1 -0
- package/dist/investigation-tools/seeking-alpha-asx-scraper.d.ts +46 -0
- package/dist/investigation-tools/seeking-alpha-asx-scraper.d.ts.map +1 -0
- package/dist/investigation-tools/seeking-alpha-asx-scraper.js +184 -0
- package/dist/investigation-tools/seeking-alpha-asx-scraper.js.map +1 -0
- package/dist/investigation-tools/tool-registry.d.ts.map +1 -1
- package/dist/investigation-tools/tool-registry.js +56 -0
- package/dist/investigation-tools/tool-registry.js.map +1 -1
- package/dist/investigation-tools/universal-forum-scraper.d.ts +44 -0
- package/dist/investigation-tools/universal-forum-scraper.d.ts.map +1 -0
- package/dist/investigation-tools/universal-forum-scraper.js +175 -0
- package/dist/investigation-tools/universal-forum-scraper.js.map +1 -0
- package/dist/investigation-tools/yahoo-finance-au-scraper.d.ts +33 -0
- package/dist/investigation-tools/yahoo-finance-au-scraper.d.ts.map +1 -0
- package/dist/investigation-tools/yahoo-finance-au-scraper.js +211 -0
- package/dist/investigation-tools/yahoo-finance-au-scraper.js.map +1 -0
- package/dist/tool-defs.d.ts.map +1 -1
- package/dist/tool-defs.js +197 -0
- package/dist/tool-defs.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* listcorp-scraper.ts — Listcorp ASX Announcements & Comments Scraper
|
|
3
|
+
*
|
|
4
|
+
* Scrapes Listcorp (https://www.listcorp.com) for ASX company announcements
|
|
5
|
+
* and user comments. Flags comments posted before official ASX lodgement as
|
|
6
|
+
* potential pre-announcement buzz signals.
|
|
7
|
+
*/
|
|
8
|
+
import { fetchHtml, normalizeTicker, parseDate, sentimentScore, sentimentLabel, isRumor, isoNow, } from "./shared.js";
|
|
9
|
+
// ── Constants ────────────────────────────────────────────────────
|
|
10
|
+
const LISTCORP_BASE = "https://www.listcorp.com/asx/{ticker}";
|
|
11
|
+
const REQUEST_DELAY_S = 1.5;
|
|
12
|
+
const MAX_TEXT_LEN = 500;
|
|
13
|
+
const ANN_TYPE_KEYWORDS = {
|
|
14
|
+
"3Y": ["appendix 3y", "change of director", "director's interest"],
|
|
15
|
+
"4C": ["appendix 4c", "quarterly cash flow", "quarterly cashflow", "quarterly activities"],
|
|
16
|
+
"3B": ["appendix 3b", "issue of securities", "new issue"],
|
|
17
|
+
};
|
|
18
|
+
// ── Helpers ──────────────────────────────────────────────────────
|
|
19
|
+
function truncate(text, maxLen = MAX_TEXT_LEN) {
|
|
20
|
+
if (text.length <= maxLen)
|
|
21
|
+
return text;
|
|
22
|
+
const cut = text.slice(0, maxLen);
|
|
23
|
+
const sp = cut.lastIndexOf(" ");
|
|
24
|
+
return (sp > 0 ? cut.slice(0, sp) : cut) + "…";
|
|
25
|
+
}
|
|
26
|
+
function classifyAnnType(title) {
|
|
27
|
+
const lower = title.toLowerCase();
|
|
28
|
+
for (const [type, keywords] of Object.entries(ANN_TYPE_KEYWORDS)) {
|
|
29
|
+
if (keywords.some((kw) => lower.includes(kw)))
|
|
30
|
+
return type;
|
|
31
|
+
}
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
function formatDateIso(d) {
|
|
35
|
+
const y = d.getFullYear();
|
|
36
|
+
const m = String(d.getMonth() + 1).padStart(2, "0");
|
|
37
|
+
const day = String(d.getDate()).padStart(2, "0");
|
|
38
|
+
return `${y}-${m}-${day}`;
|
|
39
|
+
}
|
|
40
|
+
function round3(n) {
|
|
41
|
+
return Math.round(n * 1000) / 1000;
|
|
42
|
+
}
|
|
43
|
+
// ── Scraping ─────────────────────────────────────────────────────
|
|
44
|
+
async function fetchListcorpPage(ticker) {
|
|
45
|
+
const url = LISTCORP_BASE.replace("{ticker}", ticker.toLowerCase());
|
|
46
|
+
try {
|
|
47
|
+
return await fetchHtml(url, { delay: REQUEST_DELAY_S });
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
51
|
+
console.error(`[WARN] Listcorp page fetch failed for ${ticker}: ${msg}`);
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
function parseAnnouncements($, cutoff) {
|
|
56
|
+
const anns = [];
|
|
57
|
+
$("table tr, .announcement-row, .ann-item, [class*='announcement']").each((_i, el) => {
|
|
58
|
+
const row = $(el);
|
|
59
|
+
const link = row.find("a").first();
|
|
60
|
+
const title = link.text().trim() || row.find("td").eq(1).text().trim();
|
|
61
|
+
if (!title)
|
|
62
|
+
return;
|
|
63
|
+
const href = link.attr("href") ?? "";
|
|
64
|
+
const dateText = row.find("time").attr("datetime") ??
|
|
65
|
+
row.find("td").first().text().trim() ??
|
|
66
|
+
row.find(".date").text().trim();
|
|
67
|
+
const date = parseDate(dateText);
|
|
68
|
+
if (!date || date < cutoff)
|
|
69
|
+
return;
|
|
70
|
+
const priceSensitive = row.text().toLowerCase().includes("price sensitive") ||
|
|
71
|
+
row.find("[class*='sensitive']").length > 0;
|
|
72
|
+
anns.push({
|
|
73
|
+
title,
|
|
74
|
+
date: formatDateIso(date),
|
|
75
|
+
ann_type: classifyAnnType(title),
|
|
76
|
+
url: href.startsWith("http") ? href : `https://www.listcorp.com${href}`,
|
|
77
|
+
is_price_sensitive: priceSensitive,
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
return anns;
|
|
81
|
+
}
|
|
82
|
+
function parseComments($, announcements, cutoff) {
|
|
83
|
+
const comments = [];
|
|
84
|
+
const earliestAnnDate = announcements.length > 0
|
|
85
|
+
? announcements.reduce((min, a) => (a.date < min ? a.date : min), announcements[0].date)
|
|
86
|
+
: null;
|
|
87
|
+
$(".comment, [class*='comment'], .user-post, .discussion-item").each((_i, el) => {
|
|
88
|
+
const node = $(el);
|
|
89
|
+
const author = node.find(".author, .username, [class*='user']").first().text().trim() || "anonymous";
|
|
90
|
+
const dateText = node.find("time").attr("datetime") ??
|
|
91
|
+
node.find(".date, .timestamp, [class*='date']").first().text().trim();
|
|
92
|
+
const text = truncate(node.find(".body, .text, .content, [class*='body']").first().text().trim() ||
|
|
93
|
+
node.text().trim());
|
|
94
|
+
if (!text)
|
|
95
|
+
return;
|
|
96
|
+
const date = parseDate(dateText);
|
|
97
|
+
if (!date || date < cutoff)
|
|
98
|
+
return;
|
|
99
|
+
const dateStr = formatDateIso(date);
|
|
100
|
+
const score = sentimentScore(text);
|
|
101
|
+
let preLodgement = false;
|
|
102
|
+
let relatedAnn = null;
|
|
103
|
+
for (const ann of announcements) {
|
|
104
|
+
if (dateStr < ann.date) {
|
|
105
|
+
preLodgement = true;
|
|
106
|
+
relatedAnn = ann.title;
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
comments.push({
|
|
111
|
+
author,
|
|
112
|
+
date: dateStr,
|
|
113
|
+
text,
|
|
114
|
+
sentiment_score: round3(score),
|
|
115
|
+
sentiment_label: sentimentLabel(score),
|
|
116
|
+
is_rumor: isRumor(text),
|
|
117
|
+
pre_lodgement_flag: preLodgement,
|
|
118
|
+
related_announcement: relatedAnn,
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
return comments;
|
|
122
|
+
}
|
|
123
|
+
// ── Main ─────────────────────────────────────────────────────────
|
|
124
|
+
export async function scrapeListcorp(opts) {
|
|
125
|
+
const ticker = normalizeTicker(opts.ticker);
|
|
126
|
+
const days = opts.days ?? 30;
|
|
127
|
+
const annTypeFilter = opts.ann_types ?? null;
|
|
128
|
+
const cutoff = new Date(Date.now() - days * 24 * 60 * 60 * 1000);
|
|
129
|
+
const $ = await fetchListcorpPage(ticker);
|
|
130
|
+
let announcements = [];
|
|
131
|
+
let comments = [];
|
|
132
|
+
if ($) {
|
|
133
|
+
announcements = parseAnnouncements($, cutoff);
|
|
134
|
+
if (annTypeFilter && annTypeFilter.length > 0) {
|
|
135
|
+
const filterSet = new Set(annTypeFilter.map((t) => t.toUpperCase()));
|
|
136
|
+
announcements = announcements.filter((a) => a.ann_type !== null && filterSet.has(a.ann_type));
|
|
137
|
+
}
|
|
138
|
+
comments = parseComments($, announcements, cutoff);
|
|
139
|
+
}
|
|
140
|
+
const scores = comments.map((c) => c.sentiment_score);
|
|
141
|
+
const overall = scores.length > 0
|
|
142
|
+
? round3(scores.reduce((a, b) => a + b, 0) / scores.length)
|
|
143
|
+
: 0;
|
|
144
|
+
return {
|
|
145
|
+
ticker,
|
|
146
|
+
scraped_at: isoNow(),
|
|
147
|
+
period_days: days,
|
|
148
|
+
announcements,
|
|
149
|
+
comments,
|
|
150
|
+
pre_lodgement_comments: comments.filter((c) => c.pre_lodgement_flag).length,
|
|
151
|
+
total_comments: comments.length,
|
|
152
|
+
overall_sentiment: overall,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
export function sampleData(ticker) {
|
|
156
|
+
const t = normalizeTicker(ticker);
|
|
157
|
+
return {
|
|
158
|
+
ticker: t,
|
|
159
|
+
scraped_at: isoNow(),
|
|
160
|
+
period_days: 30,
|
|
161
|
+
announcements: [
|
|
162
|
+
{
|
|
163
|
+
title: "Appendix 4C - Quarterly Cashflow Report",
|
|
164
|
+
date: "2026-02-15",
|
|
165
|
+
ann_type: "4C",
|
|
166
|
+
url: `https://www.listcorp.com/asx/${t.toLowerCase()}/announcements/4c-report`,
|
|
167
|
+
is_price_sensitive: false,
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
title: "Appendix 3Y - Change of Director's Interest Notice",
|
|
171
|
+
date: "2026-02-10",
|
|
172
|
+
ann_type: "3Y",
|
|
173
|
+
url: `https://www.listcorp.com/asx/${t.toLowerCase()}/announcements/3y-notice`,
|
|
174
|
+
is_price_sensitive: true,
|
|
175
|
+
},
|
|
176
|
+
],
|
|
177
|
+
comments: [
|
|
178
|
+
{
|
|
179
|
+
author: "eagleeye",
|
|
180
|
+
date: "2026-02-09",
|
|
181
|
+
text: "Something big is coming for this stock. Insider sources say announcement imminent.",
|
|
182
|
+
sentiment_score: 0.667,
|
|
183
|
+
sentiment_label: "bullish",
|
|
184
|
+
is_rumor: true,
|
|
185
|
+
pre_lodgement_flag: true,
|
|
186
|
+
related_announcement: "Appendix 3Y - Change of Director's Interest Notice",
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
author: "analyst42",
|
|
190
|
+
date: "2026-02-16",
|
|
191
|
+
text: "4C looks solid. Cash burn rate improving quarter over quarter.",
|
|
192
|
+
sentiment_score: 0.333,
|
|
193
|
+
sentiment_label: "bullish",
|
|
194
|
+
is_rumor: false,
|
|
195
|
+
pre_lodgement_flag: false,
|
|
196
|
+
related_announcement: null,
|
|
197
|
+
},
|
|
198
|
+
],
|
|
199
|
+
pre_lodgement_comments: 1,
|
|
200
|
+
total_comments: 2,
|
|
201
|
+
overall_sentiment: 0.5,
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
//# sourceMappingURL=listcorp-scraper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"listcorp-scraper.js","sourceRoot":"","sources":["../../src/investigation-tools/listcorp-scraper.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* seeking-alpha-asx-scraper.ts — Seeking Alpha ASX Article & Comment Scraper
|
|
3
|
+
*
|
|
4
|
+
* Scrapes Seeking Alpha for articles and comments about ASX-listed
|
|
5
|
+
* companies. Extracts sentiment, rumor flags, and author credibility data.
|
|
6
|
+
*/
|
|
7
|
+
export interface SeekingAlphaArticle {
|
|
8
|
+
article_id: string;
|
|
9
|
+
title: string;
|
|
10
|
+
date: string;
|
|
11
|
+
author: string;
|
|
12
|
+
summary: string;
|
|
13
|
+
sentiment_score: number;
|
|
14
|
+
sentiment_label: string;
|
|
15
|
+
is_rumor: boolean;
|
|
16
|
+
url: string;
|
|
17
|
+
comment_count: number;
|
|
18
|
+
}
|
|
19
|
+
export interface SeekingAlphaComment {
|
|
20
|
+
comment_id: string;
|
|
21
|
+
date: string;
|
|
22
|
+
author: string;
|
|
23
|
+
text: string;
|
|
24
|
+
sentiment_score: number;
|
|
25
|
+
sentiment_label: string;
|
|
26
|
+
is_rumor: boolean;
|
|
27
|
+
likes: number;
|
|
28
|
+
}
|
|
29
|
+
export interface SeekingAlphaResult {
|
|
30
|
+
ticker: string;
|
|
31
|
+
scraped_at: string;
|
|
32
|
+
period_days: number;
|
|
33
|
+
total_articles: number;
|
|
34
|
+
total_comments: number;
|
|
35
|
+
articles: SeekingAlphaArticle[];
|
|
36
|
+
comments: SeekingAlphaComment[];
|
|
37
|
+
overall_sentiment: number;
|
|
38
|
+
rumor_count: number;
|
|
39
|
+
}
|
|
40
|
+
export declare function scrapeSeekingAlphaAsx(opts: {
|
|
41
|
+
ticker: string;
|
|
42
|
+
days?: number;
|
|
43
|
+
pages?: number;
|
|
44
|
+
}): Promise<SeekingAlphaResult>;
|
|
45
|
+
export declare function sampleData(ticker: string): SeekingAlphaResult;
|
|
46
|
+
//# sourceMappingURL=seeking-alpha-asx-scraper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seeking-alpha-asx-scraper.d.ts","sourceRoot":"","sources":["../../src/investigation-tools/seeking-alpha-asx-scraper.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAyBH,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,OAAO,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAChC,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAChC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;CACrB;AAyGD,wBAAsB,qBAAqB,CAAC,IAAI,EAAE;IAChD,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CA8C9B;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,kBAAkB,CAiD7D"}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* seeking-alpha-asx-scraper.ts — Seeking Alpha ASX Article & Comment Scraper
|
|
3
|
+
*
|
|
4
|
+
* Scrapes Seeking Alpha for articles and comments about ASX-listed
|
|
5
|
+
* companies. Extracts sentiment, rumor flags, and author credibility data.
|
|
6
|
+
*/
|
|
7
|
+
import { fetchHtml, normalizeTicker, sentimentScore, sentimentLabel, isRumor, isoNow, } from "./shared.js";
|
|
8
|
+
// ── Constants ────────────────────────────────────────────────────
|
|
9
|
+
const SA_ANALYSIS_URL = "https://seekingalpha.com/symbol/{ticker}.AX/analysis";
|
|
10
|
+
const SA_NEWS_URL = "https://seekingalpha.com/symbol/{ticker}.AX/news";
|
|
11
|
+
const REQUEST_DELAY_S = 2.5;
|
|
12
|
+
const MAX_TEXT_LEN = 600;
|
|
13
|
+
// ── Helpers ──────────────────────────────────────────────────────
|
|
14
|
+
function truncate(text, maxLen = MAX_TEXT_LEN) {
|
|
15
|
+
if (text.length <= maxLen)
|
|
16
|
+
return text;
|
|
17
|
+
const cut = text.slice(0, maxLen);
|
|
18
|
+
const sp = cut.lastIndexOf(" ");
|
|
19
|
+
return (sp > 0 ? cut.slice(0, sp) : cut) + "…";
|
|
20
|
+
}
|
|
21
|
+
function round3(n) {
|
|
22
|
+
return Math.round(n * 1000) / 1000;
|
|
23
|
+
}
|
|
24
|
+
function formatDateIso(d) {
|
|
25
|
+
const y = d.getFullYear();
|
|
26
|
+
const m = String(d.getMonth() + 1).padStart(2, "0");
|
|
27
|
+
const day = String(d.getDate()).padStart(2, "0");
|
|
28
|
+
return `${y}-${m}-${day}`;
|
|
29
|
+
}
|
|
30
|
+
// ── Scraping ─────────────────────────────────────────────────────
|
|
31
|
+
async function fetchSaPage(url) {
|
|
32
|
+
try {
|
|
33
|
+
return await fetchHtml(url, { delay: REQUEST_DELAY_S });
|
|
34
|
+
}
|
|
35
|
+
catch (err) {
|
|
36
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
37
|
+
console.error(`[WARN] Seeking Alpha page fetch failed: ${msg}`);
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function parseArticles($, ticker, cutoff) {
|
|
42
|
+
const articles = [];
|
|
43
|
+
const articleSelectors = [
|
|
44
|
+
"article[data-test-id='post-list-item']",
|
|
45
|
+
"[data-test-id='post-list'] article",
|
|
46
|
+
".symbol-page-article",
|
|
47
|
+
"article",
|
|
48
|
+
];
|
|
49
|
+
for (const selector of articleSelectors) {
|
|
50
|
+
const items = $(selector);
|
|
51
|
+
if (items.length === 0)
|
|
52
|
+
continue;
|
|
53
|
+
items.each((i, el) => {
|
|
54
|
+
const node = $(el);
|
|
55
|
+
const link = node.find("a[href*='/article/']").first();
|
|
56
|
+
const title = link.text().trim() || node.find("h3, h2").first().text().trim();
|
|
57
|
+
if (!title)
|
|
58
|
+
return;
|
|
59
|
+
const href = link.attr("href") ?? "";
|
|
60
|
+
const dateText = node.find("time").attr("datetime") ??
|
|
61
|
+
node.find("[data-test-id='post-list-date']").text().trim() ??
|
|
62
|
+
node.find("span.date").text().trim();
|
|
63
|
+
const date = dateText ? new Date(dateText) : null;
|
|
64
|
+
if (date && date < cutoff)
|
|
65
|
+
return;
|
|
66
|
+
const author = node.find("a[href*='/author/']").text().trim() ||
|
|
67
|
+
node.find(".author-name").text().trim() ||
|
|
68
|
+
"unknown";
|
|
69
|
+
const summary = truncate(node.find("p").first().text().trim() || title);
|
|
70
|
+
const commentsText = node.find("[data-test-id='post-list-comments']").text().trim() ||
|
|
71
|
+
node.find(".comments-count").text().trim();
|
|
72
|
+
const commentCount = parseInt(commentsText, 10) || 0;
|
|
73
|
+
const score = sentimentScore(`${title} ${summary}`);
|
|
74
|
+
articles.push({
|
|
75
|
+
article_id: `sa-${ticker}-${i}`,
|
|
76
|
+
title,
|
|
77
|
+
date: date ? formatDateIso(date) : isoNow().slice(0, 10),
|
|
78
|
+
author,
|
|
79
|
+
summary,
|
|
80
|
+
sentiment_score: round3(score),
|
|
81
|
+
sentiment_label: sentimentLabel(score),
|
|
82
|
+
is_rumor: isRumor(`${title} ${summary}`),
|
|
83
|
+
url: href.startsWith("http") ? href : `https://seekingalpha.com${href}`,
|
|
84
|
+
comment_count: commentCount,
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
if (articles.length > 0)
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
return articles;
|
|
91
|
+
}
|
|
92
|
+
// ── Main ─────────────────────────────────────────────────────────
|
|
93
|
+
export async function scrapeSeekingAlphaAsx(opts) {
|
|
94
|
+
const ticker = normalizeTicker(opts.ticker);
|
|
95
|
+
const days = opts.days ?? 30;
|
|
96
|
+
const cutoff = new Date(Date.now() - days * 24 * 60 * 60 * 1000);
|
|
97
|
+
const allArticles = [];
|
|
98
|
+
const allComments = [];
|
|
99
|
+
for (const urlTemplate of [SA_ANALYSIS_URL, SA_NEWS_URL]) {
|
|
100
|
+
const url = urlTemplate.replace("{ticker}", ticker);
|
|
101
|
+
const $ = await fetchSaPage(url);
|
|
102
|
+
if (!$)
|
|
103
|
+
continue;
|
|
104
|
+
const articles = parseArticles($, ticker, cutoff);
|
|
105
|
+
allArticles.push(...articles);
|
|
106
|
+
}
|
|
107
|
+
const seen = new Set();
|
|
108
|
+
const uniqueArticles = allArticles.filter((a) => {
|
|
109
|
+
if (seen.has(a.title))
|
|
110
|
+
return false;
|
|
111
|
+
seen.add(a.title);
|
|
112
|
+
return true;
|
|
113
|
+
});
|
|
114
|
+
const allScores = [
|
|
115
|
+
...uniqueArticles.map((a) => a.sentiment_score),
|
|
116
|
+
...allComments.map((c) => c.sentiment_score),
|
|
117
|
+
];
|
|
118
|
+
const overall = allScores.length > 0
|
|
119
|
+
? round3(allScores.reduce((a, b) => a + b, 0) / allScores.length)
|
|
120
|
+
: 0;
|
|
121
|
+
return {
|
|
122
|
+
ticker,
|
|
123
|
+
scraped_at: isoNow(),
|
|
124
|
+
period_days: days,
|
|
125
|
+
total_articles: uniqueArticles.length,
|
|
126
|
+
total_comments: allComments.length,
|
|
127
|
+
articles: uniqueArticles,
|
|
128
|
+
comments: allComments,
|
|
129
|
+
overall_sentiment: overall,
|
|
130
|
+
rumor_count: uniqueArticles.filter((a) => a.is_rumor).length +
|
|
131
|
+
allComments.filter((c) => c.is_rumor).length,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
export function sampleData(ticker) {
|
|
135
|
+
const t = normalizeTicker(ticker);
|
|
136
|
+
return {
|
|
137
|
+
ticker: t,
|
|
138
|
+
scraped_at: isoNow(),
|
|
139
|
+
period_days: 30,
|
|
140
|
+
total_articles: 2,
|
|
141
|
+
total_comments: 1,
|
|
142
|
+
articles: [
|
|
143
|
+
{
|
|
144
|
+
article_id: "sa-1",
|
|
145
|
+
title: `${t}: Undervalued Gem Or Value Trap?`,
|
|
146
|
+
date: "2026-02-18",
|
|
147
|
+
author: "AussieValueHunter",
|
|
148
|
+
summary: `Deep dive into ${t}'s fundamentals suggests the stock is undervalued relative to peers. Catalyst expected from upcoming quarterly report.`,
|
|
149
|
+
sentiment_score: 0.333,
|
|
150
|
+
sentiment_label: "bullish",
|
|
151
|
+
is_rumor: false,
|
|
152
|
+
url: `https://seekingalpha.com/article/${t.toLowerCase()}-undervalued-gem`,
|
|
153
|
+
comment_count: 14,
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
article_id: "sa-2",
|
|
157
|
+
title: `Why Insiders Are Selling ${t} — Red Flags Ahead`,
|
|
158
|
+
date: "2026-02-12",
|
|
159
|
+
author: "ShortSideResearch",
|
|
160
|
+
summary: `Multiple directors have disclosed share disposals. Speculation about leaked internal projections. Bearish outlook.`,
|
|
161
|
+
sentiment_score: -0.667,
|
|
162
|
+
sentiment_label: "bearish",
|
|
163
|
+
is_rumor: true,
|
|
164
|
+
url: `https://seekingalpha.com/article/${t.toLowerCase()}-insider-selling`,
|
|
165
|
+
comment_count: 31,
|
|
166
|
+
},
|
|
167
|
+
],
|
|
168
|
+
comments: [
|
|
169
|
+
{
|
|
170
|
+
comment_id: "sc-1",
|
|
171
|
+
date: "2026-02-19",
|
|
172
|
+
author: "deep_value_au",
|
|
173
|
+
text: "Great analysis. The insider selling pattern looks like a classic exit before bad news drops.",
|
|
174
|
+
sentiment_score: -0.333,
|
|
175
|
+
sentiment_label: "bearish",
|
|
176
|
+
is_rumor: false,
|
|
177
|
+
likes: 8,
|
|
178
|
+
},
|
|
179
|
+
],
|
|
180
|
+
overall_sentiment: -0.222,
|
|
181
|
+
rumor_count: 1,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
//# sourceMappingURL=seeking-alpha-asx-scraper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seeking-alpha-asx-scraper.js","sourceRoot":"","sources":["../../src/investigation-tools/seeking-alpha-asx-scraper.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-registry.d.ts","sourceRoot":"","sources":["../../src/investigation-tools/tool-registry.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"tool-registry.d.ts","sourceRoot":"","sources":["../../src/investigation-tools/tool-registry.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAsCH,KAAK,WAAW,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;AAMjF,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAi1BxD,CAAC;AAEF,eAAO,MAAM,aAAa,aAAyC,CAAC;AAEpE,wBAAsB,SAAS,CAC7B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,OAAO,CAAC,MAAM,CAAC,CAUjB"}
|
|
@@ -32,6 +32,11 @@ import * as insiderScorer from "./insider-suspicion-scorer.js";
|
|
|
32
32
|
import * as multiForum from "./multi-forum-scraper.js";
|
|
33
33
|
import * as priceFetcher from "./price-fetcher.js";
|
|
34
34
|
import * as timelineLinker from "./timeline-linker.js";
|
|
35
|
+
import * as asxReddit from "./asx-reddit-scraper.js";
|
|
36
|
+
import * as listcorp from "./listcorp-scraper.js";
|
|
37
|
+
import * as yahooFinanceAu from "./yahoo-finance-au-scraper.js";
|
|
38
|
+
import * as seekingAlphaAsx from "./seeking-alpha-asx-scraper.js";
|
|
39
|
+
import * as universalForum from "./universal-forum-scraper.js";
|
|
35
40
|
import * as volumeScanner from "./volume-scanner.js";
|
|
36
41
|
import { isoNow } from "./shared.js";
|
|
37
42
|
function jsonResult(result) {
|
|
@@ -667,6 +672,57 @@ export const TS_TOOL_REGISTRY = {
|
|
|
667
672
|
const reportDates = (args.report_dates ?? []);
|
|
668
673
|
return jsonResult(await volumeScanner.scanTickers(tickers, days, threshold, reportDates));
|
|
669
674
|
},
|
|
675
|
+
// ── Forum & Community Scrapers ─────────────────────────────────
|
|
676
|
+
asx_reddit_scraper: async (args) => {
|
|
677
|
+
if (args.test)
|
|
678
|
+
return jsonResult(asxReddit.sampleData(String(args.ticker ?? "BHP")));
|
|
679
|
+
return jsonResult(await asxReddit.scrapeAsxReddit({
|
|
680
|
+
ticker: String(args.ticker ?? ""),
|
|
681
|
+
subreddits: args.subreddits,
|
|
682
|
+
days: args.days != null ? Number(args.days) : undefined,
|
|
683
|
+
keywords: args.keywords,
|
|
684
|
+
}));
|
|
685
|
+
},
|
|
686
|
+
listcorp_scraper: async (args) => {
|
|
687
|
+
if (args.test)
|
|
688
|
+
return jsonResult(listcorp.sampleData(String(args.ticker ?? "BHP")));
|
|
689
|
+
return jsonResult(await listcorp.scrapeListcorp({
|
|
690
|
+
ticker: String(args.ticker ?? ""),
|
|
691
|
+
days: args.days != null ? Number(args.days) : undefined,
|
|
692
|
+
ann_types: args.ann_types,
|
|
693
|
+
}));
|
|
694
|
+
},
|
|
695
|
+
yahoo_finance_au_scraper: async (args) => {
|
|
696
|
+
if (args.test)
|
|
697
|
+
return jsonResult(yahooFinanceAu.sampleData(String(args.ticker ?? "BHP")));
|
|
698
|
+
return jsonResult(await yahooFinanceAu.scrapeYahooFinanceAu({
|
|
699
|
+
ticker: String(args.ticker ?? ""),
|
|
700
|
+
days: args.days != null ? Number(args.days) : undefined,
|
|
701
|
+
pages: args.pages != null ? Number(args.pages) : undefined,
|
|
702
|
+
}));
|
|
703
|
+
},
|
|
704
|
+
seeking_alpha_asx_scraper: async (args) => {
|
|
705
|
+
if (args.test)
|
|
706
|
+
return jsonResult(seekingAlphaAsx.sampleData(String(args.ticker ?? "BHP")));
|
|
707
|
+
return jsonResult(await seekingAlphaAsx.scrapeSeekingAlphaAsx({
|
|
708
|
+
ticker: String(args.ticker ?? ""),
|
|
709
|
+
days: args.days != null ? Number(args.days) : undefined,
|
|
710
|
+
pages: args.pages != null ? Number(args.pages) : undefined,
|
|
711
|
+
}));
|
|
712
|
+
},
|
|
713
|
+
universal_forum_scraper: async (args) => {
|
|
714
|
+
const baseUrl = String(args.base_url ?? "");
|
|
715
|
+
if (args.test)
|
|
716
|
+
return jsonResult(universalForum.sampleData(baseUrl, args.ticker));
|
|
717
|
+
const selectors = (args.css_selectors ?? {});
|
|
718
|
+
return jsonResult(await universalForum.scrapeUniversalForum({
|
|
719
|
+
base_url: baseUrl,
|
|
720
|
+
css_selectors: selectors,
|
|
721
|
+
ticker: args.ticker,
|
|
722
|
+
max_pages: args.max_pages != null ? Number(args.max_pages) : undefined,
|
|
723
|
+
days: args.days != null ? Number(args.days) : undefined,
|
|
724
|
+
}));
|
|
725
|
+
},
|
|
670
726
|
};
|
|
671
727
|
export const TS_TOOL_NAMES = new Set(Object.keys(TS_TOOL_REGISTRY));
|
|
672
728
|
export async function runTsTool(name, args) {
|