fix(route): xiaohongshu (#9888)

* fix(route): xiaohongshu

* docs: fix description
This commit is contained in:
Tony 2022-06-03 09:26:06 -08:00 committed by GitHub
parent b9bc6831a4
commit 695e297c4b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 86 additions and 43 deletions

View File

@ -1312,17 +1312,17 @@ rule
## 小红书
### 用户笔记和专辑
### 用户笔记
<Route author="lotosbin" example="/xiaohongshu/user/593032945e87e77791e03696/notes" path="/xiaohongshu/user/:user_id/notes" :paramsDesc="['user_id']" puppeteer="1"/>
<Route author="lotosbin" example="/xiaohongshu/user/593032945e87e77791e03696/notes" path="/xiaohongshu/user/:user_id/notes" :paramsDesc="['用户 ID']" puppeteer="1" anticrawler="1" radar="1" rssbud="1"/>
### 用户专辑
<Route author="lotosbin" example="/xiaohongshu/user/593032945e87e77791e03696/album" path="/xiaohongshu/user/:user_id/album" :paramsDesc="['user_id']" puppeteer="1"/>
<Route author="lotosbin" example="/xiaohongshu/user/593032945e87e77791e03696/album" path="/xiaohongshu/user/:user_id/album" :paramsDesc="['用户 ID']" puppeteer="1" anticrawler="1" radar="1" rssbud="1"/>
### 专辑
<Route author="lotosbin" example="/xiaohongshu/board/5db6f79200000000020032df" path="/xiaohongshu/board/:board_id" :paramsDesc="['board_id']" puppeteer="1"/>
<Route author="lotosbin" example="/xiaohongshu/board/5db6f79200000000020032df" path="/xiaohongshu/board/:board_id" :paramsDesc="['专辑 ID']" puppeteer="1" anticrawler="1" radar="1" rssbud="1"/>
## 新榜

View File

@ -2113,11 +2113,11 @@ router.get('/zhanqi/room/:id', lazyloadRouteHandler('./routes/zhanqi/room'));
// 酒云网
router.get('/wineyun/:category', lazyloadRouteHandler('./routes/wineyun'));
// 小红书
router.get('/xiaohongshu/user/:user_id/:category', lazyloadRouteHandler('./routes/xiaohongshu/user'));
router.get('/xiaohongshu/board/:board_id', lazyloadRouteHandler('./routes/xiaohongshu/board'));
// 小红书 migrated to v2
// router.get('/xiaohongshu/user/:user_id/:category', lazyloadRouteHandler('./routes/xiaohongshu/user'));
// router.get('/xiaohongshu/board/:board_id', lazyloadRouteHandler('./routes/xiaohongshu/board'));
// 每经网 migrated to v2
// 每经网
// router.get('/nbd/daily', lazyloadRouteHandler('./routes/nbd/article'));
// router.get('/nbd/:id?', lazyloadRouteHandler('./routes/nbd/index'));

View File

@ -1,18 +0,0 @@
const delay = (timeout = 1000) => new Promise((resolve) => setTimeout(resolve, timeout));
async function getContent(url) {
const browser = await require('@/utils/puppeteer')();
try {
const page = await browser.newPage();
await page.goto(url);
await delay(1000);
const content = await page.content();
return content.replace('"RedAppLayout":undefined,', ''); // fix json parse
} finally {
browser.close();
}
}
module.exports = {
getContent,
};

View File

@ -1,11 +1,10 @@
const { getContent } = require('@/routes/xiaohongshu/util');
const { parseDate } = require('@/utils/parse-date');
const timezone = require('@/utils/timezone');
const { getContent } = require('./util');
module.exports = async (ctx) => {
const url = `https://www.xiaohongshu.com/board/${ctx.params.board_id}`;
const content = await getContent(url);
const regex = /_SSR_STATE__\S*=([\s\S]+)<\/script>/gm;
const match = regex.exec(content);
const main = JSON.parse(match[1]).Main;
const main = await getContent(url, ctx.cache);
const albumInfo = main.albumInfo;
const title = albumInfo.name;
@ -15,8 +14,11 @@ module.exports = async (ctx) => {
const resultItem = list.map((item) => ({
title: item.title,
link: `https://www.xiaohongshu.com/discovery/item/${item.id}`,
description: `<img src ="${item.cover.url}"><br>${item.title}`,
description: `<img src ="${item.cover.url.split('?imageView2')[0]}"><br>${item.title}`,
author: item.user.nickname,
pubDate: timezone(parseDate(item.time), 8),
}));
ctx.state.data = {
title,
link: url,

View File

@ -0,0 +1,4 @@
module.exports = {
'/board/:board_id': ['lotosbin'],
'/user/:user_id/:category': ['lotosbin'],
};

View File

@ -0,0 +1,25 @@
module.exports = {
'xiaohongshu.com': {
_name: '小红书',
'.': [
{
title: '用户笔记',
docs: 'https://docs.rsshub.app/social-media.html#xiao-hong-shu',
source: '/user/profile/:user_id',
target: '/xiaohongshu/user/:user_id/notes',
},
{
title: '用户专辑',
docs: 'https://docs.rsshub.app/social-media.html#xiao-hong-shu',
source: '/user/profile/:user_id',
target: '/xiaohongshu/user/:user_id/album',
},
{
title: '专辑',
docs: 'https://docs.rsshub.app/social-media.html#xiao-hong-shu',
source: '/board/:board_id',
target: '/xiaohongshu/board/:board_id',
},
],
},
};

View File

@ -0,0 +1,4 @@
module.exports = (router) => {
router.get('/board/:board_id', require('./board'));
router.get('/user/:user_id/:category', require('./user'));
};

View File

@ -1,25 +1,23 @@
const { getContent } = require('@/routes/xiaohongshu/util');
const cheerio = require('cheerio');
const { parseDate } = require('@/utils/parse-date');
const timezone = require('@/utils/timezone');
const { getContent } = require('./util');
module.exports = async (ctx) => {
const userId = ctx.params.user_id;
const category = ctx.params.category;
const url = `https://www.xiaohongshu.com/user/profile/${userId}`;
const content = await getContent(url);
const $ = cheerio.load(content);
const description = $('head title').html();
const regex = /_SSR_STATE__\S*=([\s\S]+)<\/script>/gm;
const match = regex.exec(content);
const main = JSON.parse(match[1]).Main;
const main = await getContent(url, ctx.cache);
const userDetail = main.userDetail;
const description = `${userDetail.nickname} • 小红书 / RED`;
if (category === 'notes') {
const list = main.notesDetail;
const resultItem = list.map((item) => ({
title: item.title,
link: `https://www.xiaohongshu.com/discovery/item/${item.id}`,
description: `<img src ="${item.cover.url}"><br>${item.title}`,
description: `<img src ="${item.cover.url.split('?imageView2')[0]}"><br>${item.title}`,
author: item.user.nickname,
pubDate: timezone(parseDate(item.time), 8),
}));
const title = `小红书-${userDetail.nickname}-笔记`;
@ -34,7 +32,7 @@ module.exports = async (ctx) => {
const resultItem = list.map((item) => ({
title: item.title,
link: `https://www.xiaohongshu.com/board/${item.id}`,
description: item.images.map((it) => `<img src ="${it}">`).join(`<br />`),
description: item.images.map((it) => `<img src ="${it.split('?imageView2')[0]}">`).join(`<br>`),
}));
const title = `小红书-${userDetail.nickname}-专辑`;

View File

@ -0,0 +1,28 @@
const config = require('@/config').value;
const getContent = (url, cache) =>
cache.tryGet(
url,
async () => {
const browser = await require('@/utils/puppeteer')();
try {
const page = await browser.newPage();
await page.goto(url);
await page.waitForSelector('.pc-container');
let content = await page.content();
content = content.replace('"RedAppLayout":undefined,', ''); // fix json parse
const regex = /_SSR_STATE__\S*=([\s\S]+)<\/script>/gm;
const match = regex.exec(content);
return JSON.parse(match[1]).Main;
} finally {
browser.close();
}
},
config.cache.routeExpire,
false
);
module.exports = {
getContent,
};