fix(route): 36kr资讯 (#10179)

This commit is contained in:
Ethan Shen 2022-07-09 09:18:08 +08:00 committed by GitHub
parent 56fc5fd57e
commit 749f2fef99
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 130 additions and 275 deletions

View File

@ -28,37 +28,45 @@ pageClass: routes
### 资讯
<Route author="nczitzk" example="/36kr/news/latest" path="/36kr/news/:category?" :paramsDesc="['资讯分类,见下表,默认为最新']">
<Route author="nczitzk" example="/36kr/information/web_news" path="/36kr/information/:category?" :paramsDesc="['资讯分类,见下表,默认为最新']">
| 最新 | 推荐 | 创投 | Markets |
| ------ | --------- | ------- | ------- |
| latest | recommend | contact | ccs |
| 最新 | 推荐 | 创投 | 财经 |
| -------- | ------------- | ------- | --- |
| web_news | web_recommend | contact | ccs |
| 汽车 | 科技 | 企服 | 生活 |
| ------ | ---------- | ----------------- | ---- |
| travel | technology | enterpriseservice | life |
| 汽车 | 科技 | 企服 | 生活 |
| ------ | ---------- | ----------------- | ---------- |
| travel | technology | enterpriseservice | happy_life |
| 创新 | 房产 | 职场 | 企业号 | 其他 |
| -------- | ----------- | --------- | ------- | ----- |
| innovate | real_estate | workplace | qiyehao | other |
| 创新 | 房产 | 职场 | 企业号 | 其他 |
| -------- | ----------- | ------------ | ------- | ----- |
| innovate | real_estate | web_zhichang | qiyehao | other |
</Route>
### 快讯
<Route author="hillerliao" example="/36kr/newsflashes" path="/36kr/newsflashes" />
<Route author="hillerliao nczitzk" example="/36kr/newsflashes" path="/36kr/newsflashes" />
### 用户文章
<Route author="nczitzk" example="/36kr/user/747305693" path="/36kr/user/:id" :paramsDesc="['用户 ID']" />
<Route author="nczitzk" example="/36kr/user/747305693" path="/36kr/user/:id" :paramsDesc="['用户 id可在对应用户页面 URL 中找到']" />
### 主题文章
<Route author="nczitzk" example="/36kr/motif/452" path="/36kr/motif/:id" :paramsDesc="['主题 ID']" />
<Route author="nczitzk" example="/36kr/motif/452" path="/36kr/motif/:id" :paramsDesc="['主题 id可在对应主题页面 URL 中找到']" />
### 专题文章
<Route author="nczitzk" example="/36kr/topics/1818512662032001" path="/36kr/topics/:id" :paramsDesc="['专题 id可在对应专题页面 URL 中找到']" />
### 搜索文章
<Route author="xyqfer kt286 nczitzk" example="/36kr/search/article/ofo" path="/36kr/search/article/:keyword" :paramsDesc="['关键字']" />
<Route author="xyqfer kt286 nczitzk" example="/36kr/search/articles/ofo" path="/36kr/search/articles/:keyword" :paramsDesc="['关键字']" />
### 搜索快讯
<Route author="nczitzk" example="/36kr/search/newsflashes/ofo" path="/36kr/search/newsflashes/:keyword" :paramsDesc="['关键字']" />
## 52hrtt 华人头条

75
lib/v2/36kr/index.js Normal file
View File

@ -0,0 +1,75 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
const { parseDate } = require('@/utils/parse-date');
const CryptoJS = require('crypto-js');
const shortcuts = {
'/information': '/information/web_news',
'/information/latest': '/information/web_news',
'/information/recommend': '/information/web_recommend',
'/information/life': '/information/happy_life',
'/information/estate': '/information/real_estate',
'/information/workplace': '/information/web_zhichang',
};
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({
method: 'get',
url: currentUrl,
});
const $ = cheerio.load(response.data);
const data = JSON.parse(response.data.match(/"itemList":(\[.*?\])/)[1]);
let items = data.slice(0, ctx.query.limit ? parseInt(ctx.query.limit) : 30).map((item) => {
item = item.templateMaterial ?? item;
return {
title: item.widgetTitle.replace(/<\/?em>/g, ''),
author: item.author,
pubDate: parseDate(item.publishTime),
link: `${rootUrl}/${path === '/newsflashes' ? 'newsflashes' : 'p'}/${item.itemId}`,
description: item.widgetContent ?? item.content,
};
});
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 key = CryptoJS.enc.Utf8.parse('efabccee-b754-4c');
const cipherText = detailResponse.data.match(/{"state":"(.*)","isEncrypt":true}/)[1];
const content = JSON.parse(
CryptoJS.AES.decrypt(cipherText, key, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7,
})
.toString(CryptoJS.enc.Utf8)
.toString()
).articleDetail.articleDetailData.data;
item.description = content.widgetContent;
return item;
})
)
);
}
ctx.state.data = {
title: `36氪 - ${$('title').text().split('_')[0]}`,
link: currentUrl,
item: items,
};
};

