mirror of
https://github.com/primedigitaltech/azon_seeker.git
synced 2026-02-07 15:53:18 +08:00
feat: Modify determineHasNextPage
This commit is contained in:
parent
3a8110171f
commit
6f15a8bcb5
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "azon-seeker",
|
"name": "azon-seeker",
|
||||||
"displayName": "Azon Seeker v0.7.1.1-beta",
|
"displayName": "Azon Seeker v0.7.1.2-beta",
|
||||||
"version": "0.7.2",
|
"version": "0.7.2",
|
||||||
"private": true,
|
"private": true,
|
||||||
"description": "Starter modify by honestfox101 and PetrichorFun",
|
"description": "Starter modify by honestfox101 and PetrichorFun",
|
||||||
|
|||||||
@ -14,15 +14,17 @@ defineProps<{
|
|||||||
<template>
|
<template>
|
||||||
<n-card class="progress-report" title="数据获取情况">
|
<n-card class="progress-report" title="数据获取情况">
|
||||||
<n-timeline v-if="timelines.length > 0">
|
<n-timeline v-if="timelines.length > 0">
|
||||||
<n-timeline-item
|
<n-infinite-scroll style="max-height: 40vh; padding-right: 16px" :distance="10">
|
||||||
v-for="(item, index) in timelines.toReversed()"
|
<n-timeline-item
|
||||||
:key="index"
|
v-for="(item, index) in timelines.toReversed()"
|
||||||
:type="item.type"
|
:key="index"
|
||||||
:title="item.title"
|
:type="item.type"
|
||||||
:time="item.time"
|
:title="item.title"
|
||||||
>
|
:time="item.time"
|
||||||
<div v-for="line in item.content.split('\n')">{{ line }}</div>
|
>
|
||||||
</n-timeline-item>
|
<div v-for="line in item.content.split('\n')">{{ line }}</div>
|
||||||
|
</n-timeline-item>
|
||||||
|
</n-infinite-scroll>
|
||||||
</n-timeline>
|
</n-timeline>
|
||||||
<n-empty v-else size="large">
|
<n-empty v-else size="large">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
|
|||||||
@ -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 () => {
|
return this.run(async () => {
|
||||||
const nextButton = document.querySelector<HTMLLinkElement>('.s-pagination-next');
|
const nextButton = document.querySelector<HTMLLinkElement>('.s-pagination-next');
|
||||||
if (nextButton) {
|
|
||||||
if (!nextButton.classList.contains('s-pagination-disabled')) {
|
if (nextButton && !nextButton.classList.contains('s-pagination-disabled')) {
|
||||||
await new Promise((resolve) => setTimeout(resolve, 500 + ~~(500 * Math.random())));
|
// 1. 记录当前 URL
|
||||||
nextButton.click();
|
const initialUrl = window.location.href;
|
||||||
return true;
|
|
||||||
} else {
|
// 2. 随机等待后点击
|
||||||
return false;
|
await new Promise((resolve) => setTimeout(resolve, 500 + ~~(500 * Math.random())));
|
||||||
}
|
nextButton.click();
|
||||||
} else {
|
|
||||||
return false;
|
// 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;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import { usePageWorker } from '~/page-worker';
|
|||||||
import MulInputModal from '~/sidepanel/views/components/MulInputModal.vue';
|
import MulInputModal from '~/sidepanel/views/components/MulInputModal.vue';
|
||||||
const message = useMessage();
|
const message = useMessage();
|
||||||
const showModal = ref(false);
|
const showModal = ref(false);
|
||||||
|
const initKeysCount = ref(0);
|
||||||
//#region Initial Page Worker
|
//#region Initial Page Worker
|
||||||
const worker = usePageWorker('amazon', { objects: ['search'] });
|
const worker = usePageWorker('amazon', { objects: ['search'] });
|
||||||
worker.on('error', ({ message: msg }) => {
|
worker.on('error', ({ message: msg }) => {
|
||||||
@ -39,7 +39,8 @@ const launch = async () => {
|
|||||||
content: `关键词: ${kws[0]} 数据采集开始`,
|
content: `关键词: ${kws[0]} 数据采集开始`,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
timelines.value.push();
|
// timelines.value.push();
|
||||||
|
initKeysCount.value = kws.length;
|
||||||
await worker.runSearchPageTask(kws, {
|
await worker.runSearchPageTask(kws, {
|
||||||
progress: (remains) => {
|
progress: (remains) => {
|
||||||
if (remains.length > 0) {
|
if (remains.length > 0) {
|
||||||
@ -79,15 +80,26 @@ const clickInputButton = (e: MouseEvent) => {
|
|||||||
|
|
||||||
const handleModalConfirm = (keys: string[]) => {
|
const handleModalConfirm = (keys: string[]) => {
|
||||||
keywordsList.value = keys;
|
keywordsList.value = keys;
|
||||||
// console.log(keys);
|
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="search-page-entry">
|
<div class="search-page-entry">
|
||||||
<header-title @click-mul-input="clickInputButton">Amazon Search</header-title>
|
<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">
|
<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
|
<n-dynamic-input
|
||||||
:disabled="worker.isRunning.value"
|
:disabled="worker.isRunning.value"
|
||||||
v-model:value="keywordsList"
|
v-model:value="keywordsList"
|
||||||
@ -100,8 +112,7 @@ const handleModalConfirm = (keys: string[]) => {
|
|||||||
placeholder="请输入关键词采集信息"
|
placeholder="请输入关键词采集信息"
|
||||||
/>
|
/>
|
||||||
</n-infinite-scroll>
|
</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
|
<n-button
|
||||||
v-if="!worker.isRunning.value"
|
v-if="!worker.isRunning.value"
|
||||||
type="primary"
|
type="primary"
|
||||||
@ -129,8 +140,9 @@ const handleModalConfirm = (keys: string[]) => {
|
|||||||
<n-alert title="Warning" type="warning"> 警告,在插件运行期间请勿与浏览器交互。 </n-alert>
|
<n-alert title="Warning" type="warning"> 警告,在插件运行期间请勿与浏览器交互。 </n-alert>
|
||||||
</div>
|
</div>
|
||||||
<progress-report class="progress-report" :timelines="timelines" />
|
<progress-report class="progress-report" :timelines="timelines" />
|
||||||
|
|
||||||
|
<MulInputModal v-model:show-modal="showModal" @confirm="handleModalConfirm"> </MulInputModal>
|
||||||
</div>
|
</div>
|
||||||
<MulInputModal v-model:show-modal="showModal" @confirm="handleModalConfirm"> </MulInputModal>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<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 {
|
.running-tip-section {
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
cursor: wait;
|
cursor: wait;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user