fix(route/csust): various fixes and improvements (#22704)
* fix(route/csust): self-contained routes, full title extraction, absolute URLs - Remove factory pattern from utils.ts, keep only getNoticeContent helper - Each route (tggs/xkxs) now self-contained with inline list parsing - Extract full title from article page <title> tag to avoid truncation - Convert relative URLs to absolute in article content * fix(route/csust): remove redundant logics
This commit is contained in:
parent
eeff5a3869
commit
d454ef8f47
|
|
@ -1,25 +1,48 @@
|
|||
import type { Route } from '@/types';
|
||||
import { load } from 'cheerio';
|
||||
|
||||
import { createCsustHandler } from './utils';
|
||||
import type { Data, DataItem, Route } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
import timezone from '@/utils/timezone';
|
||||
|
||||
const handler = createCsustHandler({
|
||||
listPath: '/tggs.htm',
|
||||
feedTitle: '长沙理工大学 - 通告公示',
|
||||
feedDescription: '长沙理工大学通告公示',
|
||||
});
|
||||
import { getNoticeContent } from './utils';
|
||||
|
||||
const baseUrl = 'https://www.csust.edu.cn';
|
||||
const listPath = '/tggs.htm';
|
||||
|
||||
async function handler(): Promise<Data> {
|
||||
const response = await got(`${baseUrl}${listPath}`);
|
||||
const $ = load(response.body);
|
||||
|
||||
const items: Array<DataItem & { link: string }> = $('.list ul li')
|
||||
.toArray()
|
||||
.map((li) => {
|
||||
const $li = $(li);
|
||||
|
||||
return {
|
||||
title: $li.find('.newTitle').text().trim(),
|
||||
link: new URL($li.find('a').attr('href')!, baseUrl).href,
|
||||
pubDate: timezone(parseDate($li.find('.data1').text().trim(), '发布时间 : YYYY-MM-DD'), 8),
|
||||
};
|
||||
});
|
||||
|
||||
const enrichedItems = await Promise.all(items.map((item) => cache.tryGet(item.link, () => getNoticeContent(item))));
|
||||
|
||||
return {
|
||||
title: '长沙理工大学 - 通告公示',
|
||||
link: `${baseUrl}${listPath}`,
|
||||
description: '长沙理工大学通告公示',
|
||||
item: enrichedItems,
|
||||
};
|
||||
}
|
||||
|
||||
export const route: Route = {
|
||||
path: '/tggs',
|
||||
categories: ['university'],
|
||||
example: '/csust/tggs',
|
||||
parameters: {},
|
||||
features: {
|
||||
requireConfig: false,
|
||||
requirePuppeteer: false,
|
||||
antiCrawler: false,
|
||||
supportBT: false,
|
||||
supportPodcast: false,
|
||||
supportScihub: false,
|
||||
supportRadar: true,
|
||||
},
|
||||
radar: [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,86 +1,26 @@
|
|||
import type { CheerioAPI } from 'cheerio';
|
||||
import { load } from 'cheerio';
|
||||
|
||||
import cache from '@/utils/cache';
|
||||
import type { DataItem } from '@/types';
|
||||
import got from '@/utils/got';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
|
||||
// 抓取并清清理内容
|
||||
export async function getNoticeContent(item: any) {
|
||||
type NoticeItem = DataItem & { link: string };
|
||||
|
||||
export async function getNoticeContent(item: NoticeItem): Promise<NoticeItem> {
|
||||
const response = await got(item.link);
|
||||
const $ = load(response.body);
|
||||
const pageTitle = $('title').text();
|
||||
|
||||
const $content = $('.v_news_content');
|
||||
$content.find('script, style, .vsbcontent_end').remove();
|
||||
$content.find('img[src], a[href]').each((_, element) => {
|
||||
const $element = $(element);
|
||||
const attribute = element.tagName === 'img' ? 'src' : 'href';
|
||||
$element.attr(attribute, new URL($element.attr(attribute)!, item.link).href);
|
||||
});
|
||||
|
||||
if ($content.length) {
|
||||
// 移除无用元素
|
||||
$content.find('script').remove();
|
||||
$content.find('style').remove();
|
||||
$content.find('.vsbcontent_end').remove();
|
||||
$content.find('iframe').remove();
|
||||
item.description = $content.html() || item.title;
|
||||
} else {
|
||||
item.description = item.title;
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
// 解析列表页面,返回包含标题、链接与发布日期的条目
|
||||
export function parseListItems($: CheerioAPI, baseUrl: string) {
|
||||
return $('.list ul li')
|
||||
.toArray()
|
||||
.map((li) => {
|
||||
const element = $(li);
|
||||
const title = element.find('.newTitle').text().trim();
|
||||
const linkRaw = element.find('a').attr('href');
|
||||
const dateText = element.find('.data1').text().trim();
|
||||
|
||||
if (!linkRaw || !title) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const dateMatch = dateText.match(/发布时间\s*[::]\s*(\d{4}-\d{1,2}-\d{1,2})/);
|
||||
const pubDate = dateMatch ? parseDate(dateMatch[1]) : null;
|
||||
|
||||
// 使用 URL 构造函数确保正确拼接 URL
|
||||
const link = linkRaw.startsWith('http') ? linkRaw : new URL(linkRaw, baseUrl).href;
|
||||
|
||||
return {
|
||||
title,
|
||||
link,
|
||||
pubDate,
|
||||
} as any;
|
||||
})
|
||||
.filter((i) => i !== null) as any[];
|
||||
}
|
||||
|
||||
// 通用处理器工厂:根据栏目路径与标题信息生成 handler
|
||||
export function createCsustHandler({ listPath, feedTitle, feedDescription }: { listPath: string; feedTitle: string; feedDescription: string }) {
|
||||
const baseUrl = 'https://www.csust.edu.cn';
|
||||
return async function () {
|
||||
const response = await got(`${baseUrl}${listPath}`);
|
||||
const $ = load(response.body);
|
||||
|
||||
const items = parseListItems($, baseUrl);
|
||||
|
||||
const item = await Promise.all(
|
||||
items.map((it) =>
|
||||
cache.tryGet(it.link, async () => {
|
||||
try {
|
||||
return await getNoticeContent(it);
|
||||
} catch {
|
||||
return it;
|
||||
}
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
return {
|
||||
title: feedTitle,
|
||||
link: `${baseUrl}${listPath}`,
|
||||
description: feedDescription,
|
||||
item,
|
||||
};
|
||||
return {
|
||||
...item,
|
||||
title: pageTitle.slice(0, pageTitle.lastIndexOf('-')).trim(),
|
||||
description: $content.html()!,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,25 +1,48 @@
|
|||
import type { Route } from '@/types';
|
||||
import { load } from 'cheerio';
|
||||
|
||||
import { createCsustHandler } from './utils';
|
||||
import type { Data, DataItem, Route } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
import timezone from '@/utils/timezone';
|
||||
|
||||
const handler = createCsustHandler({
|
||||
listPath: '/xkxs.htm',
|
||||
feedTitle: '长沙理工大学 - 学科学术',
|
||||
feedDescription: '长沙理工大学学科学术',
|
||||
});
|
||||
import { getNoticeContent } from './utils';
|
||||
|
||||
const baseUrl = 'https://www.csust.edu.cn';
|
||||
const listPath = '/xkxs.htm';
|
||||
|
||||
async function handler(): Promise<Data> {
|
||||
const response = await got(`${baseUrl}${listPath}`);
|
||||
const $ = load(response.body);
|
||||
|
||||
const items: Array<DataItem & { link: string }> = $('.list ul li')
|
||||
.toArray()
|
||||
.map((li) => {
|
||||
const $li = $(li);
|
||||
|
||||
return {
|
||||
title: $li.find('.newTitle').text().trim(),
|
||||
link: new URL($li.find('a').attr('href')!, baseUrl).href,
|
||||
pubDate: timezone(parseDate($li.find('.data1').text().trim(), '发布时间 : YYYY-MM-DD'), 8),
|
||||
};
|
||||
});
|
||||
|
||||
const enrichedItems = await Promise.all(items.map((item) => cache.tryGet(item.link, () => getNoticeContent(item))));
|
||||
|
||||
return {
|
||||
title: '长沙理工大学 - 学科学术',
|
||||
link: `${baseUrl}${listPath}`,
|
||||
description: '长沙理工大学学科学术',
|
||||
item: enrichedItems,
|
||||
};
|
||||
}
|
||||
|
||||
export const route: Route = {
|
||||
path: '/xkxs',
|
||||
categories: ['university'],
|
||||
example: '/csust/xkxs',
|
||||
parameters: {},
|
||||
features: {
|
||||
requireConfig: false,
|
||||
requirePuppeteer: false,
|
||||
antiCrawler: false,
|
||||
supportBT: false,
|
||||
supportPodcast: false,
|
||||
supportScihub: false,
|
||||
supportRadar: true,
|
||||
},
|
||||
radar: [
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue