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:
CaoMeiYouRen
2023-12-25 23:14:21 +08:00
committed by GitHub
parent d2d115da42
commit bbee9f247d
24 changed files with 327 additions and 13 deletions
+2 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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'));
+54
View File
@@ -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,
};
};
+6
View File
@@ -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}">`,
+4
View File
@@ -0,0 +1,4 @@
module.exports = {
'/': ['FHYunCai'],
'/search/:keyword': ['CaoMeiYouRen'],
};
+22
View File
@@ -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}`;
},
},
],
},
};
+4
View File
@@ -0,0 +1,4 @@
module.exports = function (router) {
router.get('/', require('./daily-wallpaper'));
router.get('/search/:keyword', require('./search'));
};
+28
View File
@@ -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'),
})),
};
};
+1
View File
@@ -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'],
};
+12
View File
@@ -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: '插件更新',
+1
View File
@@ -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'));
};
+62
View File
@@ -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,
};
};
+6
View File
@@ -0,0 +1,6 @@
{{@ description }}
{{if images}}
{{each images}}
<img src="{{ $value }}">
{{/each}}
{{/if}}
+4
View File
@@ -0,0 +1,4 @@
module.exports = {
'/doodles': ['xyqfer'],
'/search/:keyword': ['CaoMeiYouRen'],
};
+16
View File
@@ -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}`;
},
},
],
},
};
+4
View File
@@ -0,0 +1,4 @@
module.exports = function (router) {
router.get('/doodles', require('./doodles'));
router.get('/search/:keyword', require('./search'));
};
+54
View File
@@ -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,
};
};
+6
View File
@@ -0,0 +1,6 @@
{{@ description }}
{{if images}}
{{each images}}
<img src="{{ $value }}">
{{/each}}
{{/if}}
+21 -3
View File
@@ -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}
+2 -2
View File
@@ -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" />