View File

@ -1,7 +1,9 @@
module.exports = {
'/information/:category?': ['nczitzk'],
'/motif/:id': ['nczitzk'],
'/news/:category?': ['nczitzk'],
'/newsflashes': ['hillerliao'],
'/search/article/:keyword': ['xyqfer', 'kt286', 'nczitzk'],
'/newsflashes': ['hillerliao', 'nczitzk'],
'/search/articles/:keyword': ['xyqfer', 'kt286', 'nczitzk'],
'/search/newsflashes/:keyword': ['nczitzk'],
'/topics/:id': ['nczitzk'],
'/user/:id': ['nczitzk'],
};

View File

@ -1,57 +0,0 @@
const got = require('@/utils/got');
const { parseDate } = require('@/utils/parse-date');
const CryptoJS = require('crypto-js');
module.exports = async (ctx) => {
const id = ctx.params.id;
const rootUrl = 'https://36kr.com';
const currentUrl = `${rootUrl}/motif/${id}`;
const response = await got({
method: 'get',
url: currentUrl,
});
const data = JSON.parse(response.data.match(/"motifDetailData":{"code":0,"data":(.*)},"channel"/)[1]);
let items = data.motifArticleList.data.itemList.map((item) => ({
title: item.templateMaterial.widgetTitle,
link: `${rootUrl}/p/${item.itemId}`,
pubDate: parseDate(item.templateMaterial.publishTime),
}));
items = await Promise.all(
items.map((item) =>
ctx.cache.tryGet(item.link, async () => {
const detailResponse = await got({
method: 'get',
url: item.link,
});
const key = CryptoJS.enc.Utf8.parse('efabccee-b754-4c');
const cipherText = detailResponse.data.match(/{"state":"(.*)","isEncrypt":true}/)[1];
const content = JSON.parse(
CryptoJS.AES.decrypt(cipherText, key, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7,
})
.toString(CryptoJS.enc.Utf8)
.toString()
).articleDetail.articleDetailData.data;
item.author = content.author;
item.description = content.widgetContent;
return item;
})
)
);
ctx.state.data = {
title: `36kr - ${data.motifInfo.data.categoryTitle}`,
link: currentUrl,
item: items,
};
};

View File

@ -1,56 +0,0 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
const { parseDate } = require('@/utils/parse-date');
const links = {
latest: 'information/web_news',
recommend: 'information/web_recommend',
life: 'information/happy_life',
estate: 'information/real_estate',
workplace: 'information/web_zhichang',
};
module.exports = async (ctx) => {
const category = ctx.params.category ?? 'latest';
const rootUrl = 'https://36kr.com';
const currentUrl = `${rootUrl}/${links.hasOwnProperty(category) ? links[category] : `information/${category}`}`;
const response = await got({
method: 'get',
url: currentUrl,
});
const data = JSON.parse(response.data.match(/<script>window\.initialState=(.*?)<\/script>/)[1]);
const list = data.information.informationList.itemList
.filter((item) => item.itemType === 10)
.map((item) => ({
title: item.templateMaterial.widgetTitle,
link: `${rootUrl}/p/${item.itemId} `,
pubDate: parseDate(item.templateMaterial.publishTime),
}));
const items = await Promise.all(
list.map((item) =>
ctx.cache.tryGet(item.link, async () => {
const detailResponse = await got({
method: 'get',
url: item.link,
});
const content = cheerio.load(detailResponse.data);
item.description = content('.articleDetailContent').html();
return item;
})
)
);
ctx.state.data = {
title: `${response.data.match(/shareTitle: "(.*)频道.*",/)[1]} - 36氪资讯`,
link: currentUrl,
item: items,
};
};

View File

@ -1,37 +0,0 @@
const got = require('@/utils/got');
const { parseDate } = require('@/utils/parse-date');
module.exports = async (ctx) => {
const response = await got({
method: 'get',
url: `https://36kr.com/newsflashes`,
headers: {
Host: '36kr.com',
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 6_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A5376e Safari/8536.25',
},
});
const regexp = /<script>window\.initialState=(.*?)<\/script>/;
const newsflashes = JSON.parse(response.data.match(regexp)[1]);
const out = newsflashes.newsflashList.flow.itemList.map((item) => {
const link = item.templateMaterial.sourceUrlRoute ? new URL(`http://www.example.com/${item.templateMaterial.sourceUrlRoute}`).searchParams.get('url') : `https://36kr.com/newsflashes/${item.itemId}`;
const date = item.templateMaterial.publishTime;
const title = item.templateMaterial.widgetTitle;
const description = item.templateMaterial.widgetContent;
const single = {
title,
link,
pubDate: parseDate(date),
description,
};
return single;
});
ctx.state.data = {
title: `快讯 - 36氪`,
link: `https://36kr.com/newsflashes`,
item: out,
};
};

View File

