From a4e2eda25aa5d34afe7b4bda7ca6f798da97b155 Mon Sep 17 00:00:00 2001 From: Ethan Shen <42264778+nczitzk@users.noreply.github.com> Date: Wed, 21 Jun 2023 08:04:50 +0800 Subject: [PATCH] =?UTF-8?q?feat(route):=20add=2036kr=E8=B5=84=E8=AE=AF?= =?UTF-8?q?=E7=83=AD=E6=A6=9C=20(#12681)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(route): add 36kr资讯热榜 * fix docs * update lib/v2/36kr/utils.js --------- --- docs/new-media.md | 10 +++++++ lib/v2/36kr/hot-list.js | 59 +++++++++++++++++++++++++++++++++++++++ lib/v2/36kr/index.js | 33 ++-------------------- lib/v2/36kr/maintainer.js | 1 + lib/v2/36kr/radar.js | 6 ++++ lib/v2/36kr/router.js | 1 + lib/v2/36kr/utils.js | 36 ++++++++++++++++++++++++ 7 files changed, 116 insertions(+), 30 deletions(-) create mode 100644 lib/v2/36kr/hot-list.js create mode 100644 lib/v2/36kr/utils.js diff --git a/docs/new-media.md b/docs/new-media.md index aac99901f..427a9634d 100644 --- a/docs/new-media.md +++ b/docs/new-media.md @@ -68,6 +68,16 @@ pageClass: routes +### 资讯热榜 + + + +| 24小时热榜 | 资讯人气榜 | 资讯综合榜 | 资讯收藏榜 | +| ---------- | ---------- | ---------- | ---------- | +| 24 | renqi | zonghe | shoucang | + + + ## 52hrtt 华人头条 ### 新闻 diff --git a/lib/v2/36kr/hot-list.js b/lib/v2/36kr/hot-list.js new file mode 100644 index 000000000..52e8d95cc --- /dev/null +++ b/lib/v2/36kr/hot-list.js @@ -0,0 +1,59 @@ +const got = require('@/utils/got'); +const { parseDate } = require('@/utils/parse-date'); + +const { rootUrl, ProcessItem } = require('./utils'); + +const categories = { + 24: { + title: '24小时热榜', + key: 'homeData.data.hotlist.data', + }, + renqi: { + title: '资讯人气榜', + key: 'hotListData.topList', + }, + zonghe: { + title: '资讯综合榜', + key: 'hotListData.hotList', + }, + shoucang: { + title: '资讯综合榜', + key: 'hotListData.collectList', + }, +}; + +module.exports = async (ctx) => { + const category = ctx.params.category ?? '24'; + + const currentUrl = category === '24' ? rootUrl : `${rootUrl}/hot-list/catalog`; + + const response = await got({ + method: 'get', + url: currentUrl, + }); + + const getProperty = (object, key) => key.split('.').reduce((o, k) => o && o[k], object); + const data = getProperty(JSON.parse(response.data.match(/window.initialState=({.*})/)[1]), categories[category].key); + + let items = data + .slice(0, ctx.query.limit ? parseInt(ctx.query.limit) : 10) + .filter((item) => item.itemType !== 0) + .map((item) => { + item = item.templateMaterial ?? item; + return { + title: item.widgetTitle.replace(/<\/?em>/g, ''), + author: item.authorName, + pubDate: parseDate(item.publishTime), + link: `${rootUrl}/p/${item.itemId}`, + description: item.summary, + }; + }); + + items = await Promise.all(items.map((item) => ProcessItem(item, ctx.cache.tryGet))); + + ctx.state.data = { + title: `36氪 - ${categories[category].title}`, + link: currentUrl, + item: items, + }; +}; diff --git a/lib/v2/36kr/index.js b/lib/v2/36kr/index.js index 04dc4cb39..6f2f34ec5 100644 --- a/lib/v2/36kr/index.js +++ b/lib/v2/36kr/index.js @@ -1,7 +1,8 @@ const got = require('@/utils/got'); const cheerio = require('cheerio'); const { parseDate } = require('@/utils/parse-date'); -const CryptoJS = require('crypto-js'); + +const { rootUrl, ProcessItem } = require('./utils'); const shortcuts = { '/information': '/information/web_news', @@ -15,7 +16,6 @@ const shortcuts = { module.exports = async (ctx) => { const path = ctx.path.replace(/^\/news(?!flashes)/, '/information').replace(/\/search\/article/, '/search/articles'); - const rootUrl = 'https://www.36kr.com'; const currentUrl = `${rootUrl}${shortcuts.hasOwnProperty(path) ? shortcuts[path] : path}`; const response = await got({ @@ -42,34 +42,7 @@ module.exports = async (ctx) => { }); if (!/^\/(search|newsflashes)/.test(path)) { - items = await Promise.all( - items.map((item) => - ctx.cache.tryGet(item.link, async () => { - const detailResponse = await got({ - method: 'get', - url: item.link, - }); - - const cipherTextList = detailResponse.data.match(/{"state":"(.*)","isEncrypt":true}/) ?? []; - if (cipherTextList.length !== 0) { - const key = CryptoJS.enc.Utf8.parse('efabccee-b754-4c'); - const content = JSON.parse( - CryptoJS.AES.decrypt(cipherTextList[1], key, { - mode: CryptoJS.mode.ECB, - padding: CryptoJS.pad.Pkcs7, - }) - .toString(CryptoJS.enc.Utf8) - .toString() - ).articleDetail.articleDetailData.data; - item.description = content.widgetContent; - } else { - const $ = cheerio.load(detailResponse.body); - item.description = $('div.articleDetailContent').html(); - } - return item; - }) - ) - ); + items = await Promise.all(items.map((item) => ProcessItem(item, ctx.cache.tryGet))); } ctx.state.data = { diff --git a/lib/v2/36kr/maintainer.js b/lib/v2/36kr/maintainer.js index d72d4d414..aad6ba56d 100644 --- a/lib/v2/36kr/maintainer.js +++ b/lib/v2/36kr/maintainer.js @@ -1,4 +1,5 @@ module.exports = { + '/hot-list/:category?': ['nczitzk'], '/information/:category?': ['nczitzk'], '/motif/:id': ['nczitzk'], '/newsflashes': ['hillerliao', 'nczitzk'], diff --git a/lib/v2/36kr/radar.js b/lib/v2/36kr/radar.js index 420da8b60..d7ab9315c 100644 --- a/lib/v2/36kr/radar.js +++ b/lib/v2/36kr/radar.js @@ -44,6 +44,12 @@ module.exports = { source: ['/search/newsflashes/:keyword', '/'], target: '/36kr/search/newsflashes/:keyword', }, + { + title: '资讯热榜', + docs: 'https://docs.rsshub.app/new-media.html#_36kr-zi-xun-re-bang', + source: ['/hot-list/:category', '/'], + target: '/36kr/hot-list/:category', + }, ], }, }; diff --git a/lib/v2/36kr/router.js b/lib/v2/36kr/router.js index 2aa2b0a19..aaddd322f 100644 --- a/lib/v2/36kr/router.js +++ b/lib/v2/36kr/router.js @@ -1,3 +1,4 @@ module.exports = (router) => { + router.get('/hot-list/:category?', require('./hot-list')); router.get(/([\w-/]+)?/, require('./index')); }; diff --git a/lib/v2/36kr/utils.js b/lib/v2/36kr/utils.js new file mode 100644 index 000000000..a2be6ea1b --- /dev/null +++ b/lib/v2/36kr/utils.js @@ -0,0 +1,36 @@ +const got = require('@/utils/got'); +const cheerio = require('cheerio'); +const CryptoJS = require('crypto-js'); + +const rootUrl = 'https://www.36kr.com'; + +module.exports = { + rootUrl, + ProcessItem: (item, tryGet) => + tryGet(item.link, async () => { + const detailResponse = await got({ + method: 'get', + url: item.link, + }); + + const cipherTextList = detailResponse.data.match(/{"state":"(.*)","isEncrypt":true}/) ?? []; + + if (cipherTextList.length !== 0) { + const key = CryptoJS.enc.Utf8.parse('efabccee-b754-4c'); + const content = JSON.parse( + CryptoJS.AES.decrypt(cipherTextList[1], key, { + mode: CryptoJS.mode.ECB, + padding: CryptoJS.pad.Pkcs7, + }) + .toString(CryptoJS.enc.Utf8) + .toString() + ).articleDetail.articleDetailData.data; + item.description = content.widgetContent; + } else { + const $ = cheerio.load(detailResponse.body); + item.description = $('div.articleDetailContent').html(); + } + + return item; + }), +};