160 lines
5.2 KiB
JavaScript
160 lines
5.2 KiB
JavaScript
const got = require('@/utils/got');
|
|
const cheerio = require('cheerio');
|
|
const timezone = require('@/utils/timezone');
|
|
const { parseDate } = require('@/utils/parse-date');
|
|
const { parseRelativeDate } = require('@/utils/parse-date');
|
|
|
|
const config = {
|
|
review: {
|
|
title: '评论 & 研究',
|
|
query: '.module-news-main',
|
|
},
|
|
story: {
|
|
title: '要闻',
|
|
query: '.img-List',
|
|
},
|
|
fengwen: {
|
|
title: '风闻',
|
|
query: '.fengwen-list',
|
|
},
|
|
redian: {
|
|
title: '热点',
|
|
},
|
|
gundong: {
|
|
title: '滚动',
|
|
},
|
|
all: {
|
|
title: '全部',
|
|
},
|
|
home: {
|
|
title: '首页',
|
|
},
|
|
others: {
|
|
title: '热点 & 滚动',
|
|
},
|
|
};
|
|
|
|
module.exports = async (ctx) => {
|
|
const total = 10;
|
|
const category = ctx.params.category ?? 'all';
|
|
const rootUrl = 'https://www.guancha.cn';
|
|
|
|
let newsList = [],
|
|
redianList = [],
|
|
gundongList = [];
|
|
|
|
// 'review', 'story' and 'fengwen' come from homepage.
|
|
|
|
if (category === 'review' || category === 'story' || category === 'fengwen' || category === 'all' || category === 'home') {
|
|
const response = await got({
|
|
method: 'get',
|
|
url: rootUrl,
|
|
});
|
|
|
|
const $ = cheerio.load(response.data);
|
|
|
|
const fetchPost = (slice) =>
|
|
slice
|
|
.find('h4.module-title a')
|
|
.toArray()
|
|
|
|
// Filter some blank links which lead to no contents but 'https://user.guancha.cn'.
|
|
|
|
.filter((item) => $(item).attr('href') !== 'https://user.guancha.cn')
|
|
.map((item) => {
|
|
item = $(item);
|
|
|
|
const link = item.attr('href');
|
|
|
|
return {
|
|
title: item.text(),
|
|
link: `${link.indexOf('http') === 0 ? '' : rootUrl}${link.replace(/\.shtml/, '_s.shtml')}`,
|
|
};
|
|
});
|
|
|
|
if (category === 'all' || category === 'home') {
|
|
newsList = fetchPost($(config.review.query))
|
|
.slice(0, total / 3)
|
|
.concat(fetchPost($(config.story.query)).slice(0, total / 3), fetchPost($(config.fengwen.query)).slice(0, total / 3));
|
|
} else {
|
|
newsList = fetchPost($(config[category].query)).slice(0, total);
|
|
}
|
|
}
|
|
|
|
// 'redian' and 'gundong' come from api.
|
|
|
|
if (category === 'redian' || category === 'all' || category === 'others') {
|
|
const response = await got({
|
|
method: 'get',
|
|
url: `${rootUrl}/api/redian.htm`,
|
|
});
|
|
|
|
redianList = response.data.items
|
|
.map((item) => ({
|
|
title: item.TITLE,
|
|
link: `${rootUrl}${item.HTTP_URL.replace(/\.shtml/, '_s.shtml')}`,
|
|
}))
|
|
.slice(0, category === 'all' ? total / 3 : total);
|
|
}
|
|
|
|
if (category === 'gundong' || category === 'all' || category === 'others') {
|
|
const response = await got({
|
|
method: 'get',
|
|
url: `${rootUrl}/api/gundong.htm`,
|
|
});
|
|
|
|
gundongList = response.data.items
|
|
.map((item) => ({
|
|
title: item.TITLE,
|
|
link: `${rootUrl}${item.HTTP_URL.replace(/\.shtml/, '_s.shtml')}`,
|
|
}))
|
|
.slice(0, category === 'all' ? total / 3 : total);
|
|
}
|
|
|
|
const items = await Promise.all(
|
|
newsList.concat(redianList, gundongList).map((item) =>
|
|
ctx.cache.tryGet(item.link, async () => {
|
|
let detailResponse = await got({
|
|
method: 'get',
|
|
url: item.link,
|
|
});
|
|
|
|
// Some links to posts in 'fengwen' must be redirected in order to fetch content.
|
|
// eg. https://www.guancha.cn/politics/2020_10_23_569021.shtml
|
|
// => https://user.guancha.cn/main/content?id=399176
|
|
|
|
const jumpMatch = detailResponse.data.match(/user.guancha.cn\/main\/content\?id=(.*)";/);
|
|
|
|
if (jumpMatch !== null) {
|
|
item.link = `https://user.guancha.cn/main/content?id=${jumpMatch[1]}&page=0`;
|
|
detailResponse = await got({
|
|
method: 'get',
|
|
url: item.link,
|
|
});
|
|
}
|
|
|
|
const content = cheerio.load(detailResponse.data);
|
|
|
|
const dateMatch = detailResponse.data.match(/"pubDate": "(.*)"/);
|
|
if (dateMatch === null) {
|
|
// PubDates of posts in 'fengwen' are in an informal format.
|
|
|
|
item.pubDate = parseRelativeDate(content('.time1').text());
|
|
} else {
|
|
item.pubDate = timezone(parseDate(dateMatch[1]), +8);
|
|
}
|
|
|
|
item.description = content('.all-txt').html() || content('.article-txt-content').html();
|
|
item.author = content('.author-intro p a').text() || content('.article-content div div h4 a').text() || content('.editor-intro p a').text() || content('.left-main > div.time.fix > span').eq(2).text();
|
|
return item;
|
|
})
|
|
)
|
|
);
|
|
|
|
ctx.state.data = {
|
|
title: `观察者网 - ${config[category].title}`,
|
|
link: rootUrl,
|
|
item: items,
|
|
};
|
|
};
|