Files
Toolbox/dev_test_scripts/debug/debug_dip_eval_sources2.js
yangxiangyuan 6a7a2b089a feat: 新增免费演出雷达工具与定投评估功能,优化周报提醒逻辑
1. 新增免费演出雷达工具:含秀动/猫眼/大麦平台抓取、本地代理鉴权配置
2. 新增建行定投评估模块:四大指数PE-TTM估值与定投档位建议
3. 新增推送告警白名单过滤功能,限制推送指定指数告警
4. 重构周报首页提醒逻辑,移至服务端处理并减少前端请求
5. 新增多套调试探针脚本与单元测试用例
2026-08-04 17:33:14 +08:00

123 lines
6.0 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 探针脚本(第二轮):
* - A股指数 PE 历史:中证指数官网 csindex / 蛋卷基金 djapi
* - 美股指数 PE:Yahoo quoteSummary / CNBC / multpl 历史表格修正
* 用法:node dev_test_scripts/debug/debug_dip_eval_sources2.js
*/
const axios = require('axios')
const UA = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0 Safari/537.36' }
const cut = (s, n = 400) => String(s == null ? '' : s).replace(/\s+/g, ' ').slice(0, n)
// ---------- 1. 中证指数官网(指数官方每日数据,含市盈率) ----------
const probeCsindex = async (code) => {
const url = `https://www.csindex.com.cn/csindex-home/perf/index-perf?indexCode=${code}&startDate=20150701&endDate=20260804`
try {
const res = await axios.get(url, { timeout: 15000, headers: { ...UA, 'Referer': 'https://www.csindex.com.cn/' }, validateStatus: () => true })
const d = res.data && res.data.data
if (!Array.isArray(d) || !d.length) return console.log(` [中证官网 ${code}] 无数据 status=${res.status} body=${cut(JSON.stringify(res.data), 300)}`)
const first = d[0], last = d[d.length - 1]
console.log(` [中证官网 ${code}] OK 记录数=${d.length} 首=${JSON.stringify(first).slice(0, 200)}`)
console.log(` [中证官网 ${code}] 尾=${JSON.stringify(last).slice(0, 200)}`)
} catch (e) {
console.log(` [中证官网 ${code}] 异常: ${e.message}`)
}
}
// ---------- 2. 蛋卷基金指数估值 ----------
const probeDanjuan = async () => {
try {
const res = await axios.get('https://danjuanfunds.com/djapi/index_eva/dj', { timeout: 15000, headers: UA, validateStatus: () => true })
const items = res.data && res.data.data && res.data.data.items
if (!Array.isArray(items)) return console.log(` [蛋卷 index_eva] 无items status=${res.status} body=${cut(JSON.stringify(res.data), 300)}`)
const targets = items.filter(i => /000300|000905|沪深300|中证500|标普|纳/i.test(JSON.stringify(i)))
console.log(` [蛋卷 index_eva] OK 总数=${items.length} 相关=${targets.length}`)
for (const t of targets.slice(0, 8)) {
console.log(` ${cut(JSON.stringify(t), 350)}`)
}
} catch (e) {
console.log(` [蛋卷 index_eva] 异常: ${e.message}`)
}
}
// ---------- 3. Yahoo quoteSummary(trailingPE) ----------
const probeYahoo = async (symbol) => {
const url = `https://query1.finance.yahoo.com/v10/finance/quoteSummary/${encodeURIComponent(symbol)}?modules=summaryDetail,price`
try {
const res = await axios.get(url, { timeout: 15000, headers: UA, validateStatus: () => true })
const r = res.data && res.data.quoteSummary && res.data.quoteSummary.result && res.data.quoteSummary.result[0]
if (!r) return console.log(` [Yahoo ${symbol}] 无数据 status=${res.status} body=${cut(JSON.stringify(res.data), 250)}`)
const sd = r.summaryDetail || {}
const pr = r.price || {}
console.log(` [Yahoo ${symbol}] OK 名称=${pr.shortName} 价格=${pr.regularMarketPrice && pr.regularMarketPrice.raw} trailingPE=${sd.trailingPE && sd.trailingPE.raw} forwardPE=${sd.forwardPE && sd.forwardPE.raw}`)
} catch (e) {
console.log(` [Yahoo ${symbol}] 异常: ${e.message}`)
}
}
// ---------- 4. CNBC quote ----------
const probeCnbc = async () => {
const url = 'https://quote.cnbc.com/quote-html-webservice/restQuote/symbolType/symbol?symbols=.NDX|.INX&requestMethod=itv&noform=1&partnerId=2&fund=1&exthrs=1&output=json'
try {
const res = await axios.get(url, { timeout: 15000, headers: UA, validateStatus: () => true })
const quotes = res.data && res.data.FormattedQuoteResult && res.data.FormattedQuoteResult.formattedQuote
if (!Array.isArray(quotes)) return console.log(` [CNBC] 无数据 status=${res.status} body=${cut(JSON.stringify(res.data), 300)}`)
for (const q of quotes) {
console.log(` [CNBC ${q.symbol}] 名称=${q.name} 价格=${q.last} PE=${q.Pe} pe=${q.pe} 全字段=${cut(Object.keys(q).join(','), 300)}`)
}
} catch (e) {
console.log(` [CNBC] 异常: ${e.message}`)
}
}
// ---------- 5. multpl 历史表格(修正解析) ----------
const probeMultplHistory = async () => {
try {
const res = await axios.get('https://www.multpl.com/s-p-500-pe-ratio/table/by-month', { timeout: 15000, headers: UA, validateStatus: () => true })
const html = String(res.data)
const tbody = html.match(/<tbody>([\s\S]*?)<\/tbody>/)
const rows = tbody ? (tbody[1].match(/<tr>[\s\S]*?<\/tr>/g) || []) : []
console.log(` [multpl 历史] status=${res.status} tbody行数=${rows.length}`)
for (const r of rows.slice(0, 3)) console.log(` ${cut(r, 150)}`)
if (!rows.length) {
const i = html.indexOf('datatable')
console.log(` datatable 附近片段: ${cut(html.slice(Math.max(0, i - 100), i + 500), 550)}`)
}
} catch (e) {
console.log(` [multpl 历史] 异常: ${e.message}`)
}
}
// ---------- 6. 乐咕乐股(公开接口尝试) ----------
const probeLegu = async () => {
try {
const res = await axios.get('https://legulegu.com/api/stockdata/index-basic-info?indexCode=000300', { timeout: 15000, headers: { ...UA, 'Referer': 'https://legulegu.com/stockdata/shanghaiPE' }, validateStatus: () => true })
console.log(` [乐咕 index-basic-info] status=${res.status} body=${cut(JSON.stringify(res.data), 300)}`)
} catch (e) {
console.log(` [乐咕] 异常: ${e.message}`)
}
}
;(async () => {
console.log('=== 中证指数官网(A股指数官方数据,含市盈率) ===')
await probeCsindex('000300')
await probeCsindex('000905')
console.log('\n=== 蛋卷基金指数估值 ===')
await probeDanjuan()
console.log('\n=== Yahoo quoteSummary(美股指数 PE) ===')
await probeYahoo('^GSPC')
await probeYahoo('^NDX')
console.log('\n=== CNBC(美股指数 PE) ===')
await probeCnbc()
console.log('\n=== multpl 标普500 月度PE历史 ===')
await probeMultplHistory()
console.log('\n=== 乐咕乐股 ===')
await probeLegu()
console.log('\n探针结束')
})()