mirror of
https://github.com/DIYgod/RSSHub.git
synced 2026-09-24 23:12:34 +08:00
feat(route): 新增 bing 搜索; 迁移 bing 每日图片到 v2; 新增 百度搜索; 迁移 搜狗特色LOGO 到 v2 规范;添加 搜狗搜索;添加 Google Search (#13936)
* fix(route): 修复 米游社 公告栏 template 错误 * feat(route): 新增 bing 搜索 * docs: Update other.mdx * docs: fix docs * feat(route): 新增 百度搜索 * fix(route): 修复 pubDate 解析错误 * fix(route): 优化 百度搜索的缓存,减轻反爬问题 * feat(route): 新增 360 搜索 * feat(route): 迁移 搜狗特色LOGO 到 v2 规范;添加 搜狗搜索 * fix(route): 百度搜索增加图片 * feat(route): 新增 Google Search * fix(route): 修复 百度搜索相关问题 * fix(route): 修复 Google 相关问题 * fix(route): 修复 360 搜索 * fix(route): 修复 搜狗搜索 * fix(route): 修复 await 问题 * fix: 移除 google sites * fix(route): 修复 缓存和过滤逻辑问题 * fix(route): 修复 360 搜索缺少 cookie 的问题 * fix(route): 修复 360 搜索 cookie 的问题 * feat(route): 移除 so.com 路由 * fix: merge conflict ---------
This commit is contained in:
+2
-2
@@ -376,7 +376,7 @@ router.get('/autotrader/:query', lazyloadRouteHandler('./routes/autotrader'));
|
||||
router.get('/geekpark/breakingnews', lazyloadRouteHandler('./routes/geekpark/breakingnews'));
|
||||
|
||||
// 搜狗
|
||||
router.get('/sogou/doodles', lazyloadRouteHandler('./routes/sogou/doodles'));
|
||||
// router.get('/sogou/doodles', lazyloadRouteHandler('./routes/sogou/doodles'));
|
||||
|
||||
// 香港天文台
|
||||
router.get('/hko/weather', lazyloadRouteHandler('./routes/hko/weather'));
|
||||
@@ -690,7 +690,7 @@ router.get('/digitaling/articles/:category/:subcate?', lazyloadRouteHandler('./r
|
||||
router.get('/digitaling/projects/:category', lazyloadRouteHandler('./routes/digitaling/project'));
|
||||
|
||||
// Bing壁纸
|
||||
router.get('/bing', lazyloadRouteHandler('./routes/bing/index'));
|
||||
// router.get('/bing', lazyloadRouteHandler('./routes/bing/index'));
|
||||
|
||||
// AlgoCasts
|
||||
router.get('/algocasts', lazyloadRouteHandler('./routes/algocasts/all'));
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
module.exports = {
|
||||
'/gushitong/index': ['CaoMeiYouRen'],
|
||||
'/search/:keyword': ['CaoMeiYouRen'],
|
||||
'/tieba/forum/good/:kw/:cid?/:sortBy?': ['u3u'],
|
||||
'/tieba/forum/:kw/:sortBy?': ['u3u'],
|
||||
'/tieba/post/:id': ['u3u'],
|
||||
|
||||
+12
-1
@@ -1,6 +1,17 @@
|
||||
module.exports = {
|
||||
'baidu.com': {
|
||||
_name: '百度',
|
||||
www: [
|
||||
{
|
||||
title: '搜索',
|
||||
docs: 'https://docs.rsshub.app/routes/other#bai-du-sou-suo',
|
||||
source: ['/'],
|
||||
target: (params, url) => {
|
||||
const keyword = new URL(url).searchParams.get('wd');
|
||||
return `/baidu/search/${keyword}`;
|
||||
},
|
||||
},
|
||||
],
|
||||
gushitong: [
|
||||
{
|
||||
title: '首页指数',
|
||||
@@ -73,7 +84,7 @@ module.exports = {
|
||||
top: [
|
||||
{
|
||||
title: '热搜榜单',
|
||||
docs: 'https://docs.rsshub.app/routes/other#bai-du-re-sou',
|
||||
docs: 'https://docs.rsshub.app/routes/other#bai-du-re-sou-bang-dan',
|
||||
source: ['/board'],
|
||||
target: (_, url) => `/baidu/top/${new URL(url).searchParams.get('tab')}`,
|
||||
},
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
module.exports = (router) => {
|
||||
router.get('/gushitong/index', require('./gushitong'));
|
||||
router.get('/search/:keyword', require('./search'));
|
||||
router.get('/tieba/forum/good/:kw/:cid?/:sortBy?', require('./tieba/forum'));
|
||||
router.get('/tieba/forum/:kw/:sortBy?', require('./tieba/forum'));
|
||||
router.get('/tieba/post/:id', require('./tieba/post'));
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
const got = require('@/utils/got');
|
||||
const cheerio = require('cheerio');
|
||||
const { art } = require('@/utils/render');
|
||||
const path = require('path');
|
||||
const renderDescription = (description, images) => art(path.join(__dirname, './templates/description.art'), { description, images });
|
||||
const config = require('@/config').value;
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const { keyword } = ctx.params;
|
||||
const url = `https://www.baidu.com/s?wd=${encodeURIComponent(keyword)}`;
|
||||
const key = `baidu-search:${url}`;
|
||||
|
||||
const items = await ctx.cache.tryGet(
|
||||
key,
|
||||
async () => {
|
||||
const response = (await got(url)).data;
|
||||
const visitedLinks = new Set();
|
||||
const $ = cheerio.load(response);
|
||||
const contentLeft = $('#content_left');
|
||||
const containers = contentLeft.find('.c-container');
|
||||
return containers
|
||||
.map((i, el) => {
|
||||
const element = $(el);
|
||||
const link = element.find('h3 a').first().attr('href');
|
||||
if (link && !visitedLinks.has(link)) {
|
||||
visitedLinks.add(link);
|
||||
const imgs = element
|
||||
.find('img')
|
||||
.map((_j, _el) => $(_el).attr('src'))
|
||||
.toArray();
|
||||
const description = element.find('.c-gap-top-small [class^="content-right_"]').first().text() || element.find('.c-row').first().text() || element.find('.cos-row').first().text();
|
||||
return {
|
||||
title: element.find('h3').first().text(),
|
||||
description: renderDescription(description, imgs),
|
||||
link: element.find('h3 a').first().attr('href'),
|
||||
author: element.find('.c-row .c-color-gray').first().text() || '',
|
||||
};
|
||||
}
|
||||
return null;
|
||||
})
|
||||
.toArray()
|
||||
.filter((e) => e?.link);
|
||||
},
|
||||
config.cache.routeExpire,
|
||||
false
|
||||
);
|
||||
|
||||
ctx.state.data = {
|
||||
title: `${keyword} - 百度搜索`,
|
||||
description: `${keyword} - 百度搜索`,
|
||||
link: url,
|
||||
item: items,
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,6 @@
|
||||
{{@ description }}
|
||||
{{if images}}
|
||||
{{each images}}
|
||||
<img src="{{ $value }}">
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
@@ -1,22 +1,21 @@
|
||||
const got = require('@/utils/got');
|
||||
const queryString = require('query-string');
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const response = await got({
|
||||
method: 'get',
|
||||
prefixUrl: 'https://cn.bing.com',
|
||||
url: 'HPImageArchive.aspx',
|
||||
searchParams: queryString.stringify({
|
||||
searchParams: {
|
||||
format: 'js',
|
||||
idx: 0,
|
||||
n: 7,
|
||||
n: ctx.query.limit ? parseInt(ctx.query.limit, 10) : 7,
|
||||
mkt: 'zh-CN',
|
||||
}),
|
||||
},
|
||||
});
|
||||
const data = response.data;
|
||||
ctx.state.data = {
|
||||
title: 'Bing每日壁纸',
|
||||
link: `https://cn.bing.com/`,
|
||||
link: 'https://cn.bing.com/',
|
||||
item: data.images.map((item) => ({
|
||||
title: item.copyright,
|
||||
description: `<img src="https://cn.bing.com${item.url}">`,
|
||||
@@ -0,0 +1,4 @@
|
||||
module.exports = {
|
||||
'/': ['FHYunCai'],
|
||||
'/search/:keyword': ['CaoMeiYouRen'],
|
||||
};
|
||||
@@ -0,0 +1,22 @@
|
||||
module.exports = {
|
||||
'bing.com': {
|
||||
_name: 'Bing',
|
||||
cn: [
|
||||
{
|
||||
title: '每日壁纸',
|
||||
docs: 'https://docs.rsshub.app/routes/picture#bing',
|
||||
source: '/',
|
||||
target: '/bing',
|
||||
},
|
||||
{
|
||||
title: '搜索',
|
||||
docs: 'https://docs.rsshub.app/routes/other#bing',
|
||||
source: '/',
|
||||
target: (params, url) => {
|
||||
const q = new URL(url).searchParams.get('q');
|
||||
return `/bing/search/${q}`;
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,4 @@
|
||||
module.exports = function (router) {
|
||||
router.get('/', require('./daily-wallpaper'));
|
||||
router.get('/search/:keyword', require('./search'));
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
const parser = require('@/utils/rss-parser');
|
||||
const { parseDate } = require('@/utils/parse-date');
|
||||
const dayjs = require('dayjs');
|
||||
const localizedFormat = require('dayjs/plugin/localizedFormat');
|
||||
require('dayjs/locale/zh-cn');
|
||||
dayjs.extend(localizedFormat);
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const q = ctx.params.keyword;
|
||||
const searchParams = new URLSearchParams({
|
||||
format: 'rss',
|
||||
q,
|
||||
});
|
||||
const url = new URL('https://cn.bing.com/search');
|
||||
url.search = searchParams.toString();
|
||||
const data = await parser.parseURL(url.toString());
|
||||
ctx.state.data = {
|
||||
title: data.title,
|
||||
link: data.link,
|
||||
description: data.description + ' - ' + data.copyright,
|
||||
image: data.image.url,
|
||||
item: data.items.map((e) => ({
|
||||
...e,
|
||||
description: e.content,
|
||||
pubDate: parseDate(e.pubDate, 'dddd, DD MMM YYYY HH:mm:ss [GMT]', 'zh-cn'),
|
||||
})),
|
||||
};
|
||||
};
|
||||
@@ -6,6 +6,7 @@ module.exports = {
|
||||
'/fonts/:sort?': ['Fatpandac'],
|
||||
'/news/:category/:locale': ['zoenglinghou'],
|
||||
'/scholar/:query': ['HenryQW'],
|
||||
'/search/:keyword/:language?': ['CaoMeiYouRen'],
|
||||
'/sites/:id': ['hoilc'],
|
||||
'/sites/recentChanges/:id': ['nczitzk'],
|
||||
};
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
module.exports = {
|
||||
'google.com': {
|
||||
_name: '谷歌',
|
||||
www: [
|
||||
{
|
||||
title: '搜索',
|
||||
docs: 'https://docs.rsshub.app/routes/other#google',
|
||||
source: '/',
|
||||
target: (params, url, document) => {
|
||||
const q = new URL(url).searchParams.get('q');
|
||||
const lang = document.documentElement.lang;
|
||||
return `/google/search/${q}/${lang}`;
|
||||
},
|
||||
},
|
||||
],
|
||||
chrome: [
|
||||
{
|
||||
title: '插件更新',
|
||||
|
||||
@@ -6,4 +6,5 @@ module.exports = function (router) {
|
||||
router.get('/fonts/:sort?', require('./fonts'));
|
||||
router.get('/news/:category/:locale', require('./news'));
|
||||
router.get('/scholar/:query', require('./scholar'));
|
||||
router.get('/search/:keyword/:language?', require('./search'));
|
||||
};
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
const got = require('@/utils/got');
|
||||
const cheerio = require('cheerio');
|
||||
const { art } = require('@/utils/render');
|
||||
const path = require('path');
|
||||
const config = require('@/config').value;
|
||||
|
||||
const renderDescription = (description, images) => art(path.join(__dirname, './templates/description.art'), { description, images });
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const { keyword, language } = ctx.params;
|
||||
const searchParams = new URLSearchParams({
|
||||
q: keyword,
|
||||
});
|
||||
const tempUrl = new URL('https://www.google.com/search');
|
||||
tempUrl.search = searchParams.toString();
|
||||
const url = tempUrl.toString();
|
||||
const key = `google-search:${language}:${url}`;
|
||||
const items = await ctx.cache.tryGet(
|
||||
key,
|
||||
async () => {
|
||||
const response = (
|
||||
await got(url, {
|
||||
headers: {
|
||||
'Accept-Language': language,
|
||||
},
|
||||
})
|
||||
).data;
|
||||
const $ = cheerio.load(response);
|
||||
const content = $('#rso');
|
||||
return content
|
||||
.find('> div')
|
||||
.map((i, el) => {
|
||||
const element = $(el);
|
||||
const link = element.find('div > div > div > div > div > span > a').first().attr('href');
|
||||
const title = element.find('div > div > div> div > div > span > a > h3').first().text();
|
||||
const imgs = element
|
||||
.find('img')
|
||||
.map((_j, _el) => $(_el).attr('src'))
|
||||
.toArray();
|
||||
const description = element.find('div[style="-webkit-line-clamp:2"]').first().text() || element.find('div[role="heading"]').first().text();
|
||||
const author = element.find('div > div > div > div > div > span > a > div > div > span').first().text() || '';
|
||||
return {
|
||||
link,
|
||||
title,
|
||||
description: renderDescription(description, imgs),
|
||||
author,
|
||||
};
|
||||
})
|
||||
.toArray()
|
||||
.filter((e) => e?.link);
|
||||
},
|
||||
config.cache.routeExpire,
|
||||
false
|
||||
);
|
||||
|
||||
ctx.state.data = {
|
||||
title: `${keyword} - Google Search`,
|
||||
description: `${keyword} - Google Search`,
|
||||
link: url,
|
||||
item: items,
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,6 @@
|
||||
{{@ description }}
|
||||
{{if images}}
|
||||
{{each images}}
|
||||
<img src="{{ $value }}">
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
@@ -0,0 +1,4 @@
|
||||
module.exports = {
|
||||
'/doodles': ['xyqfer'],
|
||||
'/search/:keyword': ['CaoMeiYouRen'],
|
||||
};
|
||||
@@ -0,0 +1,16 @@
|
||||
module.exports = {
|
||||
'sogou.com': {
|
||||
_name: '搜狗',
|
||||
www: [
|
||||
{
|
||||
title: '搜索',
|
||||
docs: 'https://docs.rsshub.app/routes/other#sou-gou-sou-suo',
|
||||
source: '/',
|
||||
target: (params, url) => {
|
||||
const keyword = new URL(url).searchParams.get('query');
|
||||
return `/sogou/search/${keyword}`;
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,4 @@
|
||||
module.exports = function (router) {
|
||||
router.get('/doodles', require('./doodles'));
|
||||
router.get('/search/:keyword', require('./search'));
|
||||
};
|
||||
@@ -0,0 +1,54 @@
|
||||
const got = require('@/utils/got');
|
||||
const cheerio = require('cheerio');
|
||||
const { art } = require('@/utils/render');
|
||||
const path = require('path');
|
||||
const { parseDate } = require('@/utils/parse-date');
|
||||
const config = require('@/config').value;
|
||||
|
||||
const renderDescription = (description, images) => art(path.join(__dirname, './templates/description.art'), { description, images });
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const { keyword } = ctx.params;
|
||||
const url = `https://www.sogou.com/web?query=${encodeURIComponent(keyword)}`;
|
||||
const key = `sogou-search:${url}`;
|
||||
const items = await ctx.cache.tryGet(
|
||||
key,
|
||||
async () => {
|
||||
const response = (await got(url)).data;
|
||||
const $ = cheerio.load(response);
|
||||
const result = $('#main');
|
||||
return result
|
||||
.find('.vrwrap')
|
||||
.map((i, el) => {
|
||||
const element = $(el);
|
||||
const imgs = element
|
||||
.find('img')
|
||||
.map((j, el2) => $(el2).attr('src'))
|
||||
.toArray();
|
||||
const link = element.find('h3 a').first().attr('href');
|
||||
const title = element.find('h3').first().text();
|
||||
const description = element.find('.text-layout').first().text() || element.find('.space-txt').first().text() || element.find('[class^="translate"]').first().text();
|
||||
const author = element.find('.citeurl span').first().text() || '';
|
||||
const pubDate = parseDate(element.find('.citeurl .cite-date').first().text().trim());
|
||||
return {
|
||||
link,
|
||||
title,
|
||||
description: renderDescription(description, imgs),
|
||||
author,
|
||||
pubDate,
|
||||
};
|
||||
})
|
||||
.toArray()
|
||||
.filter((e) => e?.link);
|
||||
},
|
||||
config.cache.routeExpire,
|
||||
false
|
||||
);
|
||||
|
||||
ctx.state.data = {
|
||||
title: `${keyword} - 搜狗搜索`,
|
||||
description: `${keyword} - 搜狗搜索`,
|
||||
link: url,
|
||||
item: items,
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,6 @@
|
||||
{{@ description }}
|
||||
{{if images}}
|
||||
{{each images}}
|
||||
<img src="{{ $value }}">
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
@@ -91,6 +91,12 @@ See [#app-store-mac-app-store](/routes/program-update#app-store-mac-app-store)
|
||||
2. Copy everything in the URL after `?`, for example: `https://www.autotrader.co.uk/car-search?radius=50&postcode=sw1a1aa&onesearchad=Used&onesearchad=Nearly%20New&onesearchad=New&price-to=9000&year-from=2012&body-type=Hatchback&transmission=Automatic&exclude-writeoff-categories=on` will produce `radius=50&postcode=sw1a1aa&onesearchad=Used&onesearchad=Nearly%20New&onesearchad=New&price-to=9000&year-from=2012&body-type=Hatchback&transmission=Automatic&exclude-writeoff-categories=on`
|
||||
</Route>
|
||||
|
||||
## Bing {#bing}
|
||||
|
||||
### 搜索 {#bing-sou-suo}
|
||||
|
||||
<Route author="CaoMeiYouRen" example="/bing/search/rss" path="/bing/search/:keyword" paramsDesc={['搜索关键词']} radar="1" />
|
||||
|
||||
## BOOKWALKERTW {#bookwalkertw}
|
||||
|
||||
### 热门新书 {#bookwalkertw-re-men-xin-shu}
|
||||
@@ -181,6 +187,10 @@ Official Website: [https://news.yahoo.co.jp/pages/article/20200207](https://news
|
||||
|
||||
<Route author="TonyRL" example="/google/alerts/RSSHub" path="/google/alerts/:keyword" paramsDesc={['Keyword']} />
|
||||
|
||||
### Search {#google-search}
|
||||
|
||||
<Route author="CaoMeiYouRen" example="/google/search/rss/zh-CN,zh" path="/google/search/:keyword/:language?" paramsDesc={['Keyword','Accept-Language. Example: zh-CN,zh;q=0.9,en;q=0.8,ja;q=0.7']} />
|
||||
|
||||
## Grand-Challenge {#grand-challenge}
|
||||
|
||||
### Challenge 列表 {#grand-challenge-challenge-lie-biao}
|
||||
@@ -597,9 +607,13 @@ Specify options (in the format of query string) in parameter `routeParams` param
|
||||
|
||||
<Route author="sanmmm" example="/afdian/dynamic/@afdian" path="/afdian/dynamic/:uid?" paramsDesc={['用户id,用户动态页面url里可找到']} />
|
||||
|
||||
## 百度热搜 {#bai-du-re-sou}
|
||||
## 百度 {#bai-du}
|
||||
|
||||
### 榜单 {#bai-du-re-sou-bang-dan}
|
||||
### 搜索 {#bai-du-sou-suo}
|
||||
|
||||
<Route author="CaoMeiYouRen" example="/baidu/search/rss" path="/baidu/search/:keyword" paramsDesc={['搜索关键词']} radar="1" anticrawler="1" />
|
||||
|
||||
### 热搜榜单 {#bai-du-re-sou-bang-dan}
|
||||
|
||||
<Route author="xyqfer" example="/baidu/top" path="/baidu/top/:board?" paramsDesc={['榜单,默认为 `realtime`']} radar="1">
|
||||
| 热搜榜 | 小说榜 | 电影榜 | 电视剧榜 | 汽车榜 | 游戏榜 |
|
||||
@@ -851,10 +865,14 @@ Specify options (in the format of query string) in parameter `routeParams` param
|
||||
|
||||
## 搜狗 {#sou-gou}
|
||||
|
||||
### 搜狗特色 LOGO {#sou-gou-sou-gou-te-se-logo}
|
||||
### 特色 LOGO {#sou-gou-te-se-logo}
|
||||
|
||||
<Route author="xyqfer" example="/sogou/doodles" path="/sogou/doodles" />
|
||||
|
||||
### 搜索 {#sou-gou-sou-suo}
|
||||
|
||||
<Route author="CaoMeiYouRen" example="/sogou/search/rss" path="/sogou/search/:keyword" paramsDesc={['搜索关键词']} radar="1" />
|
||||
|
||||
## 台灣事實查核中心 {#tai-wan-shi-shi-cha-he-zhong-xin}
|
||||
|
||||
### 最新相關資訊 / 最新查核報告 {#tai-wan-shi-shi-cha-he-zhong-xin-zui-xin-xiang-guan-zi-xun-zui-xin-cha-he-bao-gao}
|
||||
|
||||
@@ -165,9 +165,9 @@
|
||||
|
||||
<Route author="nczitzk" example="/asiantolick/page/news" path="/asiantolick/page/:id" paramsDesc={['Page id']} radar="1" />
|
||||
|
||||
## Bing Wallpaper {#bing-wallpaper}
|
||||
## Bing {#bing}
|
||||
|
||||
### Daily Wallpaper {#bing-wallpaper-daily-wallpaper}
|
||||
### Daily Wallpaper {#bing-daily-wallpaper}
|
||||
|
||||
<Route author="FHYunCai" example="/bing" path="/bing" radar="1" />
|
||||
|
||||
|
||||
Reference in New Issue
Block a user