DIYgod/RSSHub · error · Error
无法从页面中获取到帖子ID,可能网站结构已变更
Error message
无法从页面中获取到帖子ID,可能网站结构已变更
What it means
Thrown by handleCommentSection in the jandan route when extractPageMeta cannot find a page id. extractPageMeta scrapes the category page's inline scripts and matches `/PAGE\s*=\s*\{\s*id\s*:\s*(\d+)\s*\}/`; if no script tag containing 'PAGE' yields that pattern, pageId becomes '' and the handler refuses to continue (Chinese: 'could not get post id from page, site structure may have changed'). It is a defensive guard because every subsequent API call depends on that id.
Source
Thrown at lib/routes/jandan/utils.ts:106
link: `${rootUrl}/new/forum/topic/${post.post_id}`,
category: post.reply_count > 0 ? [`${post.reply_count}条回复`] : undefined,
}) as DataItem
);
return { title, items, link: currentUrl };
};
/**
* Handle other sections (问答, 树洞, 随手拍, 女装, 无聊图)
*/
export const handleCommentSection = async (rootUrl: string, category: string): Promise<{ title: string; items: DataItem[] }> => {
const currentUrl = `${rootUrl}/${category}`;
const { pageId, title: pageTitle } = await extractPageMeta(currentUrl);
const title = pageTitle || `煎蛋 - ${category}`;
if (!pageId) {
throw new Error('无法从页面中获取到帖子ID,可能网站结构已变更');
}
const apiUrl = `${rootUrl}/api/comment/post/${pageId}?order=desc&page=0`;
const commentsData = await ofetch(apiUrl);
if (commentsData.code !== 0) {
throw new Error('没有获取到内容,可能需要更新解析规则');
}
const items = commentsData.data.list.map((comment) => {
const content = comment.content.replaceAll(/img src="(.*?)"/g, (match, src) => match.replace(src, () => src.replace(/^https?:\/\/(\w+)\.moyu\.im/, 'https://$1.sinaimg.cn')));
return {
author: comment.author,
title: `${comment.author}: ${sanitizeHtml(content, { allowedTags: [], allowedAttributes: {} })}`,
description: content,
pubDate: parseDate(comment.date_gmt),
link: `${rootUrl}/t/${comment.id}`,View on GitHub (pinned to bed535e087)
Solutions
- Open the category URL in a browser, view-source, and confirm whether `PAGE = { id:` still exists in an inline script
- If the script tag changed, update the regex in extractPageMeta (lib/routes/jandan/utils.ts:20-22) to match the new shape
- If the value now lives in an external JS bundle or a JSON blob, fetch that resource instead and parse it
- Clear the `jandan:pageMeta:${url}` cache key so a stale empty pageId is not reused
Example fix
// before
pageId:
$('script:contains("PAGE")')
.text()
.match(/PAGE\s*=\s*\{\s*id\s*:\s*(\d+)\s*\}/)?.[1] ?? '',
// after
const scripts = $('script').toArray().map((el) => $(el).text()).join('\n');
const pageId = scripts.match(/PAGE\s*=\s*\{\s*id\s*:\s*(\d+)\s*\}/)?.[1]
?? scripts.match(/"pageId"\s*:\s*(\d+)/)?.[1]
?? ''; Defensive patterns
Strategy: validation
Validate before calling
// Validate the page actually exposes the PAGE id before delegating to the handler
async function pageHasPageId(url: string): Promise<boolean> {
const html = await ofetch(url);
const $ = load(html);
const scripts = $('script').toArray().map((el) => $(el).text()).join('\n');
return /PAGE\s*=\s*\{\s*id\s*:\s*\d+\s*\}/.test(scripts);
} Type guard
function hasPageId(meta: { pageId?: string }): meta is { pageId: string } {
return typeof meta.pageId === 'string' && /^\d+$/.test(meta.pageId);
} Try / catch
try {
return await handleCommentSection(rootUrl, category);
} catch (e) {
if (e instanceof Error && e.message.includes('帖子ID')) {
// bust the cached pageMeta then retry once — likely a stale empty extraction
await cache.tryGet.delete?.(`jandan:pageMeta:${rootUrl}/${category}`);
throw new Error('jandan page structure changed; extraction regex needs updating');
}
throw e;
} Prevention
- Cache pageMeta with a short TTL so structural changes self-heal
- Pin extraction to multiple fallback patterns (PAGE global, JSON island, data attribute)
- Add a content-length / content-type sanity check on the fetched page to detect anti-bot interstitials
- Log a snippet of the fetched HTML when pageId extraction fails
When it happens
Trigger: GET `${rootUrl}/${category}` returns HTML, but the inline `PAGE = { id: <number> }` assignment is gone, renamed, minified to a different shape, or moved into an external bundle that cheerio does not execute. Also fires when ofetch receives an error/interstitial page (HTTP 200 with anti-bot body) instead of the real category page.
Common situations: 煎蛋 ships a frontend rebuild that changes the PAGE global name; anti-bot middleware returns a challenge page; the cached pageMeta is stale and points at a now-redirecting URL; category slug passed in does not correspond to a real page so the returned HTML is the homepage.
Related errors
- 请填入合法的用户 id,参见用户排名 https://www.jisilu.cn/users/
- missing next data
- 无法正确获取快递公司列表:请稍后重试
- LSD token not found
- User ID not found
AI-assisted analysis of DIYgod/RSSHub@bed535e087 (2026-08-12).
Data as JSON: /api/errors/c24a863852d142df.
Report an issue: GitHub.