feat: Modify determineHasNextPage

This commit is contained in:
PetrichorFun 2026-01-21 21:48:28 +08:00
parent 3a8110171f
commit 6f15a8bcb5
4 changed files with 143 additions and 28 deletions

View File

@ -1,6 +1,6 @@
{
"name": "azon-seeker",
"displayName": "Azon Seeker v0.7.1.1-beta",
"displayName": "Azon Seeker v0.7.1.2-beta",
"version": "0.7.2",
"private": true,
"description": "Starter modify by honestfox101 and PetrichorFun",

View File

@ -14,15 +14,17 @@ defineProps<{
<template>
<n-card class="progress-report" title="数据获取情况">
<n-timeline v-if="timelines.length > 0">
<n-timeline-item
v-for="(item, index) in timelines.toReversed()"
:key="index"
:type="item.type"
:title="item.title"
:time="item.time"
>
<div v-for="line in item.content.split('\n')">{{ line }}</div>
</n-timeline-item>
<n-infinite-scroll style="max-height: 40vh; padding-right: 16px" :distance="10">
<n-timeline-item
v-for="(item, index) in timelines.toReversed()"
:key="index"
:type="item.type"
:title="item.title"
:time="item.time"
>
<div v-for="line in item.content.split('\n')">{{ line }}</div>
</n-timeline-item>
</n-infinite-scroll>
</n-timeline>
<n-empty v-else size="large">
<template #icon>

View File

@ -118,20 +118,109 @@ export class AmazonSearchPageInjector extends BaseInjector {
});
}
public async determineHasNextPage() {
// /**
// * 检测当前亚马逊搜索页面是否有下一页,并自动点击翻页按钮。
// *
// * 该方法在页面上下文中执行,查找亚马逊标准分页按钮('.s-pagination-next'
// * 检查按钮是否未被禁用('s-pagination-disabled' 类),然后模拟用户点击。
// * 点击前会随机等待 500-1000 毫秒以避免被识别为机器人。
// *
// * @returns `true` 表示有下一页且已点击翻页按钮,页面正在加载下一页内容;
// * `false` 表示没有下一页(按钮不存在或被禁用)。
// */
// public async determineHasNextPage() {
// return this.run(async () => {
// const nextButton = document.querySelector<HTMLLinkElement>('.s-pagination-next');
// if (nextButton) {
// if (!nextButton.classList.contains('s-pagination-disabled')) {
// await new Promise((resolve) => setTimeout(resolve, 500 + ~~(500 * Math.random())));
// nextButton.click();
// return true;
// } else {
// return false;
// }
// } else {
// return false;
// }
// });
// }
// /**
// * 检测并执行亚马逊搜索页面翻页,等待页面刷新完成。
// * @returns 能否翻页true=翻页成功false=没有下一页或翻页失败)
// */
// public async determineHasNextPage(): Promise<boolean> {
// return this.run(async () => {
// const nextButton = document.querySelector<HTMLLinkElement>('.s-pagination-next');
// if (nextButton && !nextButton.classList.contains('s-pagination-disabled')) {
// // 记录当前页码
// const initialPage = await this.getCurrentPage();
// // 随机等待后点击
// await new Promise((resolve) => setTimeout(resolve, 500 + ~~(500 * Math.random())));
// nextButton.click();
// // 等待页面刷新完成
// await this.waitForPageLoaded();
// // 验证翻页是否成功
// const newPage = await this.getCurrentPage();
// // 只有页码真正变化才算翻页成功
// return newPage !== null && newPage !== initialPage;
// }
// return false;
// });
// }
/**
* URL
* @returns true=false=
*/
public async determineHasNextPage(): Promise<boolean> {
return this.run(async () => {
const nextButton = document.querySelector<HTMLLinkElement>('.s-pagination-next');
if (nextButton) {
if (!nextButton.classList.contains('s-pagination-disabled')) {
await new Promise((resolve) => setTimeout(resolve, 500 + ~~(500 * Math.random())));
nextButton.click();
return true;
} else {
return false;
}
} else {
return false;
if (nextButton && !nextButton.classList.contains('s-pagination-disabled')) {
// 1. 记录当前 URL
const initialUrl = window.location.href;
// 2. 随机等待后点击
await new Promise((resolve) => setTimeout(resolve, 500 + ~~(500 * Math.random())));
nextButton.click();
// 3. 等待 URL 变化(表示页面已开始导航)
await new Promise<void>((resolve) => {
const checkUrl = () => {
if (window.location.href !== initialUrl) {
resolve();
} else {
setTimeout(checkUrl, 100);
}
};
checkUrl();
});
// 4. 等待页面稳定document.readyState === 'complete'
await new Promise<void>((resolve) => {
const checkReadyState = () => {
if (document.readyState === 'complete') {
resolve();
} else {
setTimeout(checkReadyState, 100);
}
};
checkReadyState();
});
// 5. 额外等待确保内容加载
await new Promise((resolve) => setTimeout(resolve, 500));
return true;
}
return false;
});
}
}

View File

@ -5,7 +5,7 @@ import { usePageWorker } from '~/page-worker';
import MulInputModal from '~/sidepanel/views/components/MulInputModal.vue';
const message = useMessage();
const showModal = ref(false);
const initKeysCount = ref(0);
//#region Initial Page Worker
const worker = usePageWorker('amazon', { objects: ['search'] });
worker.on('error', ({ message: msg }) => {
@ -39,7 +39,8 @@ const launch = async () => {
content: `关键词: ${kws[0]} 数据采集开始`,
},
];
timelines.value.push();
// timelines.value.push();
initKeysCount.value = kws.length;
await worker.runSearchPageTask(kws, {
progress: (remains) => {
if (remains.length > 0) {
@ -79,15 +80,26 @@ const clickInputButton = (e: MouseEvent) => {
const handleModalConfirm = (keys: string[]) => {
keywordsList.value = keys;
// console.log(keys);
};
</script>
<template>
<div class="search-page-entry">
<header-title @click-mul-input="clickInputButton">Amazon Search</header-title>
<div class="overview-card">
<span style="display: inline-block">总览</span>
<span style="display: inline-block"> 总关键词数量 {{ initKeysCount }} </span>
<span style="display: inline-block"> 当前剩余关键词数量 {{ keywordsList.length }} </span>
<span style="display: inline-block">
现在爬到第
{{
initKeysCount - keywordsList.length + 1 ? '---' : initKeysCount - keywordsList.length + 1
}}
</span
>
</div>
<div class="interactive-section">
<n-infinite-scroll style="max-height: 60vh; padding-right: 16px" :distance="10">
<n-infinite-scroll style="max-height: 40vh; padding-right: 16px" :distance="10">
<n-dynamic-input
:disabled="worker.isRunning.value"
v-model:value="keywordsList"
@ -100,8 +112,7 @@ const handleModalConfirm = (keys: string[]) => {
placeholder="请输入关键词采集信息"
/>
</n-infinite-scroll>
<!-- <n-dynamic-input :disabled="worker.isRunning.value" v-model:value="keywordsList" :min="1" :max="999"
class="search-input-box" autosize size="large" round placeholder="请输入关键词采集信息" /> -->
<n-button
v-if="!worker.isRunning.value"
type="primary"
@ -129,8 +140,9 @@ const handleModalConfirm = (keys: string[]) => {
<n-alert title="Warning" type="warning"> 警告在插件运行期间请勿与浏览器交互 </n-alert>
</div>
<progress-report class="progress-report" :timelines="timelines" />
<MulInputModal v-model:show-modal="showModal" @confirm="handleModalConfirm"> </MulInputModal>
</div>
<MulInputModal v-model:show-modal="showModal" @confirm="handleModalConfirm"> </MulInputModal>
</template>
<style scoped lang="scss">
@ -158,6 +170,18 @@ const handleModalConfirm = (keys: string[]) => {
}
}
.overview-card {
border-radius: 10px;
width: 80%;
outline: 1px #00000020 dashed;
display: flex;
flex-direction: column;
justify-content: center;
align-items: stretch;
gap: 15px;
padding: 15px 25px;
}
.running-tip-section {
border-radius: 10px;
cursor: wait;