diff --git a/lib/v2/cs/index.js b/lib/v2/cs/index.js new file mode 100644 index 000000000..42fd9c58a --- /dev/null +++ b/lib/v2/cs/index.js @@ -0,0 +1,83 @@ +const got = require('@/utils/got'); +const cheerio = require('cheerio'); +const iconv = require('iconv-lite'); +const timezone = require('@/utils/timezone'); +const { parseDate } = require('@/utils/parse-date'); + +const decodeBufferByCharset = (buffer) => { + const isGBK = /charset="?'?gb/i.test(buffer.toString()); + const encoding = isGBK ? 'gbk' : 'utf-8'; + + return iconv.decode(buffer, encoding); +}; + +module.exports = async (ctx) => { + const { category = 'xwzx' } = ctx.params; + const limit = ctx.query.limit ? Number.parseInt(ctx.query.limit, 10) : 30; + + const rootUrl = 'https://www.cs.com.cn'; + const currentUrl = new URL(category.endsWith('/') ? category : `${category}/`, rootUrl).href; + + const { data: response } = await got(currentUrl, { + responseType: 'buffer', + }); + + const $ = cheerio.load(decodeBufferByCharset(response)); + + let items = $('ul.ch_type3_list li a') + .slice(0, limit) + .toArray() + .map((item) => { + item = $(item); + + return { + title: item.find('h3').text().trim(), + link: new URL(item.prop('href'), currentUrl).href, + pubDate: timezone(parseDate(item.find('em').text()), +8), + }; + }); + + items = await Promise.all( + items.map((item) => + ctx.cache.tryGet(item.link, async () => { + try { + const { data: detailResponse } = await got(item.link, { + responseType: 'buffer', + }); + + const content = cheerio.load(decodeBufferByCharset(detailResponse)); + + item.title = content('article.cont_article header h1').text().trim(); + item.description = content('article.cont_article section').html(); + item.author = content('div.artc_info em').text().trim(); + item.category = content('div.artc_route div a') + .slice(1) + .toArray() + .map((c) => content(c).prop('title') ?? content(c).text()); + item.pubDate = timezone(parseDate(content('.time').prop('datetime')), +8); + } catch { + // no-empty + } + + return item; + }) + ) + ); + + const title = $('title').text(); + const image = new URL($('div.logo_cs a img').prop('src'), currentUrl).href; + const icon = new URL('favicon.ico', rootUrl).href; + + ctx.state.data = { + item: items, + title, + link: currentUrl, + description: $('meta[name="Description"]').prop('content'), + language: $('html').prop('lang'), + image, + icon, + logo: icon, + subtitle: $('meta[name="Keywords"]').prop('content'), + author: title.split('-').pop().trim(), + }; +}; diff --git a/lib/v2/cs/maintainer.js b/lib/v2/cs/maintainer.js index 3bc3c44c6..066baab97 100644 --- a/lib/v2/cs/maintainer.js +++ b/lib/v2/cs/maintainer.js @@ -1,3 +1,4 @@ module.exports = { '/zzkx': ['nczitzk'], + '/:category?': ['nczitzk'], }; diff --git a/lib/v2/cs/radar.js b/lib/v2/cs/radar.js index 6330e55c4..5467b450f 100644 --- a/lib/v2/cs/radar.js +++ b/lib/v2/cs/radar.js @@ -3,10 +3,184 @@ module.exports = { _name: '中证网', '.': [ { - title: '中证快讯', - docs: 'https://docs.rsshub.app/routes/finance#zhong-zheng-wang-zhong-zheng-kuai-xun', + title: '要闻', + docs: 'https://docs.rsshub.app/routes/finance#zhong-zheng-wang-lan-mu', + source: ['/xwzx/'], + target: '/cs/xwzx', + }, + { + title: '公司', + docs: 'https://docs.rsshub.app/routes/finance#zhong-zheng-wang-lan-mu', + source: ['/ssgs/'], + target: '/cs/ssgs', + }, + { + title: '市场', + docs: 'https://docs.rsshub.app/routes/finance#zhong-zheng-wang-lan-mu', + source: ['/gppd/'], + target: '/cs/gppd', + }, + { + title: '基金', + docs: 'https://docs.rsshub.app/routes/finance#zhong-zheng-wang-lan-mu', + source: ['/tzjj/'], + target: '/cs/tzjj', + }, + { + title: '科创', + docs: 'https://docs.rsshub.app/routes/finance#zhong-zheng-wang-lan-mu', + source: ['/5g/'], + target: '/cs/5g', + }, + { + title: '产经', + docs: 'https://docs.rsshub.app/routes/finance#zhong-zheng-wang-lan-mu', + source: ['/cj2020/'], + target: '/cs/cj2020', + }, + { + title: '期货', + docs: 'https://docs.rsshub.app/routes/finance#zhong-zheng-wang-lan-mu', + source: ['/zzqh2020/'], + target: '/cs/zzqh2020', + }, + { + title: '海外', + docs: 'https://docs.rsshub.app/routes/finance#zhong-zheng-wang-lan-mu', + source: ['/hw2020/'], + target: '/cs/hw2020', + }, + { + title: '财经要闻', + docs: 'https://docs.rsshub.app/routes/finance#zhong-zheng-wang-lan-mu', + source: ['/xwzx/hg/'], + target: '/cs/xwzx/hg', + }, + { + title: '观点评论', + docs: 'https://docs.rsshub.app/routes/finance#zhong-zheng-wang-lan-mu', + source: ['/xwzx/jr/'], + target: '/cs/xwzx/jr', + }, + { + title: '民生消费', + docs: 'https://docs.rsshub.app/routes/finance#zhong-zheng-wang-lan-mu', + source: ['/xwzx/msxf/'], + target: '/cs/xwzx/msxf', + }, + { + title: '公司要闻', + docs: 'https://docs.rsshub.app/routes/finance#zhong-zheng-wang-lan-mu', + source: ['/ssgs/gsxw/'], + target: '/cs/ssgs/gsxw', + }, + { + title: '公司深度', + docs: 'https://docs.rsshub.app/routes/finance#zhong-zheng-wang-lan-mu', + source: ['/ssgs/gssd/'], + target: '/cs/ssgs/gssd', + }, + { + title: '公司巡礼', + docs: 'https://docs.rsshub.app/routes/finance#zhong-zheng-wang-lan-mu', + source: ['/ssgs/gsxl/'], + target: '/cs/ssgs/gsxl', + }, + { + title: 'A股市场', + docs: 'https://docs.rsshub.app/routes/finance#zhong-zheng-wang-lan-mu', + source: ['/gppd/gsyj/'], + target: '/cs/gppd/gsyj', + }, + { + title: '港股资讯', + docs: 'https://docs.rsshub.app/routes/finance#zhong-zheng-wang-lan-mu', + source: ['/gppd/ggzx/'], + target: '/cs/gppd/ggzx', + }, + { + title: '债市研究', + docs: 'https://docs.rsshub.app/routes/finance#zhong-zheng-wang-lan-mu', + source: ['/gppd/zqxw/'], + target: '/cs/gppd/zqxw', + }, + { + title: '海外报道', + docs: 'https://docs.rsshub.app/routes/finance#zhong-zheng-wang-lan-mu', + source: ['/gppd/hwbd/'], + target: '/cs/gppd/hwbd', + }, + { + title: '期货报道', + docs: 'https://docs.rsshub.app/routes/finance#zhong-zheng-wang-lan-mu', + source: ['/gppd/qhbd/'], + target: '/cs/gppd/qhbd', + }, + { + title: '基金动态', + docs: 'https://docs.rsshub.app/routes/finance#zhong-zheng-wang-lan-mu', + source: ['/tzjj/jjdt/'], + target: '/cs/tzjj/jjdt', + }, + { + title: '基金视点', + docs: 'https://docs.rsshub.app/routes/finance#zhong-zheng-wang-lan-mu', + source: ['/tzjj/jjks/'], + target: '/cs/tzjj/jjks', + }, + { + title: '基金持仓', + docs: 'https://docs.rsshub.app/routes/finance#zhong-zheng-wang-lan-mu', + source: ['/tzjj/jjcs/'], + target: '/cs/tzjj/jjcs', + }, + { + title: '私募基金', + docs: 'https://docs.rsshub.app/routes/finance#zhong-zheng-wang-lan-mu', + source: ['/tzjj/smjj/'], + target: '/cs/tzjj/smjj', + }, + { + title: '基民学苑', + docs: 'https://docs.rsshub.app/routes/finance#zhong-zheng-wang-lan-mu', + source: ['/tzjj/tjdh/'], + target: '/cs/tzjj/tjdh', + }, + { + title: '券商', + docs: 'https://docs.rsshub.app/routes/finance#zhong-zheng-wang-lan-mu', + source: ['/qs/'], + target: '/cs/qs', + }, + { + title: '银行', + docs: 'https://docs.rsshub.app/routes/finance#zhong-zheng-wang-lan-mu', + source: ['/yh/'], + target: '/cs/yh', + }, + { + title: '保险', + docs: 'https://docs.rsshub.app/routes/finance#zhong-zheng-wang-lan-mu', + source: ['/bx/'], + target: '/cs/bx', + }, + { + title: '中证快讯 7x24', + docs: 'https://docs.rsshub.app/routes/finance#zhong-zheng-wang-lan-mu', source: ['/sylm/jsbd/'], - target: '/cs/zzkx', + target: '/cs/sylm/jsbd', + }, + { + title: 'IPO鉴真', + docs: 'https://docs.rsshub.app/routes/finance#zhong-zheng-wang-lan-mu', + source: ['/yc/ipojz/'], + target: '/cs/yc/ipojz', + }, + { + title: '公司能见度', + docs: 'https://docs.rsshub.app/routes/finance#zhong-zheng-wang-lan-mu', + source: ['/yc/gsnjd/'], + target: '/cs/yc/gsnjd', }, ], }, diff --git a/lib/v2/cs/router.js b/lib/v2/cs/router.js index daa87cf07..fb1aa85c8 100644 --- a/lib/v2/cs/router.js +++ b/lib/v2/cs/router.js @@ -1,4 +1,12 @@ -module.exports = (router) => { - router.get('/news/zzkx', require('./zzkx')); - router.get('/zzkx', require('./zzkx')); +const toZzkx = (ctx) => { + // https://www.cs.com.cn/sylm/jsbd/ + + const redirectTo = '/cs/sylm/jsbd'; + ctx.redirect(redirectTo); +}; + +module.exports = (router) => { + router.get('/news/zzkx', toZzkx); + router.get('/zzkx', toZzkx); + router.get('/:category*', require('./')); }; diff --git a/lib/v2/cs/zzkx.js b/lib/v2/cs/zzkx.js deleted file mode 100644 index dd90df907..000000000 --- a/lib/v2/cs/zzkx.js +++ /dev/null @@ -1,56 +0,0 @@ -const got = require('@/utils/got'); -const cheerio = require('cheerio'); -const timezone = require('@/utils/timezone'); -const { parseDate } = require('@/utils/parse-date'); - -const rootUrl = 'http://www.cs.com.cn/'; - -const config = { - link: '/sylm/jsbd/', - title: '中证快讯', - query: 'ul.some-list li', -}; - -module.exports = async (ctx) => { - const currentUrl = new URL(config.link, rootUrl).href; - const response = await got({ - method: 'get', - url: currentUrl, - }); - - const $ = cheerio.load(response.data); - const list = $(config.query) - .slice(0, 20) - .map((_, item) => { - item = $(item); - const a = item.find('a'); - return { - title: item.find('h3').text() || a.text(), - link: new URL(a.attr('href'), currentUrl).href, - pubDate: timezone(parseDate(item.find('em').text() || item.find('span').text()), +8), - }; - }) - .get(); - - const items = await Promise.all( - list.map((item) => - ctx.cache.tryGet(item.link, async () => { - const res = await got({ - method: 'get', - url: item.link, - }); - const content = cheerio.load(res.data); - - item.description = content('.cont_article section').html() || content('.article-t').html(); - - return item; - }) - ) - ); - - ctx.state.data = { - title: '中证网 - ' + config.title, - link: currentUrl, - item: items, - }; -}; diff --git a/website/docs/routes/finance.mdx b/website/docs/routes/finance.mdx index 3185a561c..c45056eba 100644 --- a/website/docs/routes/finance.mdx +++ b/website/docs/routes/finance.mdx @@ -942,6 +942,54 @@ TokenInsight also provides official RSS, you can take a look at [https://api.tok ## 中证网 {#zhong-zheng-wang} -### 中证快讯 {#zhong-zheng-wang-zhong-zheng-kuai-xun} +### 栏目 {#zhong-zheng-wang-lan-mu} - + + | 要闻 | 公司 | 市场 | 基金 | + | ---- | ---- | ---- | ---- | + | xwzx | ssgs | gppd | tzjj | + + | 科创 | 产经 | 期货 | 海外 | + | ---- | ------ | -------- | ------ | + | 5g | cj2020 | zzqh2020 | hw2020 | + +
+ 更多栏目 + + #### 要闻 + + | 财经要闻 | 观点评论 | 民生消费 | + | -------- | -------- | --------- | + | xwzx/hg | xwzx/jr | xwzx/msxf | + + #### 公司 + + | 公司要闻 | 公司深度 | 公司巡礼 | + | --------- | --------- | --------- | + | ssgs/gsxw | ssgs/gssd | ssgs/gsxl | + + #### 市场 + + | A 股市场 | 港股资讯 | 债市研究 | 海外报道 | 期货报道 | + | --------- | --------- | --------- | --------- | --------- | + | gppd/gsyj | gppd/ggzx | gppd/zqxw | gppd/hwbd | gppd/qhbd | + + #### 基金 + + | 基金动态 | 基金视点 | 基金持仓 | 私募基金 | 基民学苑 | + | --------- | --------- | --------- | --------- | --------- | + | tzjj/jjdt | tzjj/jjks | tzjj/jjcs | tzjj/smjj | tzjj/tjdh | + + #### 机构 + + | 券商 | 银行 | 保险 | + | ---- | ---- | ---- | + | qs | yh | bx | + + #### 其他 + + | 中证快讯 7x24 | IPO 鉴真 | 公司能见度 | + | ------------- | -------- | ---------- | + | sylm/jsbd | yc/ipojz | yc/gsnjd | +
+