rsshub
Version:
Make RSS Great Again!
144 lines (136 loc) • 5.82 kB
text/typescript
import { DataItem, Route } from '@/types';
import cache from '@/utils/cache';
import { load } from 'cheerio';
import got from '@/utils/got';
import { parseDate } from '@/utils/parse-date';
import timezone from '@/utils/timezone';
export const route: Route = {
path: '/rail/:category?/:topic?',
categories: ['new-media'],
example: '/ally/rail/hyzix/chengguijiaotong',
parameters: { category: '分类,可在 URL 中找到;略去则抓取首页', topic: '话题,可在 URL 中找到;并非所有页面均有此字段' },
features: {
requireConfig: false,
requirePuppeteer: false,
antiCrawler: false,
supportBT: false,
supportPodcast: false,
supportScihub: false,
},
radar: [
{
source: ['rail.ally.net.cn/', 'rail.ally.net.cn/html/:category?/:topic?'],
},
],
name: '世界轨道交通资讯网',
maintainers: ['Rongronggg9'],
handler,
url: 'rail.ally.net.cn/',
description: `::: tip
默认抓取前 20 条,可通过 \`?limit=\` 改变。
:::`,
};
async function handler(ctx) {
// http://rail.ally.net.cn/sitemap.html
const { category, topic } = ctx.req.param();
const rootUrl = 'http://rail.ally.net.cn';
const pageUrl = category ? (topic ? `${rootUrl}/html/${category}/${topic}/` : `${rootUrl}/html/${category}/`) : rootUrl;
const response = await got.get(pageUrl);
const $ = load(response.data);
let title = '';
const titleLinks = $('.container .regsiter a').toArray().slice(1); // what a typo... drop "首页"
for (const link of titleLinks) {
const linkText = $(link).text();
title = title ? `${title} - ${linkText}` : linkText;
}
title = title || (category && topic ? `${category} - ${topic}` : category) || '首页';
let links = [
// list page: http://rail.ally.net.cn/html/lujuzixun/
$('.left .hynewsO h2 a').toArray(),
// multi-sub-topic page: http://rail.ally.net.cn/html/hyzix/
$('.left .list_content_c').find('.new_hy_focus_con_tit a, .new_hy_list_name a').toArray(),
// multi-sub-topic page 2: http://rail.ally.net.cn/html/foster/
$('.left').find('.nnewslistpic a, .nnewslistinfo dd a').toArray(),
// data list page: http://rail.ally.net.cn/html/tongjigongbao/
$('.left .list_con .datacountTit a').toArray(),
// home page: http://rail.ally.net.cn
$('.container_left').find('dd a, h1 a, ul.slideshow li a').toArray(),
].flat();
if (!links.length) {
// try aggressively sniffing links, e.g. http://rail.ally.net.cn/html/InviteTen/
links = $('.left a, .container_left a').toArray();
}
let items = links
.map((link) => {
link = $(link);
const url = link.attr('href');
const urlMatch = url && url.match(/\/html\/(\d{4})\/\w+_(\d{4})\/\d+\.html/);
if (!urlMatch) {
return null;
}
const title = link.text();
return {
title,
link: url.startsWith('/') ? `${rootUrl}${url}` : url,
pubDate: timezone(parseDate(`${urlMatch[1]}${urlMatch[2]}`), 8),
};
})
.filter(Boolean);
const uniqueItems: DataItem[] = [];
for (const item of items) {
if (!uniqueItems.some((uniqueItem) => uniqueItem.link === item?.link)) {
uniqueItems.push(item!);
}
}
items = uniqueItems.sort((a, b) => b.pubDate - a.pubDate).slice(0, ctx.req.query('limit') || 20);
items = await Promise.all(
items.map((item) =>
cache.tryGet(item.link, async () => {
const response = await got(item.link);
const $ = load(response.data);
// fix weird format
let description = '';
const content = $('div.content_all');
if (content.length) {
content
.eq(content.length - 1) // some pages have "summary"
.contents()
.each((_, child) => {
const $child = $(child);
let innerHtml;
if (child.name === 'div') {
innerHtml = $child.html();
innerHtml = innerHtml && innerHtml.trim();
description += !innerHtml || innerHtml === ' ' ? (description ? '<br>' : '') : innerHtml;
} else {
// bare text node or something else
description += $child.toString().trim();
}
});
} else {
// http://rail.ally.net.cn/html/2022/InviteTen_0407/4686.html
description = $('div.content div').first().html();
}
description = description.replace(/\s*<br ?\/?>\s*$/, ''); // trim <br> at the end
const info = $('.content > em span');
return {
title: $('.content > h2').text() || item.title,
description,
// pubDate: timezone(parseDate(info.eq(0).text()), 8),
pubDate: item.pubDate,
author: info
.eq(1)
.text()
.replace(/^来源:/, ''),
link: item.link,
};
})
)
);
return {
title: `世界轨道交通资讯网 - ${title}`,
link: pageUrl,
item: items,
description: $('head > meta[name="description"]').attr('content'),
};
}