feat: 新增 wikihow/正版中国 (#2679)

* feat: 新增 wikihow/正版中国/小众软件

* 移除 小众软件
This commit is contained in:
sanmmmm
2019-07-24 14:23:36 +08:00
committed by DIYgod
parent 982268b42b
commit 901bcbd3f9
7 changed files with 243 additions and 0 deletions
+38
View File
@@ -270,6 +270,26 @@ type 为 all 时,category 参数不支持 cost 和 free
</Route>
## wikiHow
### 首页
<Route author="sanmmm" example="/wikihow/index" path="/wikihow/index"/>
### 分类目录
<Route author="sanmmm" example="/wikihow/category/饮食与休闲/" path="/wikihow/category/:category/:type" :paramsDesc="['目录分类', '类型']">
顶级目录分类可在目录分类页[查看](https://zh.wikihow.com/Special:CategoryListing), 支持二级目录
类型
| 所有 | 推荐 |
| ---- | ---- |
| all | rec |
</Route>
## ZAKER
### source
@@ -1041,6 +1061,24 @@ type 为 all 时,category 参数不支持 cost 和 free
</Route>
## 正版中国
### 分类列表
<Route author="sanmmm" example="/getitfree/category/8" path="/getitfree/category/category?" :paramsDesc="['内容类型, 默认为`全部`']">
类型
| 全部文章 | 永久免费 | 限时折扣 | 限时免费 | PC | Mac | Android | UWP |
| -------- | -------- | -------- | -------- | --- | --- | ------- | --- |
| all | 311 | 309 | 310 | 8 | 50 | 17 | 312 |
</Route>
### 搜索
<Route author="sanmmm" example="/getitfree/search/windows" path="/getitfree/search/:keyword" :paramsDesc="['搜索关键词']"/>
## 中国大学 MOOC(慕课)
### 最新
+8
View File
@@ -1545,4 +1545,12 @@ router.get('/ff14/ff14_zh/:type', require('./routes/ff14/ff14_zh'));
router.get('/xuetangx/course/:cid/:type', require('./routes/xuetangx/course_info'));
router.get('/xuetangx/course/list/:mode/:credential/:status/:type?', require('./routes/xuetangx/course_list'));
// wikihow
router.get('/wikihow/index', require('./routes/wikihow/index.js'));
router.get('/wikihow/category/:category/:type', require('./routes/wikihow/category.js'));
// 正版中国
router.get('/getitfree/category/:category?', require('./routes/getitfree/category.js'));
router.get('/getitfree/search/:keyword?', require('./routes/getitfree/search.js'));
module.exports = router;
+59
View File
@@ -0,0 +1,59 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
const utils = require('./utils');
module.exports = async (ctx) => {
const { category = 'all' } = ctx.params;
const baseUrl = `https://getitfree.cn`;
const categoryToLabel = {
'8': 'PC',
'17': 'Android',
'50': 'Mac',
'309': '限时折扣',
'310': '限时免费',
'311': '永久免费',
'312': 'UWP',
all: '全部文章',
};
let item = [];
if (category === 'all') {
const res = await got(baseUrl);
const $ = cheerio.load(res.data);
$('#page-content .top-content .top-slide > .item')
.toArray()
.forEach((ele) => {
const $item = cheerio.load(ele);
const infoNode = $item('.slider-image > a');
const title = infoNode.attr('title');
const link = infoNode.attr('href');
const thumbnail = infoNode.attr('style').replace(/background-image:url\(|\)/g, '');
const deadlineStr = utils.getDeadlineStr($item, '.countDownCont');
const description = [title, deadlineStr, `<a href="${thumbnail}"/>`].filter((str) => !!str).join('<br/>');
item.push({
title,
link,
description,
});
});
item = item.concat(utils.parseListItem($, '.main-content'));
} else {
const res = await got(baseUrl, {
query: {
action: 'fa_load_postlist',
paged: 1,
category,
},
});
const $ = cheerio.load(res.data);
item = utils.parseListItem($, '.ajax-load-con');
}
const categoryLabel = categoryToLabel[category];
ctx.state.data = {
title: `正版中国 - ${categoryLabel}`,
description: `正版中国 - ${categoryLabel}`,
link: baseUrl,
item,
};
};
+25
View File
@@ -0,0 +1,25 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
const qs = require('query-string');
const utils = require('./utils');
module.exports = async (ctx) => {
const { keyword } = ctx.params;
const link = 'https://getitfree.cn';
const query = {
s: keyword,
};
const res = await got(link, {
query,
});
const $ = cheerio.load(res.data);
const item = utils.parseListItem($, '#page-content');
ctx.state.data = {
title: `正版中国搜索 - ${keyword}`,
description: `正版中国搜索 - ${keyword}`,
link: `${link}?${qs.stringify(query)}`,
item,
};
};
+47
View File
@@ -0,0 +1,47 @@
const cheerio = require('cheerio');
const getDeadlineStr = ($, countDownNodeSelector) => {
const countDownNode = $(countDownNodeSelector);
let deadlineStr = '';
if (countDownNode.text().includes('活动已经结束')) {
return '截至日期: 活动已经结束';
}
const countdownCodeStr = countDownNode.children('script').html() || '';
const arr = /ShowCountDown\("\d*"\s*,\s*([\d,]+)\s*\)/.exec(countdownCodeStr.trim());
if (arr) {
const dateStr = arr[1].replace(/,/g, (...args) => {
const index = args[args.length - 2];
return index === 10 ? ' ' : index < 10 ? '-' : ':';
});
deadlineStr = `截至日期: ${new Date(dateStr).toUTCString()}`;
}
return deadlineStr;
};
const parseListItem = ($, listSelector) =>
$(`${listSelector} .content-box`)
.map((_, ele) => {
const $item = cheerio.load(ele);
const infoNode = $item('.posts-default-title > h2 > a');
const title = infoNode.attr('title');
const link = infoNode.attr('href');
const pubDateStr = $item('.posts-default-info .icon-time').text();
const pubDate = new Date(pubDateStr).toUTCString();
const thumbnail = $item('.posts-default-img img').attr('data-original');
const deadlineStr = getDeadlineStr($item, '.countDownCont');
const digest = $item('.posts-default-content > .posts-text')
.text()
.trim();
return {
title,
link,
pubDate,
description: [title, deadlineStr, digest, `<img src="${thumbnail}"/>`].filter((str) => !!str).join('<br/>'),
};
})
.get();
module.exports = {
getDeadlineStr,
parseListItem,
};
+34
View File
@@ -0,0 +1,34 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
module.exports = async (ctx) => {
const { category, type = 'all' } = ctx.params;
const link = encodeURI(`https://zh.wikihow.com/Category:${category}`);
const res = await got(link);
const $ = cheerio.load(res.data);
const itemsSelector = type === 'all' ? '#cat_featured .thumbnail' : '#cat_all .thumbnail';
const item = $(itemsSelector)
.map((_, ele) => {
const $item = cheerio.load(ele);
const title = '如何' + $item('.text span').text();
const link = $item('a').attr('href');
const thumbnail = $item('img').attr('data-src');
return {
title,
description: `
${title}<br/>
<img src="${thumbnail}"/>
`,
link,
};
})
.get();
ctx.state.data = {
title: `wikiHow - ${category}`,
description: `wikiHow - ${category}`,
link,
item,
};
};
+32
View File
@@ -0,0 +1,32 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
module.exports = async (ctx) => {
const link = `https://zh.wikihow.com/${encodeURIComponent('首页')}`;
const res = await got(link);
const $ = cheerio.load(res.data);
const item = $('#fa_container td.image_map')
.map((_, ele) => {
const $item = cheerio.load(ele);
const title = '如何' + $item('.text span').text();
const link = $item('.thumbnail > a').attr('href');
const thumbnail = $item('.thumbnail img').attr('data-src');
return {
title,
description: `
${title}<br/>
<img src="${thumbnail}"/>
`,
link,
};
})
.get();
ctx.state.data = {
title: 'wikiHow - 首页',
description: 'wikiHow - 首页',
link,
item,
};
};