mirror of
https://github.com/DIYgod/RSSHub.git
synced 2026-09-01 14:57:14 +08:00
feat(route/eastmoney): 增加支持东方财富类型为个股研报的研究报告 (#16526)
* feat(route/eastmoney): 增加支持东方财富类型为个股研报的研究报告 * feat(route/eastmoney): 个股研报标题增加公司名 * feat(route/eastmoney): 东方财富个股研报获取收益/市盈率 方法合并
This commit is contained in:
@@ -1,8 +1,14 @@
|
||||
import { Route } from '@/types';
|
||||
import { getCurrentPath } from '@/utils/helpers';
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { load } from 'cheerio';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
import { art } from '@/utils/render';
|
||||
import path from 'node:path';
|
||||
import { getRatingChangeStr, getEpsOrPeStr } from '../utils';
|
||||
|
||||
const __dirname = getCurrentPath(import.meta.url);
|
||||
|
||||
export const route: Route = {
|
||||
path: '/report/:category',
|
||||
@@ -25,9 +31,9 @@ export const route: Route = {
|
||||
name: '研究报告',
|
||||
maintainers: ['syzq'],
|
||||
handler,
|
||||
description: `| 策略报告 | 宏观研究 | 券商晨报 | 行业研究 |
|
||||
| -------------- | ----------- | ------------ | -------- |
|
||||
| strategyreport | macresearch | brokerreport | industry |`,
|
||||
description: `| 策略报告 | 宏观研究 | 券商晨报 | 行业研究 | 个股研报 |
|
||||
| -------------- | ----------- | ------------ | -------- | -------- |
|
||||
| strategyreport | macresearch | brokerreport | industry | stock |`,
|
||||
};
|
||||
|
||||
async function handler(ctx) {
|
||||
@@ -39,12 +45,14 @@ async function handler(ctx) {
|
||||
industry: '行业研报',
|
||||
macresearch: '宏观研究',
|
||||
strategyreport: '策略报告',
|
||||
stock: '个股研报',
|
||||
};
|
||||
const linkType = {
|
||||
brokerreport: 'zw_brokerreport',
|
||||
industry: 'zw_industry',
|
||||
macresearch: 'zw_macresearch',
|
||||
strategyreport: 'zw_strategy',
|
||||
stock: 'info',
|
||||
};
|
||||
|
||||
const res = await got(`${baseUrl}/report/${category}`);
|
||||
@@ -56,27 +64,67 @@ async function handler(ctx) {
|
||||
.match(/var initdata(.=?)(.*?);/)[2]
|
||||
);
|
||||
|
||||
const list = initData.data.map((item) => ({
|
||||
title: `[${item.orgSName}]${item.title}`,
|
||||
link: `${baseUrl}/report/${linkType[category]}.jshtml?encodeUrl=${item.encodeUrl}`,
|
||||
pubDate: parseDate(item.publishDate),
|
||||
author: item.researcher,
|
||||
}));
|
||||
const list = initData.data.map((item) => {
|
||||
const stockName = category === 'stock' ? `[${item.stockName}]` : '';
|
||||
return {
|
||||
title: `[${item.orgSName}]${stockName}${item.title}`,
|
||||
link: `${baseUrl}/report/${linkType[category]}` + (category === 'stock' ? `/${item.infoCode}.html` : `.jshtml?encodeUrl=${item.encodeUrl}`),
|
||||
pubDate: parseDate(item.publishDate),
|
||||
author: item.researcher,
|
||||
originItem: item, // temp use
|
||||
};
|
||||
});
|
||||
|
||||
const items = await Promise.all(
|
||||
list.map((item) =>
|
||||
cache.tryGet(item.link, async () => {
|
||||
list.map((item) => {
|
||||
const tempOriginItem = item.originItem;
|
||||
delete item.originItem; // temp use
|
||||
|
||||
return cache.tryGet(item.link, async () => {
|
||||
try {
|
||||
const { data: response } = await got(item.link);
|
||||
const $ = load(response);
|
||||
item.link = $('.pdf-link').attr('href');
|
||||
item.description = $('.ctx-content').text();
|
||||
|
||||
if (category === 'stock') {
|
||||
const { title, stockName, stockCode, emRatingName, ratingChange, orgSName, indvInduName } = tempOriginItem;
|
||||
const ratingChangeStr = getRatingChangeStr(ratingChange);
|
||||
const currentYear = new Date().getFullYear();
|
||||
const nextYear = currentYear + 1;
|
||||
const description = $('.newsContent').html();
|
||||
const enclosureUrl = $('#ContentBody .rightlab').attr('href');
|
||||
const predictThisYearEps = getEpsOrPeStr(tempOriginItem.predictThisYearEps, 3);
|
||||
const predictThisYearPe = getEpsOrPeStr(tempOriginItem.predictThisYearPe, 2);
|
||||
const predictNextYearEps = getEpsOrPeStr(tempOriginItem.predictNextYearEps, 3);
|
||||
const predictNextYearPe = getEpsOrPeStr(tempOriginItem.predictNextYearPe, 2);
|
||||
|
||||
item.enclosure_url = enclosureUrl;
|
||||
item.description = art(path.join(__dirname, '../templates/stock_description.art'), {
|
||||
title,
|
||||
stockName,
|
||||
stockCode,
|
||||
emRatingName,
|
||||
ratingChangeStr,
|
||||
description,
|
||||
orgSName,
|
||||
predictThisYearEps,
|
||||
predictThisYearPe,
|
||||
predictNextYearEps,
|
||||
predictNextYearPe,
|
||||
indvInduName,
|
||||
currentYear,
|
||||
nextYear,
|
||||
enclosureUrl,
|
||||
});
|
||||
} else {
|
||||
item.link = $('.pdf-link').attr('href');
|
||||
item.description = $('.ctx-content').text();
|
||||
}
|
||||
return item;
|
||||
} catch {
|
||||
return item;
|
||||
}
|
||||
})
|
||||
)
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th rowspan="2">股票代码</th>
|
||||
<th rowspan="2">股票简称</th>
|
||||
<th rowspan="2">报告名称</th>
|
||||
<th rowspan="2">东财评级</th>
|
||||
<th rowspan="2">评级变动</th>
|
||||
<th colspan="2">{{ currentYear }}盈利预测</th>
|
||||
<th colspan="2">{{ nextYear }}盈利预测</th>
|
||||
<th rowspan="2">行业</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>收益</th>
|
||||
<th>市盈率</th>
|
||||
<th>收益</th>
|
||||
<th>市盈率</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ stockCode }}</td>
|
||||
<td>{{ stockName }}</td>
|
||||
<td><a href="{{ enclosureUrl }}">{{ title }}</a></td>
|
||||
<td>{{ emRatingName }}</td>
|
||||
<td>{{ ratingChangeStr }}</td>
|
||||
<td>{{ predictThisYearEps }}</td>
|
||||
<td>{{ predictThisYearPe }}</td>
|
||||
<td>{{ predictNextYearEps }}</td>
|
||||
<td>{{ predictNextYearPe }}</td>
|
||||
<td>{{ indvInduName }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div>
|
||||
{{@ description }}
|
||||
</div>
|
||||
@@ -0,0 +1,35 @@
|
||||
function getRatingChangeStr(ratingChange) {
|
||||
let ratingChangeName = '';
|
||||
switch (String(ratingChange)) {
|
||||
case '0':
|
||||
ratingChangeName = '调高';
|
||||
break;
|
||||
case '1':
|
||||
ratingChangeName = '调低';
|
||||
break;
|
||||
case '2':
|
||||
ratingChangeName = '首次';
|
||||
break;
|
||||
case '3':
|
||||
ratingChangeName = '维持';
|
||||
break;
|
||||
case '4':
|
||||
ratingChangeName = '无';
|
||||
break;
|
||||
default:
|
||||
ratingChangeName = '-';
|
||||
break;
|
||||
}
|
||||
return ratingChangeName;
|
||||
}
|
||||
|
||||
// 按照东方财富的 js 规则:收益是保留三位小数,市盈率是保留两位小数
|
||||
function getEpsOrPeStr(epsOrPe, keepDecimal) {
|
||||
let EpsOrPeStr = '';
|
||||
if (epsOrPe !== undefined) {
|
||||
EpsOrPeStr = epsOrPe === '' ? '' : Number(epsOrPe).toFixed(keepDecimal);
|
||||
}
|
||||
return EpsOrPeStr;
|
||||
}
|
||||
|
||||
export { getRatingChangeStr, getEpsOrPeStr };
|
||||
Reference in New Issue
Block a user