增加更多评论详情内容
This commit is contained in:
@@ -43,6 +43,8 @@ func (f *FeedDetailAction) GetFeedDetail(ctx context.Context, feedID, xsecToken
|
|||||||
const DELTA_MIN = 480;
|
const DELTA_MIN = 480;
|
||||||
const SCROLL_TIMEOUT = 900;
|
const SCROLL_TIMEOUT = 900;
|
||||||
const MAX_ATTEMPTS = 200;
|
const MAX_ATTEMPTS = 200;
|
||||||
|
const CLICK_MORE_INTERVAL = 2; // 每滚动2次检查一次"更多"按钮
|
||||||
|
const CLICK_WAIT_TIME = 300; // 点击后等待时间
|
||||||
|
|
||||||
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
||||||
const scrollRoot = () => document.scrollingElement || document.documentElement || document.body;
|
const scrollRoot = () => document.scrollingElement || document.documentElement || document.body;
|
||||||
@@ -97,6 +99,77 @@ func (f *FeedDetailAction) GetFeedDetail(ctx context.Context, feedID, xsecToken
|
|||||||
console.debug('dispatchWheel error', err);
|
console.debug('dispatchWheel error', err);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 点击所有"更多"按钮 - 使用多种策略确保不遗漏
|
||||||
|
const clickShowMoreButtons = () => {
|
||||||
|
// 尝试多个可能的选择器
|
||||||
|
const selectors = [
|
||||||
|
'.show-more',
|
||||||
|
'.show-more-btn',
|
||||||
|
'[class*="show-more"]',
|
||||||
|
'[class*="showMore"]',
|
||||||
|
'button:has-text("更多")',
|
||||||
|
'span:has-text("更多")',
|
||||||
|
'div:has-text("更多")'
|
||||||
|
];
|
||||||
|
|
||||||
|
const clickedElements = new Set();
|
||||||
|
let clickedCount = 0;
|
||||||
|
|
||||||
|
selectors.forEach((selector) => {
|
||||||
|
try {
|
||||||
|
const elements = document.querySelectorAll(selector);
|
||||||
|
elements.forEach((el) => {
|
||||||
|
// 避免重复点击同一个元素
|
||||||
|
if (clickedElements.has(el)) return;
|
||||||
|
|
||||||
|
// 检查元素文本是否包含"更多"或者是否有相关class
|
||||||
|
const text = el.textContent || '';
|
||||||
|
const className = el.className || '';
|
||||||
|
const shouldClick = text.includes('更多') ||
|
||||||
|
className.includes('show-more') ||
|
||||||
|
className.includes('showMore');
|
||||||
|
|
||||||
|
if (!shouldClick) return;
|
||||||
|
|
||||||
|
// 检查元素是否可见(放宽条件,不要求完全在视口内)
|
||||||
|
const rect = el.getBoundingClientRect();
|
||||||
|
const style = window.getComputedStyle(el);
|
||||||
|
const isVisible = (
|
||||||
|
rect.height > 0 &&
|
||||||
|
rect.width > 0 &&
|
||||||
|
style.display !== 'none' &&
|
||||||
|
style.visibility !== 'hidden' &&
|
||||||
|
style.opacity !== '0' &&
|
||||||
|
rect.top < window.innerHeight + 500 && // 允许元素在视口下方500px内
|
||||||
|
rect.bottom > -500 // 允许元素在视口上方500px内
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isVisible) {
|
||||||
|
try {
|
||||||
|
// 尝试多种点击方式
|
||||||
|
el.click();
|
||||||
|
|
||||||
|
// 如果是嵌套元素,也尝试点击父元素
|
||||||
|
if (el.parentElement && el.parentElement.classList.contains('show-more')) {
|
||||||
|
el.parentElement.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
clickedElements.add(el);
|
||||||
|
clickedCount++;
|
||||||
|
} catch (err) {
|
||||||
|
console.debug('点击失败', err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
console.debug('选择器错误: ' + selector, err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return clickedCount;
|
||||||
|
};
|
||||||
|
|
||||||
let cachedTarget = null;
|
let cachedTarget = null;
|
||||||
const collectCandidates = () => {
|
const collectCandidates = () => {
|
||||||
const container = getContainer();
|
const container = getContainer();
|
||||||
@@ -175,16 +248,45 @@ func (f *FeedDetailAction) GetFeedDetail(ctx context.Context, feedID, xsecToken
|
|||||||
let lastCount = 0;
|
let lastCount = 0;
|
||||||
let stagnantChecks = 0;
|
let stagnantChecks = 0;
|
||||||
let noScrollChangeCount = 0;
|
let noScrollChangeCount = 0;
|
||||||
|
let totalClickedButtons = 0;
|
||||||
|
|
||||||
for (let attempt = 0; attempt < MAX_ATTEMPTS; attempt++) {
|
for (let attempt = 0; attempt < MAX_ATTEMPTS; attempt++) {
|
||||||
const container = getContainer();
|
const container = getContainer();
|
||||||
if (!container) {
|
if (!container) {
|
||||||
await sleep(300);
|
await sleep(300);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 每隔一定次数检查并点击"更多"按钮
|
||||||
|
if (attempt % CLICK_MORE_INTERVAL === 0) {
|
||||||
|
const clicked = clickShowMoreButtons();
|
||||||
|
if (clicked > 0) {
|
||||||
|
totalClickedButtons += clicked;
|
||||||
|
console.log('点击了 ' + clicked + ' 个"更多"按钮,累计: ' + totalClickedButtons);
|
||||||
|
await sleep(CLICK_WAIT_TIME); // 等待内容展开
|
||||||
|
|
||||||
|
// 点击后再次检查是否有新的"更多"按钮出现
|
||||||
|
await sleep(200);
|
||||||
|
const clicked2 = clickShowMoreButtons();
|
||||||
|
if (clicked2 > 0) {
|
||||||
|
totalClickedButtons += clicked2;
|
||||||
|
console.log('二次检查点击了 ' + clicked2 + ' 个"更多"按钮');
|
||||||
|
await sleep(CLICK_WAIT_TIME);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const total = getTotalCount(container);
|
const total = getTotalCount(container);
|
||||||
const count = getCommentCount(container);
|
const count = getCommentCount(container);
|
||||||
if (total && count >= total) {
|
if (total && count >= total) {
|
||||||
return { status: 'complete', reason: 'total', attempts: attempt + 1, count, total };
|
return {
|
||||||
|
status: 'complete',
|
||||||
|
reason: 'total',
|
||||||
|
attempts: attempt + 1,
|
||||||
|
count,
|
||||||
|
total,
|
||||||
|
clickedButtons: totalClickedButtons
|
||||||
|
};
|
||||||
}
|
}
|
||||||
if (count === lastCount) {
|
if (count === lastCount) {
|
||||||
stagnantChecks += 1;
|
stagnantChecks += 1;
|
||||||
@@ -193,7 +295,14 @@ func (f *FeedDetailAction) GetFeedDetail(ctx context.Context, feedID, xsecToken
|
|||||||
stagnantChecks = 0;
|
stagnantChecks = 0;
|
||||||
}
|
}
|
||||||
if (stagnantChecks >= STAGNANT_LIMIT) {
|
if (stagnantChecks >= STAGNANT_LIMIT) {
|
||||||
return { status: 'complete', reason: 'stagnant', attempts: attempt + 1, count, total };
|
return {
|
||||||
|
status: 'complete',
|
||||||
|
reason: 'stagnant',
|
||||||
|
attempts: attempt + 1,
|
||||||
|
count,
|
||||||
|
total,
|
||||||
|
clickedButtons: totalClickedButtons
|
||||||
|
};
|
||||||
}
|
}
|
||||||
const target = findScrollTarget();
|
const target = findScrollTarget();
|
||||||
const beforeTop = getScrollMetrics(target).top;
|
const beforeTop = getScrollMetrics(target).top;
|
||||||
@@ -206,13 +315,23 @@ func (f *FeedDetailAction) GetFeedDetail(ctx context.Context, feedID, xsecToken
|
|||||||
noScrollChangeCount = 0;
|
noScrollChangeCount = 0;
|
||||||
}
|
}
|
||||||
if (noScrollChangeCount >= NO_CHANGE_SCROLL_LIMIT) {
|
if (noScrollChangeCount >= NO_CHANGE_SCROLL_LIMIT) {
|
||||||
return { status: 'complete', reason: 'no-scroll-change', attempts: attempt + 1, count, total };
|
return {
|
||||||
|
status: 'complete',
|
||||||
|
reason: 'no-scroll-change',
|
||||||
|
attempts: attempt + 1,
|
||||||
|
count,
|
||||||
|
total,
|
||||||
|
clickedButtons: totalClickedButtons
|
||||||
|
};
|
||||||
}
|
}
|
||||||
if (INTERVAL_MS > SCROLL_TIMEOUT) {
|
if (INTERVAL_MS > SCROLL_TIMEOUT) {
|
||||||
await sleep(INTERVAL_MS - SCROLL_TIMEOUT);
|
await sleep(INTERVAL_MS - SCROLL_TIMEOUT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return { status: 'timeout' };
|
return {
|
||||||
|
status: 'timeout',
|
||||||
|
clickedButtons: totalClickedButtons
|
||||||
|
};
|
||||||
})()
|
})()
|
||||||
.then((res) => JSON.stringify(res))
|
.then((res) => JSON.stringify(res))
|
||||||
.catch((err) => JSON.stringify({ status: 'error', message: err && err.message ? err.message : String(err) }));
|
.catch((err) => JSON.stringify({ status: 'error', message: err && err.message ? err.message : String(err) }));
|
||||||
|
|||||||
Reference in New Issue
Block a user