mirror of
https://github.com/DIYgod/RSSHub.git
synced 2026-08-31 01:01:11 +08:00
fix(route/bloomberg): switch to official RSS feeds as news sitemaps were removed
Bloomberg removed all per-site news sitemaps (/feeds/{site}/sitemap_news.xml
now returns 404), which broke every section of this route.
- Fetch the official RSS feeds (/feeds/{site}/news.rss) instead, via ofetch
so PROXY_URI and the global request layer still apply
- Update section IDs to match the feeds Bloomberg currently serves, keeping
bpol/bbiz as backward-compatible aliases of politics/business
- Drop sections Bloomberg no longer provides (green, pursuits, equality,
citylab); add economics, industries and crypto
- Keep the full-text pipeline; pass the RSS summary through when the story
API is blocked so degraded items still have a description
Fixes #22787
This commit is contained in:
@@ -2,29 +2,37 @@ import pMap from 'p-map';
|
||||
|
||||
import type { Route } from '@/types';
|
||||
import { ViewType } from '@/types';
|
||||
import ofetch from '@/utils/ofetch';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
import rssParser from '@/utils/rss-parser';
|
||||
|
||||
import { parseArticle, parseNewsList, rootUrl } from './utils';
|
||||
import { parseArticle, rootUrl } from './utils';
|
||||
|
||||
const siteTitleMapping = {
|
||||
'/': 'News',
|
||||
bpol: 'Politics',
|
||||
bbiz: 'Business',
|
||||
politics: 'Politics',
|
||||
business: 'Business',
|
||||
markets: 'Markets',
|
||||
technology: 'Technology',
|
||||
green: 'Green',
|
||||
wealth: 'Wealth',
|
||||
pursuits: 'Pursuits',
|
||||
bview: 'Opinion',
|
||||
equality: 'Equality',
|
||||
businessweek: 'Businessweek',
|
||||
citylab: 'CityLab',
|
||||
economics: 'Economics',
|
||||
industries: 'Industries',
|
||||
crypto: 'Crypto',
|
||||
};
|
||||
|
||||
// Bloomberg removed the per-site news sitemaps; map legacy site IDs to the equivalent RSS feeds
|
||||
const legacySiteMapping = {
|
||||
bpol: 'politics',
|
||||
bbiz: 'business',
|
||||
};
|
||||
|
||||
export const route: Route = {
|
||||
path: '/:site?',
|
||||
categories: ['finance'],
|
||||
view: ViewType.Articles,
|
||||
example: '/bloomberg/bbiz',
|
||||
example: '/bloomberg/business',
|
||||
parameters: {
|
||||
site: {
|
||||
description: 'Site ID, can be found below',
|
||||
@@ -44,29 +52,37 @@ export const route: Route = {
|
||||
description: `| Site ID | Title |
|
||||
| ------------ | ------------ |
|
||||
| / | News |
|
||||
| bpol | Politics |
|
||||
| bbiz | Business |
|
||||
| politics | Politics |
|
||||
| business | Business |
|
||||
| markets | Markets |
|
||||
| technology | Technology |
|
||||
| green | Green |
|
||||
| wealth | Wealth |
|
||||
| pursuits | Pursuits |
|
||||
| bview | Opinion |
|
||||
| equality | Equality |
|
||||
| businessweek | Businessweek |
|
||||
| citylab | CityLab |`,
|
||||
| economics | Economics |
|
||||
| industries | Industries |
|
||||
| crypto | Crypto |
|
||||
|
||||
Legacy site IDs \`bpol\` and \`bbiz\` still work as aliases of \`politics\` and \`business\`.`,
|
||||
handler,
|
||||
};
|
||||
|
||||
async function handler(ctx) {
|
||||
const site = ctx.req.param('site');
|
||||
const currentUrl = site ? `${rootUrl}/${site}/sitemap_news.xml` : `${rootUrl}/sitemap_news.xml`;
|
||||
const mappedSite = site ? (legacySiteMapping[site] ?? site) : undefined;
|
||||
const currentUrl = mappedSite ? `${rootUrl}/${mappedSite}/news.rss` : `${rootUrl}/news.rss`;
|
||||
|
||||
const list = await parseNewsList(currentUrl, ctx);
|
||||
const feed = await rssParser.parseString(await ofetch(currentUrl));
|
||||
const list = feed.items.slice(0, ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit')) : 50).map((item) => ({
|
||||
title: item.title,
|
||||
link: item.link,
|
||||
pubDate: item.pubDate ? parseDate(item.pubDate) : undefined,
|
||||
description: item.content,
|
||||
}));
|
||||
const items = await pMap(list, (item) => parseArticle(item), { concurrency: 1 });
|
||||
return {
|
||||
title: `Bloomberg - ${siteTitleMapping[site ?? '/']}`,
|
||||
link: currentUrl,
|
||||
title: `Bloomberg - ${siteTitleMapping[mappedSite ?? '/'] ?? feed.title}`,
|
||||
link: feed.link ?? currentUrl,
|
||||
item: items,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ import { load } from 'cheerio';
|
||||
import { destr } from 'destr';
|
||||
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import ofetch from '@/utils/ofetch';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
|
||||
@@ -71,28 +70,6 @@ const redirectGot = (url) =>
|
||||
}),
|
||||
});
|
||||
|
||||
const parseNewsList = async (url, ctx) => {
|
||||
const resp = await got(url);
|
||||
const $ = load(resp.data, {
|
||||
xml: {
|
||||
xmlMode: true,
|
||||
},
|
||||
});
|
||||
const urls = $('urlset url');
|
||||
return urls
|
||||
.toArray()
|
||||
.slice(0, ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit')) : 50)
|
||||
.map((u) => {
|
||||
u = $(u);
|
||||
const item = {
|
||||
title: u.find(String.raw`news\:title`).text(),
|
||||
link: u.find('loc').text(),
|
||||
pubDate: parseDate(u.find(String.raw`news\:publication_date`).text()),
|
||||
};
|
||||
return item;
|
||||
});
|
||||
};
|
||||
|
||||
const parseArticle = (item) =>
|
||||
cache.tryGet(item.link, async () => {
|
||||
const group = regex
|
||||
@@ -119,6 +96,7 @@ const parseArticle = (item) =>
|
||||
title: item.title,
|
||||
link: item.link,
|
||||
pubDate: item.pubDate,
|
||||
description: item.description,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -130,6 +108,7 @@ const parseArticle = (item) =>
|
||||
title: item.title,
|
||||
link: item.link,
|
||||
pubDate: item.pubDate,
|
||||
description: item.description,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -611,4 +590,4 @@ const documentToHtmlString = async (document) => {
|
||||
return str;
|
||||
};
|
||||
|
||||
export { parseArticle, parseNewsList, rootUrl };
|
||||
export { parseArticle, rootUrl };
|
||||
|
||||
Reference in New Issue
Block a user