diff --git a/lib/routes/xiaohongshu/user.ts b/lib/routes/xiaohongshu/user.ts
index 4550898e4..031d54f84 100644
--- a/lib/routes/xiaohongshu/user.ts
+++ b/lib/routes/xiaohongshu/user.ts
@@ -98,14 +98,17 @@ async function getUserFeeds(url: string, category: string) {
const renderNote = (notes) =>
notes.flatMap((n) =>
- n.map(({ id, noteCard }) => ({
- title: noteCard.displayTitle,
- link: new URL(noteCard.noteId || id, url).href,
- guid: noteCard.displayTitle,
- description: `.url})
${noteCard.displayTitle}`,
- author: noteCard.user.nickname,
- upvotes: noteCard.interactInfo.likedCount,
- }))
+ n.map(({ noteCard }) => {
+ const coverUrl = noteCard.cover.infoList.pop().url;
+ return {
+ title: noteCard.displayTitle,
+ link: coverUrl,
+ guid: noteCard.displayTitle,
+ description: `
${noteCard.displayTitle}`,
+ author: noteCard.user.nickname,
+ upvotes: noteCard.interactInfo.likedCount,
+ };
+ })
);
const renderCollect = (collect) => {
if (!collect) {
diff --git a/lib/routes/xiaohongshu/util.ts b/lib/routes/xiaohongshu/util.ts
index a3084ff28..cf1b40e2e 100644
--- a/lib/routes/xiaohongshu/util.ts
+++ b/lib/routes/xiaohongshu/util.ts
@@ -1,3 +1,4 @@
+import type { CheerioAPI } from 'cheerio';
import { load } from 'cheerio';
import { config } from '@/config';
@@ -77,17 +78,22 @@ const getUser = (url, cache) =>
await page.goto(url, {
waitUntil: 'domcontentloaded',
});
- await page.waitForSelector('div.reds-tab-item:nth-child(2), #red-captcha');
+ try {
+ await page.waitForSelector('div.reds-tab-item:nth-child(2), .fe-verify-box', { timeout: 3000 });
+ } catch {
+ //
+ }
- if (await page.$('#red-captcha')) {
+ if (await page.$('.fe-verify-box')) {
throw new CaptchaError('小红书风控校验,请稍后再试');
}
- const initialState = await page.evaluate(() => (window as any).__INITIAL_STATE__);
+ const content = await page.content();
+ const initialState = JSON.parse(extractInitialState(load(content)));
if (!(await page.$('.lock-icon'))) {
- await page.click('div.reds-tab-item:nth-child(2)');
try {
+ await page.click('div.reds-tab-item:nth-child(2)', { timeout: 3000 });
const response = await page.waitForResponse(
(res) => {
const req = res.request();
@@ -105,6 +111,10 @@ const getUser = (url, cache) =>
userPageData = userPageData._rawValue || userPageData;
notes = notes._rawValue || notes;
+ if (!userPageData.basicInfo) {
+ throw new Error(`小红书未返回用户数据,请稍后再试: ${JSON.stringify(userPageData.result)}`);
+ }
+
return { userPageData, notes, collect };
} finally {
await destroy();
@@ -299,38 +309,20 @@ async function getUserWithCookie(url: string) {
}
// Add helper function to extract initial state
-function extractInitialState($) {
- let script = $('script')
- .filter((i, script) => {
- const text = script.children[0]?.data;
- return text?.startsWith('window.__INITIAL_STATE__=');
- })
- .text();
- script = script.slice('window.__INITIAL_STATE__='.length);
+function extractInitialState($: CheerioAPI) {
+ let script = $('script:contains("window.__INITIAL_STATE__=")').text();
+ script = script.slice(script.indexOf('window.__INITIAL_STATE__=') + 'window.__INITIAL_STATE__='.length);
script = script.replaceAll('undefined', 'null');
return script;
}
// Add helper function to extract initial SSR state
-function extractInitialSsrState($) {
- let script = $('script')
- .filter((i, script) => {
- const text = script.children[0]?.data;
- return text?.includes('window.__INITIAL_SSR_STATE__=');
- })
- .text();
+function extractInitialSsrState($: CheerioAPI) {
+ const script = $('script:contains("window.__INITIAL_SSR_STATE__=")').text();
const match = script.match(/window\.__INITIAL_SSR_STATE__\s*=\s*(\{[\s\S]*?\})\s*(?:;|$)/);
if (match) {
return match[1].replaceAll('undefined', 'null');
}
- // Fallback: try simple extraction
- const startMarker = 'window.__INITIAL_SSR_STATE__=';
- const startIndex = script.indexOf(startMarker);
- if (startIndex !== -1) {
- script = script.slice(startIndex + startMarker.length);
- script = script.replaceAll('undefined', 'null');
- return script;
- }
throw new Error('Cannot extract __INITIAL_SSR_STATE__');
}