@ -1,36 +1,48 @@
module.exports = {
'36kr.com': {
_name: '36kr',
_name: '36',
'.': [
{
title: '资讯',
docs: 'https://docs.rsshub.app/new-media.html#_36kr',
source: '/',
target: '/36kr/news',
docs: 'https://docs.rsshub.app/new-media.html#_36kr-zi-xun',
source: ['/information/:category', '/'],
target: '/36kr/information/:category',
},
{
title: '快讯',
docs: 'https://docs.rsshub.app/new-media.html#_36kr',
source: '/',
docs: 'https://docs.rsshub.app/new-media.html#_36kr-kuai-xun',
source: ['/newsflashes', '/'],
target: '/36kr/newsflashes',
},
{
title: '用户文章',
docs: 'https://docs.rsshub.app/new-media.html#_36kr',
source: '/user/:uid',
target: '/36kr/user/:uid',
docs: 'https://docs.rsshub.app/new-media.html#_36kr-yong-hu-wen-zhang',
source: ['/user/:id', '/'],
target: '/36kr/user/:id',
},
{
title: '主题文章',
docs: 'https://docs.rsshub.app/new-media.html#_36kr',
source: '/motif/:mid',
target: '/36kr/motif/:mid',
docs: 'https://docs.rsshub.app/new-media.html#_36kr-zhu-ti-wen-zhang',
source: ['/motif/:id', '/'],
target: '/36kr/motif/:id',
},
{
title: '专题文章',
docs: 'https://docs.rsshub.app/new-media.html#_36kr-zhuan-ti-wen-zhang',
source: ['/topics/:id', '/'],
target: '/36kr/topics/:id',
},
{
title: '搜索文章',
docs: 'https://docs.rsshub.app/new-media.html#_36kr',
source: '/search/articles/:keyword',
target: '/36kr/search/article/:keyword',
docs: 'https://docs.rsshub.app/new-media.html#_36kr-sou-suo-wen-zhang',
source: ['/search/articles/:keyword', '/'],
target: '/36kr/search/articles/:keyword',
},
{
title: '搜索快讯',
docs: 'https://docs.rsshub.app/new-media.html#_36kr-sou-suo-kuai-xun',
source: ['/search/newsflashes/:keyword', '/'],
target: '/36kr/search/newsflashes/:keyword',
},
],
},

View File

@ -1,7 +1,3 @@
module.exports = (router) => {
router.get('/motif/:id', require('./motif'));
router.get('/news/:category?', require('./news'));
router.get('/newsflashes', require('./newsflashes'));
router.get('/search/article/:keyword', require('./search/article'));
router.get('/user/:id', require('./user'));
router.get(/([\w-/]+)?/, require('./index'));
};

View File

@ -1,27 +0,0 @@
const got = require('@/utils/got');
const { parseDate } = require('@/utils/parse-date');
module.exports = async (ctx) => {
const keyword = ctx.params.keyword ?? '';
const rootUrl = 'https://www.36kr.com';
const currentUrl = `${rootUrl}/search/articles/${keyword}`;
const response = await got({
method: 'get',
url: currentUrl,
});
const items = JSON.parse(response.data.match(/"itemList":(.*),"pageCallback"/)[1]).map((item) => ({
title: item.widgetTitle.replace(/<\/?em>/g, ''),
link: `${rootUrl}/p/${item.itemId}`,
description: `<p>${item.content}</p>`,
pubDate: parseDate(item.publishTime),
}));
ctx.state.data = {
title: `36氪 - ${keyword}相关文章`,
link: currentUrl,
item: items,
};
};

View File

@ -1,61 +0,0 @@
const got = require('@/utils/got');
const { parseDate } = require('@/utils/parse-date');
module.exports = async (ctx) => {
const id = ctx.params.id;
const rootUrl = 'https://36kr.com';
const apiRootUrl = 'https://gateway.36kr.com';
const currentUrl = `${rootUrl}/user/${id}`;
const infoResponse = await got({
method: 'post',
url: `${apiRootUrl}/api/mis/user/info`,
json: {
param: {
userId: id,
siteId: 1,
platformId: 2,
},
platformId: 2,
siteId: 1,
userId: id,
partner_id: 'web',
},
});
const response = await got({
method: 'post',
url: `${apiRootUrl}/api/mis/me/article`,
json: {
param: {
userId: id,
pageEvent: 0,
pageSize: 20,
pageCallback: '',
siteId: 1,
platformId: 2,
},
pageCallback: '',
pageEvent: 0,
pageSize: 20,
platformId: 2,
siteId: 1,
userId: id,
partner_id: 'web',
},
});
const items = response.data.data.itemList.map((item) => ({
title: item.templateMaterial.widgetTitle,
link: `${rootUrl}/p/${item.itemId}`,
pubDate: parseDate(item.templateMaterial.publishTime),
description: `<p>${item.templateMaterial.widgetContent}</p>`,
}));
ctx.state.data = {
title: `36kr - ${infoResponse.data.data.userNick}`,
link: currentUrl,
item: items,
};
};