6a7a2b089a
1. 新增免费演出雷达工具:含秀动/猫眼/大麦平台抓取、本地代理鉴权配置 2. 新增建行定投评估模块:四大指数PE-TTM估值与定投档位建议 3. 新增推送告警白名单过滤功能,限制推送指定指数告警 4. 重构周报首页提醒逻辑,移至服务端处理并减少前端请求 5. 新增多套调试探针脚本与单元测试用例
123 lines
6.0 KiB
JavaScript
123 lines
6.0 KiB
JavaScript
/**
|
||
* 探针脚本(第二轮):
|
||
* - 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探针结束')
|
||
})()
|