feat(route): add AI 博客 (#20488)
* feat(route): add AI 博客 新增了一个归档路由处理函数,用于抓取AI博客的所有文章归档。 - 定义了一个新的路由配置对象`route`,路径为`/archives`,属于`blog`类别。 - 使用`ofetch`获取归档页面内容,并通过`cheerio`解析HTML。 - 遍历每个月份分组内的每篇文章,提取标题、链接、发布时间,并存储在列表中。 - 对列表中的每个条目,使用`cache.tryGet`缓存文章详情,若无缓存则再次使用`ofetch`获取,并解析出文章的主要内容。 - 返回处理后的结果对象,包含优化后的标题、归档页面链接以及过滤无效数据后的文章列表。 新增了一个命名空间配置对象`namespace`,用于定义AI博客的基本信息。 - 定义了一个新的命名空间配置对象`namespace`,包含站点名称、URL和语言。 * refactor(handler): 优化归档页面处理逻辑 - 使用 `toArray()` 和 `flatMap()` 方法简化了遍历每个月份分组和提取文章信息的代码逻辑。 - 修正了 `link` 属性的处理,确保当链接不存在时返回空字符串。 - 添加了 `author` 和 `description` 属性到文章对象中,以便更完整地描述文章内容。 - 精简了每个文章项的 `description` 构建,去除了不必要的 HTML 结构复制。
This commit is contained in:
parent
92032a8c51
commit
6e5409d7eb
|
|
@ -0,0 +1,92 @@
|
|||
import { Route } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import ofetch from '@/utils/ofetch';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
import { load } from 'cheerio';
|
||||
|
||||
export const route: Route = {
|
||||
path: '/archives',
|
||||
categories: ['blog'],
|
||||
example: '/aiblog-2xv/archives',
|
||||
parameters: {},
|
||||
features: {
|
||||
requireConfig: false,
|
||||
requirePuppeteer: false,
|
||||
antiCrawler: false,
|
||||
supportBT: false,
|
||||
supportPodcast: false,
|
||||
supportScihub: false,
|
||||
},
|
||||
radar: [
|
||||
{
|
||||
source: ['aiblog-2xv.pages.dev/archives'],
|
||||
target: '/archives',
|
||||
},
|
||||
],
|
||||
name: '归档-全部文章',
|
||||
maintainers: ['Liao-Ke'],
|
||||
handler,
|
||||
};
|
||||
|
||||
async function handler() {
|
||||
const baseUrl = 'https://aiblog-2xv.pages.dev';
|
||||
const response = await ofetch(`${baseUrl}/archives`);
|
||||
const $ = load(response);
|
||||
|
||||
// 遍历每个月份分组
|
||||
const list = $('#top > main > div > div.archive-month')
|
||||
.toArray()
|
||||
.flatMap((monthItem) =>
|
||||
$(monthItem)
|
||||
.find('.archive-posts .archive-entry')
|
||||
.toArray()
|
||||
.map((postItem) => {
|
||||
const $post = $(postItem);
|
||||
const $link = $post.find('a').first();
|
||||
const $title = $post.find('h3').first();
|
||||
const $dateMeta = $post.find('.archive-meta span');
|
||||
|
||||
return {
|
||||
title: $title.text().trim(), // 去除首尾空格
|
||||
link: $link.attr('href') || '',
|
||||
// 解析发布时间和更新时间(根据页面结构调整选择器,若存在则启用)
|
||||
pubDate: parseDate($dateMeta.eq(0).attr('title') || ''),
|
||||
author: $post.find('.archive-meta span').last().text().trim() || '',
|
||||
description: '',
|
||||
};
|
||||
})
|
||||
);
|
||||
|
||||
const items = await Promise.all(
|
||||
list.map((item) =>
|
||||
cache.tryGet(item.link, async () => {
|
||||
const response = await ofetch(item.link);
|
||||
const $ = load(response);
|
||||
|
||||
const $main = $('main').first();
|
||||
item.description = `<article>
|
||||
<header>
|
||||
<div class="post-description">
|
||||
${$main.find('header .post-description').first().html()}
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<figure class="entry-cover">
|
||||
${$main.find('figure').first().html()}
|
||||
</figure>
|
||||
|
||||
<div class="post-content">
|
||||
${$main.find('.post-content').first().html()}
|
||||
</div>
|
||||
</article>`;
|
||||
return item;
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
return {
|
||||
title: '归档-全部文章 | AI Blog', // 优化标题,增加站点标识
|
||||
link: `${baseUrl}/archives`,
|
||||
item: items.filter((item) => item.title && item.link), // 过滤无效数据
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
import type { Namespace } from '@/types';
|
||||
|
||||
export const namespace: Namespace = {
|
||||
name: 'AI 博客',
|
||||
url: 'aiblog-2xv.pages.dev',
|
||||
lang: 'zh-CN',
|
||||
};
|
||||
Loading…
Reference in New Issue