feat(route): cw author (#11618)

This commit is contained in:
Tony 2023-01-13 08:49:36 -05:00 committed by GitHub
parent b0253d09d8
commit 2502bef792
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 88 additions and 62 deletions

View File

@ -2071,6 +2071,10 @@ category 对应的关键词有
<Route author="TonyRL" example="/cw/sub/615" path="/cw/sub/:channel" :paramsDesc="['子頻道 ID可在 URL 中找到']" radar="1" rssbud="1" puppeteer="1"/>
### 作者
<Route author="TonyRL" example="/cw/author/57" path="/cw/author/:channel" :paramsDesc="['作者 ID可在 URL 中找到']" radar="1" rssbud="1" puppeteer="1"/>
## 卫报 The Guardian
通过提取文章全文,以提供比官方源更佳的阅读体验。

18
lib/v2/cw/author.js Normal file
View File

@ -0,0 +1,18 @@
const { baseUrl, parsePage } = require('./utils');
module.exports = async (ctx) => {
const browser = await require('@/utils/puppeteer')();
const { $, items } = await parsePage('author', browser, ctx);
await browser.close();
ctx.state.data = {
title: $('head title').text(),
description: $('.authorTxt').text(),
link: `${baseUrl}/author/${ctx.params.channel}`,
image: $('.authorPhoto img').attr('src') || `${baseUrl}/assets_new/img/fbshare.jpg'`,
language: $('meta[property="og:locale"]').attr('content'),
item: items,
};
};

View File

@ -1,4 +1,5 @@
module.exports = {
'/author/:channel': ['TonyRL'],
'/master/:channel': ['TonyRL'],
'/sub/:channel': ['TonyRL'],
'/today': ['TonyRL'],

View File

@ -1,34 +1,16 @@
const cheerio = require('cheerio');
const { baseUrl, parseList, parseItems, getCookie, setCookies } = require('./utils');
const { baseUrl, parsePage } = require('./utils');
module.exports = async (ctx) => {
const { channel } = ctx.params;
const pageUrl = `${baseUrl}/masterChannel.action`;
const browser = await require('@/utils/puppeteer')();
const cookie = await getCookie(browser, ctx.cache.tryGet);
const page = await browser.newPage();
await page.setRequestInterception(true);
page.on('request', (request) => {
request.resourceType() === 'document' || request.resourceType() === 'script' ? request.continue() : request.abort();
});
await setCookies(page, cookie, 'cw.com.tw');
await page.goto(`${pageUrl}?idMasterChannel=${channel}`, {
waitUntil: 'domcontentloaded',
});
const response = await page.evaluate(() => document.documentElement.innerHTML);
await page.close();
const $ = cheerio.load(response);
const list = parseList($, ctx.query.limit ? Number(ctx.query.limit) : 12);
const items = await parseItems(list, browser, ctx.cache.tryGet);
const { $, items } = await parsePage('master', browser, ctx);
await browser.close();
ctx.state.data = {
title: $('head title').text(),
description: $('meta[name=description]').attr('content'),
link: `${baseUrl}/masterChannel.action?idMasterChannel=${ctx.params.channel}`,
image: `${baseUrl}/assets_new/img/fbshare.jpg`,
language: $('meta[property="og:locale"]').attr('content'),
item: items,

View File

@ -20,6 +20,12 @@ module.exports = {
source: ['/subchannel.action'],
target: (_, url) => `/cw/sub/${new URL(url).searchParams.get('idSubChannel')}`,
},
{
title: '作者',
docs: 'https://docs.rsshub.app/traditional-media.html#tian-xia-za-zhi',
source: ['/author/:channel'],
target: '/cw/author/:channel',
},
],
},
};

View File

@ -1,4 +1,5 @@
module.exports = (router) => {
router.get('/author/:channel', require('./author'));
router.get('/master/:channel', require('./master'));
router.get('/sub/:channel', require('./sub'));
router.get('/today', require('./today'));

View File

@ -1,34 +1,16 @@
const cheerio = require('cheerio');
const { baseUrl, parseList, parseItems, getCookie, setCookies } = require('./utils');
const { baseUrl, parsePage } = require('./utils');
module.exports = async (ctx) => {
const { channel } = ctx.params;
const pageUrl = `${baseUrl}/subchannel.action`;
const browser = await require('@/utils/puppeteer')();
const cookie = await getCookie(browser, ctx.cache.tryGet);
const page = await browser.newPage();
await page.setRequestInterception(true);
page.on('request', (request) => {
request.resourceType() === 'document' || request.resourceType() === 'script' ? request.continue() : request.abort();
});
await setCookies(page, cookie, 'cw.com.tw');
await page.goto(`${pageUrl}?idSubChannel=${channel}`, {
waitUntil: 'domcontentloaded',
});
const response = await page.evaluate(() => document.documentElement.innerHTML);
await page.close();
const $ = cheerio.load(response);
const list = parseList($, ctx.query.limit ? Number(ctx.query.limit) : 12);
const items = await parseItems(list, browser, ctx.cache.tryGet);
const { $, items } = await parsePage('sub', browser, ctx);
await browser.close();
ctx.state.data = {
title: $('head title').text(),
description: $('meta[name=description]').attr('content'),
link: `${baseUrl}/subchannel.action?idSubChannel=${ctx.params.channel}`,
image: `${baseUrl}/assets_new/img/fbshare.jpg`,
language: $('meta[property="og:locale"]').attr('content'),
item: items,

View File

@ -1,33 +1,16 @@
const cheerio = require('cheerio');
const { baseUrl, parseList, parseItems, getCookie, setCookies } = require('./utils');
const { baseUrl, parsePage } = require('./utils');
module.exports = async (ctx) => {
const pageUrl = `${baseUrl}/today`;
const browser = await require('@/utils/puppeteer')();
const cookie = await getCookie(browser, ctx.cache.tryGet);
const page = await browser.newPage();
await page.setRequestInterception(true);
page.on('request', (request) => {
request.resourceType() === 'document' || request.resourceType() === 'script' ? request.continue() : request.abort();
});
await setCookies(page, cookie, 'cw.com.tw');
await page.goto(pageUrl, {
waitUntil: 'domcontentloaded',
});
const response = await page.evaluate(() => document.documentElement.innerHTML);
await page.close();
const $ = cheerio.load(response);
const list = parseList($, ctx.query.limit ? Number(ctx.query.limit) : 30);
const items = await parseItems(list, browser, ctx.cache.tryGet);
const { $, items } = await parsePage('today', browser, ctx);
await browser.close();
ctx.state.data = {
title: $('head title').text(),
description: $('meta[name=description]').attr('content'),
link: `${baseUrl}/today`,
image: `${baseUrl}/assets_new/img/fbshare.jpg`,
language: $('meta[property="og:locale"]').attr('content'),
item: items,

View File

@ -1,10 +1,30 @@
const cheerio = require('cheerio');
const { parseDate } = require('@/utils/parse-date');
const { getCookies, setCookies } = require('@/utils/puppeteer-utils');
const logger = require('@/utils/logger');
let cookie;
const baseUrl = 'https://www.cw.com.tw';
const pathMap = {
today: {
pageUrl: () => '/today',
limit: 30,
},
master: {
pageUrl: (channel) => `/masterChannel.action?idMasterChannel=${channel}`,
limit: 12,
},
sub: {
pageUrl: (channel) => `/subchannel.action?idSubChannel=${channel}`,
limit: 12,
},
author: {
pageUrl: (channel) => `/author/${channel}`,
limit: 10,
},
};
const getCookie = async (browser, tryGet) => {
if (!cookie) {
cookie = await tryGet('cw:cookie', async () => {
@ -13,6 +33,7 @@ const getCookie = async (browser, tryGet) => {
page.on('request', (request) => {
request.resourceType() === 'document' || request.resourceType() === 'script' ? request.continue() : request.abort();
});
logger.debug(`Requesting ${baseUrl}/user/get/cookie-bar`);
await page.goto(`${baseUrl}/user/get/cookie-bar`, {
waitUntil: 'domcontentloaded',
});
@ -24,6 +45,31 @@ const getCookie = async (browser, tryGet) => {
return cookie;
};
const parsePage = async (path, browser, ctx) => {
const pageUrl = `${baseUrl}${pathMap[path].pageUrl(ctx.params.channel)}`;
const cookie = await getCookie(browser, ctx.cache.tryGet);
const page = await browser.newPage();
await page.setRequestInterception(true);
page.on('request', (request) => {
request.resourceType() === 'document' || request.resourceType() === 'script' ? request.continue() : request.abort();
});
await setCookies(page, cookie, 'cw.com.tw');
logger.debug(`Requesting ${pageUrl}`);
await page.goto(pageUrl, {
waitUntil: 'domcontentloaded',
});
const response = await page.evaluate(() => document.documentElement.innerHTML);
await page.close();
const $ = cheerio.load(response);
const list = parseList($, ctx.query.limit ? Number(ctx.query.limit) : pathMap[path].limit);
const items = await parseItems(list, browser, ctx.cache.tryGet);
return { $, items };
};
const parseList = ($, limit) =>
$('.caption')
.toArray()
@ -47,6 +93,7 @@ const parseItems = (list, browser, tryGet) =>
request.resourceType() === 'document' || request.resourceType() === 'script' ? request.continue() : request.abort();
});
await setCookies(page, cookie, 'cw.com.tw');
logger.debug(`Requesting ${item.link}`);
await page.goto(item.link, {
waitUntil: 'domcontentloaded',
});
@ -77,8 +124,10 @@ const parseItems = (list, browser, tryGet) =>
module.exports = {
baseUrl,
pathMap,
getCookie,
setCookies,
parsePage,
parseList,
parseItems,
};