@tocha688/browser 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,386 @@
1
+ import * as patchright_core from 'patchright-core';
2
+ import { Page, Locator, Request, Browser, Route } from 'patchright-core';
3
+ import * as cl from 'chrome-launcher';
4
+ import * as ProxyChain from 'proxy-chain';
5
+
6
+ /** 坐标点定义 */
7
+ type Point = {
8
+ /** X坐标 */
9
+ x: number;
10
+ /** Y坐标 */
11
+ y: number;
12
+ };
13
+ /** 范围定义,用于指定元素内的随机点范围 */
14
+ type Range = {
15
+ /** 最小边界比例 (0-1) */
16
+ min?: number;
17
+ /** 最大边界比例 (0-1) */
18
+ max?: number;
19
+ };
20
+ /** 鼠标移动配置 */
21
+ type Config = {
22
+ /** 最小移动步数 */
23
+ minSteps: number;
24
+ /** 最大移动步数 */
25
+ maxSteps: number;
26
+ };
27
+ /** 延迟和移动选项 */
28
+ type DelayOptions = {
29
+ /** 移动步数,覆盖默认配置 */
30
+ steps?: number;
31
+ /** 移动速度 (0-1),越大越快 */
32
+ speed?: number;
33
+ /** 随机性 (0-1),越大路径越随机 */
34
+ randomness?: number;
35
+ };
36
+ /** 移动到元素的选项,结合了延迟选项和范围选项 */
37
+ type MoveOptions = DelayOptions & Range;
38
+ /** 鼠标按键类型 */
39
+ type MouseButton = 'left' | 'right' | 'middle';
40
+ /** 点击选项 */
41
+ type ClickOptions = DelayOptions & {
42
+ /** 是否执行双击 */
43
+ doubleClick?: boolean;
44
+ /** 鼠标按键 */
45
+ button?: MouseButton;
46
+ };
47
+ /** 点击元素的选项,结合了点击选项和范围选项 */
48
+ type ClickElementOptions = ClickOptions & Range;
49
+ /**
50
+ * 模拟真人鼠标移动和点击的类
51
+ * 使用贝塞尔曲线生成自然的鼠标轨迹,避免被检测为机器人
52
+ */
53
+ declare class HumanMouse {
54
+ /** Playwright页面实例 */
55
+ page: Page;
56
+ /** 当前鼠标位置 */
57
+ currentPosition: Point;
58
+ /** 移动配置 */
59
+ config: Config;
60
+ /**
61
+ * 构造函数
62
+ * @param page Playwright页面实例
63
+ * @param config 可选的配置参数
64
+ */
65
+ constructor(page: Page, config?: Partial<Config>);
66
+ /**
67
+ * 生成随机步数
68
+ * @returns 在配置范围内的随机步数
69
+ */
70
+ private _randomSteps;
71
+ /**
72
+ * 计算元素内的随机点
73
+ * @param el 目标元素
74
+ * @param options 范围选项
75
+ * @returns 元素内的随机坐标点
76
+ */
77
+ private _toPoint;
78
+ /**
79
+ * 模拟真人鼠标绝对移动
80
+ * @param x 目标X坐标
81
+ * @param y 目标Y坐标
82
+ * @param options 移动选项
83
+ */
84
+ moveTo(x: number, y: number, options?: DelayOptions): Promise<void>;
85
+ /**
86
+ * 模拟真人鼠标移动到指定元素
87
+ * @param el 目标元素
88
+ * @param options 移动和范围选项
89
+ */
90
+ moveToEl(el: Locator, options?: MoveOptions): Promise<void>;
91
+ /**
92
+ * 模拟真人鼠标相对移动
93
+ * @param deltaX X轴偏移量
94
+ * @param deltaY Y轴偏移量
95
+ * @param options 移动和范围选项
96
+ */
97
+ moveBy(deltaX: number, deltaY: number, options?: MoveOptions): Promise<void>;
98
+ scrollBy(deltaY: number, options?: DelayOptions): Promise<void>;
99
+ scrollTo(y: number, options?: DelayOptions): Promise<void>;
100
+ scrollToEl(el: Locator, options?: DelayOptions): Promise<void>;
101
+ /**
102
+ * 模拟真人鼠标单击
103
+ * @param x 目标X坐标
104
+ * @param y 目标Y坐标
105
+ * @param options 点击选项
106
+ */
107
+ click(x: number, y: number, options?: ClickOptions): Promise<void>;
108
+ /**
109
+ * 模拟真人鼠标单击指定元素
110
+ * @param el 目标元素
111
+ * @param options 点击和范围选项
112
+ */
113
+ clickEl(el: Locator, options?: ClickElementOptions): Promise<void>;
114
+ /**
115
+ * 生成贝塞尔曲线控制点
116
+ * @param start 起始点
117
+ * @param end 终点
118
+ * @param randomness 随机性程度
119
+ * @returns 四个控制点组成的数组
120
+ */
121
+ generateControlPoints(start: Point, end: Point, randomness: number): Point[];
122
+ /**
123
+ * 计算动态延迟,模拟加速减速效果
124
+ * @param index 当前步骤索引
125
+ * @param totalPoints 总步数
126
+ * @param speed 速度参数
127
+ * @returns 延迟时间(毫秒)
128
+ */
129
+ getDynamicDelay(index: number, totalPoints: number, speed: number): number;
130
+ /**
131
+ * 生成指定范围内的随机延迟
132
+ * @param min 最小延迟(毫秒)
133
+ * @param max 最大延迟(毫秒)
134
+ * @returns 随机延迟时间(毫秒)
135
+ */
136
+ getRandomDelay(min?: number, max?: number): number;
137
+ /**
138
+ * 在页面上显示鼠标轨迹,用于调试
139
+ * 会在页面上添加一个红色小点跟随鼠标移动
140
+ */
141
+ showCursor(): Promise<void>;
142
+ }
143
+
144
+ type AutoPage = Page & {
145
+ [key: string]: any;
146
+ };
147
+ type AutoLocator = Locator & {
148
+ _loc: Locator;
149
+ input(text: string, options?: Parameters<Locator["waitFor"]>[0] & {
150
+ clear?: boolean;
151
+ delay?: {
152
+ min: number;
153
+ max: number;
154
+ };
155
+ retries?: number;
156
+ }): Promise<void>;
157
+ select(value: Parameters<Locator["selectOption"]>[0], options?: Parameters<Locator["waitFor"]>[0] & Parameters<Locator["selectOption"]>[1] & {
158
+ retries?: number;
159
+ verify?: boolean;
160
+ }): Promise<void>;
161
+ check(options?: Parameters<Locator["waitFor"]>[0] & {
162
+ force?: boolean;
163
+ retries?: number;
164
+ verify?: boolean;
165
+ }): Promise<void>;
166
+ uncheck(options?: Parameters<Locator["waitFor"]>[0] & {
167
+ force?: boolean;
168
+ retries?: number;
169
+ verify?: boolean;
170
+ }): Promise<void>;
171
+ };
172
+ interface FrameInLocatorOptions {
173
+ has?: Locator;
174
+ hasNot?: Locator;
175
+ hasNotText?: string | RegExp;
176
+ hasText?: string | RegExp;
177
+ }
178
+ interface WaitForIframeCompleteOptions {
179
+ frameAttachedTimeout?: number;
180
+ frameVisibleTimeout?: number;
181
+ frameBodyTimeout?: number;
182
+ frameInLocatorOptions?: FrameInLocatorOptions;
183
+ waitForElementTimeout?: number;
184
+ timeout?: number;
185
+ }
186
+ interface MonitorOptions {
187
+ interval?: number;
188
+ debug?: boolean;
189
+ }
190
+
191
+ declare function splitTextIntoChunks(text: string, chunkSize: number): string[];
192
+ declare function isElementFocused(locator: any): Promise<boolean>;
193
+ declare function isLocator(obj: any): boolean;
194
+
195
+ declare class AutoHelper {
196
+ private page;
197
+ mouse: HumanMouse;
198
+ constructor(page: Page);
199
+ static create(page: Page): AutoPage;
200
+ private enhanceLocator;
201
+ /** 点击元素 */
202
+ click(locator: Locator | string, options?: Parameters<Locator["waitFor"]>[0] & Parameters<Locator["click"]>[0] & {
203
+ /** 滚动超时时间 */
204
+ scrollTimeout?: number;
205
+ /** 是否跳过滚动检查 */
206
+ skipScroll?: boolean;
207
+ }): Promise<void>;
208
+ /** 点击指定坐标 */
209
+ clickPoint(x: number, y: number, options?: ClickOptions): Promise<void>;
210
+ isLocator(obj: any): obj is Locator;
211
+ /**
212
+ * 模拟真人输入文本到指定元素
213
+ */
214
+ input(locator: Locator | string, text: string, options?: Parameters<Locator["waitFor"]>[0] & {
215
+ clear?: boolean;
216
+ delay?: {
217
+ min: number;
218
+ max: number;
219
+ };
220
+ retries?: number;
221
+ }): Promise<void>;
222
+ /**
223
+ * 模拟真人输入文本到指定元素 (Force)
224
+ */
225
+ inputFofce(locator: Locator | string, text: string, options?: Parameters<Locator["waitFor"]>[0] & {
226
+ clear?: boolean;
227
+ delay?: {
228
+ min: number;
229
+ max: number;
230
+ };
231
+ retries?: number;
232
+ }): Promise<void>;
233
+ /**
234
+ * 选择下拉框选项
235
+ */
236
+ select(locator: Locator | string, value: Parameters<Locator["selectOption"]>[0], options?: Parameters<Locator["waitFor"]>[0] & Parameters<Locator["selectOption"]>[1] & {
237
+ retries?: number;
238
+ verify?: boolean;
239
+ }): Promise<void>;
240
+ /**
241
+ * 勾选复选框或单选框
242
+ */
243
+ check(locator: Locator | string, options?: Parameters<Locator["waitFor"]>[0] & {
244
+ force?: boolean;
245
+ retries?: number;
246
+ verify?: boolean;
247
+ }): Promise<void>;
248
+ /**
249
+ * 取消勾选复选框或单选框
250
+ */
251
+ uncheck(locator: Locator | string, options?: Parameters<Locator["waitFor"]>[0] & {
252
+ force?: boolean;
253
+ retries?: number;
254
+ verify?: boolean;
255
+ }): Promise<void>;
256
+ /** 随机等待 */
257
+ rWait(minMs?: number, maxMs?: number): Promise<unknown>;
258
+ /**
259
+ * 通用且安全的等待页面加载状态完成
260
+ */
261
+ safeWaitForLoadState(state?: "load" | "domcontentloaded" | "networkidle" | undefined, timeoutMs?: number): Promise<boolean>;
262
+ /**
263
+ * 等待指定 iframe 完全加载并等待指定目标元素可见
264
+ */
265
+ waitForIframeComplete(frameLocator: string | number | symbol, frameInLocator: string | Locator, options?: WaitForIframeCompleteOptions): Promise<patchright_core.FrameLocator>;
266
+ /**
267
+ * 开启后台请求轮询监听
268
+ */
269
+ startRequestPolling(urlRule: string | RegExp, callback?: (request: Request) => void, options?: MonitorOptions): {
270
+ stop: () => void;
271
+ };
272
+ /**
273
+ * 开启后台元素轮询监听
274
+ */
275
+ startElementPolling(page: Page, selector: string, callback?: (locator: Locator) => Promise<void> | void, options?: MonitorOptions): {
276
+ stop: () => void;
277
+ };
278
+ /** 可取消等待出现函数 */
279
+ waitForAbort(el: Locator, options?: Parameters<Locator["waitFor"]>[0]): {
280
+ controller: AbortController;
281
+ main: Promise<Locator>;
282
+ cancel: () => void;
283
+ };
284
+ /**
285
+ * 模拟人类滚动
286
+ */
287
+ humanScroll(distance: number, targetLocator?: Locator): Promise<void>;
288
+ }
289
+
290
+ declare const BrowserCachePath: string;
291
+
292
+ type BrowserStartOptions = {
293
+ proxy?: string;
294
+ headless?: boolean;
295
+ chromePath: string;
296
+ userDataDir?: string;
297
+ };
298
+ type BrowserResult = {
299
+ userDataDir: string;
300
+ port: number;
301
+ browser: cl.LaunchedChrome;
302
+ close: Function;
303
+ };
304
+ type StartBrowserFn = (opts: BrowserStartOptions) => Promise<BrowserResult>;
305
+ type ProxyServerResult = {
306
+ port: number;
307
+ server: ProxyChain.Server;
308
+ ipinfo: any;
309
+ };
310
+
311
+ declare function makeUniqueBrowserConfig(): {
312
+ sessionId: string;
313
+ userDataDir: string;
314
+ };
315
+ declare function getBrowserWebSocketUrl(port: number): Promise<string>;
316
+ declare function createBrowser(startBrowserMain: StartBrowserFn, opts: BrowserStartOptions): Promise<{
317
+ page: patchright_core.Page;
318
+ auto: AutoHelper;
319
+ brw: patchright_core.Browser;
320
+ }>;
321
+
322
+ interface PoolOptions {
323
+ min?: number;
324
+ max?: number;
325
+ testOnBorrow?: boolean;
326
+ idleTimeoutMillis?: number;
327
+ }
328
+ interface PooledBrowser {
329
+ page: Page;
330
+ auto: AutoHelper;
331
+ brw: Browser;
332
+ release: () => Promise<void>;
333
+ }
334
+ declare class BrowserPool {
335
+ private startFn;
336
+ private opts;
337
+ private pool;
338
+ constructor(startFn: StartBrowserFn, opts: BrowserStartOptions, poolOpts?: PoolOptions);
339
+ acquire(): Promise<PooledBrowser>;
340
+ drain(): Promise<void>;
341
+ use<T>(fn: (browser: PooledBrowser) => Promise<T>): Promise<T>;
342
+ }
343
+
344
+ /**
345
+ * 用于浏览器缓存
346
+ */
347
+
348
+ /** 缓存浏览器到目录 ./tmp/browser_cache */
349
+ declare function routeAssetsCache(page: Page, cachePath: string): Promise<void>;
350
+
351
+ declare function fetchResource(route: Route, req: Request, page: Page): Promise<void>;
352
+ declare function routeAssetsLocal(page: Page): Promise<void>;
353
+ declare function routeAssetsAbort(page: Page): Promise<void>;
354
+
355
+ declare function startLocalBrowser(opts: BrowserStartOptions): Promise<BrowserResult>;
356
+
357
+ declare function AdsBrowserStartMain(opts: BrowserStartOptions): Promise<BrowserResult>;
358
+
359
+ declare function OKBrowserStartMain(opts: BrowserStartOptions): Promise<BrowserResult>;
360
+ declare function OKBrowserCreate(opts: BrowserStartOptions): Promise<BrowserResult>;
361
+
362
+ interface BrowserLaunchConfig {
363
+ prepare: (userDataDir: string, devtoolsPort: number) => Promise<{
364
+ args: string[];
365
+ startingUrl?: string;
366
+ cleanup?: () => Promise<void>;
367
+ }>;
368
+ }
369
+ declare function launchBrowserBase(opts: BrowserStartOptions, config: BrowserLaunchConfig): Promise<BrowserResult>;
370
+
371
+ declare const PcScreen: string[];
372
+ declare const Cpus: string[];
373
+ declare const Memorys: string[];
374
+ declare const LinuxWebGL: {
375
+ name: string;
376
+ values: string[];
377
+ }[];
378
+ declare const WindowsWebGL: {
379
+ name: string;
380
+ vendor: string;
381
+ values: string[];
382
+ }[];
383
+ /** 获取系统字体,并且随机返回一些字体(不重复,排除中文字体) */
384
+ declare function rSysFonts(): Promise<string[]>;
385
+
386
+ export { AdsBrowserStartMain, AutoHelper, type AutoLocator, type AutoPage, BrowserCachePath, type BrowserLaunchConfig, BrowserPool, type BrowserResult, type BrowserStartOptions, type ClickOptions, Cpus, type FrameInLocatorOptions, HumanMouse, LinuxWebGL, Memorys, type MonitorOptions, OKBrowserCreate, OKBrowserStartMain, PcScreen, type PoolOptions, type PooledBrowser, type ProxyServerResult, type StartBrowserFn, type WaitForIframeCompleteOptions, WindowsWebGL, createBrowser, fetchResource, getBrowserWebSocketUrl, isElementFocused, isLocator, launchBrowserBase, makeUniqueBrowserConfig, rSysFonts, routeAssetsAbort, routeAssetsCache, routeAssetsLocal, splitTextIntoChunks, startLocalBrowser };
package/dist/index.js ADDED
@@ -0,0 +1,39 @@
1
+ import{sleep as I}from"@tocha688/utils";import{rInt as S}from"@tocha688/utils/random";import{Bezier as fe}from"bezier-js";var F=class{page;currentPosition={x:0,y:0};config={minSteps:15,maxSteps:50};constructor(t,e={}){this.page=t,this.currentPosition={x:0,y:0},this.config={minSteps:15,maxSteps:50,...e}}_randomSteps(){return Math.floor(Math.random()*(this.config.maxSteps-this.config.minSteps))+this.config.minSteps}async _toPoint(t,e){let{min:r=.2,max:o=.8}=e||{},s=await t.boundingBox();if(!s)throw new Error("Element has no bounding box");return{x:s.x+s.width*(r+Math.random()*(o-r)),y:s.y+s.height*(r+Math.random()*(o-r))}}async moveTo(t,e,r={}){let{speed:o=.5,randomness:s=.3}=r,n=this.currentPosition,c={x:t,y:e},a=this.generateControlPoints(n,c,s),p=new fe(...a),l=r.steps||this._randomSteps(),u=p.getLUT(l);for(let m=0;m<u.length;m++){let w=u[m],N=this.getDynamicDelay(m,u.length,o);await this.page.mouse.move(w.x,w.y),await I(N)}this.currentPosition=c}async moveToEl(t,e={}){let r=await this._toPoint(t,e);await this.moveTo(r.x,r.y,e)}async moveBy(t,e,r={}){let o=this.currentPosition.x+t,s=this.currentPosition.y+e;return this.moveTo(o,s,r)}async scrollBy(t,e={}){let{speed:r=.5,randomness:o=.3}=e,s=e.steps||this._randomSteps(),n=t/s;for(let c=0;c<s;c++){let a=n*(Math.random()-.5)*o,p=n+a;await this.page.evaluate("(y) => { window.scrollBy(0, y); }",p);let l=this.getDynamicDelay(c,s,r);await I(l)}}async scrollTo(t,e={}){let r=await this.page.evaluate("() => window.scrollY || document.documentElement.scrollTop || 0"),o=t-r;Math.abs(o)<1||await this.scrollBy(o,e)}async scrollToEl(t,e={}){let o=this.page.viewportSize()?.height??await this.page.evaluate("() => window.innerHeight"),s=await t.evaluate(`(node) => {
2
+ const rect = node.getBoundingClientRect();
3
+ return { top: rect.top + window.scrollY, height: rect.height };
4
+ }`),n=Math.max(0,s.top-o*.3);await this.scrollTo(n,e)}async click(t,e,r={}){let{doubleClick:o=!1,button:s="left"}=r;await this.moveTo(t,e,{steps:r.steps,speed:r.speed,randomness:r.randomness}),await this.page.mouse.down({button:s}),await I(S(50,150)),await this.page.mouse.up({button:s}),o&&(await I(S(100,300)),await this.page.mouse.down({button:s}),await I(S(50,150)),await this.page.mouse.up({button:s}))}async clickEl(t,e={}){try{let r=await this._toPoint(t,e);await this.click(r.x,r.y,e)}catch(r){console.log("clickEl err: ",r,"el: ",t)}}generateControlPoints(t,e,r){let o=Math.hypot(e.x-t.x,e.y-t.y),s={x:t.x+(e.x-t.x)*.3+(Math.random()-.5)*o*r,y:t.y+(e.y-t.y)*.3+(Math.random()-.5)*o*r},n={x:e.x-(e.x-t.x)*.3+(Math.random()-.5)*o*r,y:e.y-(e.y-t.y)*.3+(Math.random()-.5)*o*r};return[t,s,n,e]}getDynamicDelay(t,e,r){let o=t/e,s=10+(1-r)*50;return Math.max(10,s*(1-Math.sin(o*Math.PI))*.5)}getRandomDelay(t=20,e=100){return Math.floor(Math.random()*(e-t+1))+t}async showCursor(){await this.page.addInitScript({content:`
5
+ let dot;
6
+ document.addEventListener('mousemove', (e) => {
7
+ if (!dot) {
8
+ dot = document.createElement('div');
9
+ Object.assign(dot.style, {
10
+ position: 'fixed',
11
+ width: '5px',
12
+ height: '5px',
13
+ borderRadius: '50%',
14
+ backgroundColor: 'red',
15
+ pointerEvents: 'none',
16
+ zIndex: 999999
17
+ });
18
+ document.body.appendChild(dot);
19
+ }
20
+ dot.style.left = e.clientX + 'px';
21
+ dot.style.top = e.clientY + 'px';
22
+ });
23
+ `})}},B=F;function R(i,t){let e=[];for(let r=0;r<i.length;r+=t)e.push(i.slice(r,r+t));return e}async function C(i){try{return await i.evaluate(`(element) => {
24
+ let active = document.activeElement;
25
+ // \u7A7F\u900F Shadow DOM
26
+ while (active && active.shadowRoot && active.shadowRoot.activeElement) {
27
+ active = active.shadowRoot.activeElement;
28
+ }
29
+ // 1. \u7CBE\u786E\u5339\u914D
30
+ if (active === element) return true;
31
+ // 2. \u5BB9\u5668\u5305\u542B\u5339\u914D (\u5982\u679C locator \u662F\u7236\u5BB9\u5668)
32
+ if (element.contains(active)) return true;
33
+
34
+ return false;
35
+ }`)}catch{return!1}}function _(i){return i&&typeof i=="object"&&"_frame"in i&&"_selector"in i}async function y(i,t,e,r){typeof e=="string"&&(e=i.locator(e));let{scrollTimeout:o=6e4,skipScroll:s=!1,...n}=r||{};if(await e.waitFor({state:"visible",...r}),await e.waitFor({state:"attached",...r}),!s)try{await e.scrollIntoViewIfNeeded({timeout:o})}catch(c){console.warn(`\u6EDA\u52A8\u8D85\u65F6(${o}ms)\uFF0C\u5C1D\u8BD5\u7EE7\u7EED\u6267\u884C:`,c.message);try{await e.evaluate(`
36
+ (el) => {
37
+ el.scrollIntoView({ behavior: "auto", block: "center" });
38
+ }
39
+ `),await i.waitForTimeout(500)}catch(a){console.warn("\u7B80\u5355\u6EDA\u52A8\u4E5F\u5931\u8D25\uFF0C\u5F3A\u5236\u7EE7\u7EED:",a.message)}}return await t.clickEl(e,r)}async function O(i,t,e,r){return await i.click(t,e,r)}import{cancelableFunction as we}from"@tocha688/utils/sync";import{rInt as ge}from"@tocha688/utils";async function D(i=200,t=800){let e=ge(i,t);return new Promise(r=>setTimeout(r,e))}async function H(i,t="load",e=3e4){let r=t.toUpperCase();try{return console.log(`[\u7B49\u5F85\u9875\u9762\u52A0\u8F7D] \u76EE\u6807\u72B6\u6001: ${r}, \u8D85\u65F6: ${e/1e3}s`),await i.waitForLoadState(t,{timeout:e}),console.log(`[\u7B49\u5F85\u9875\u9762\u52A0\u8F7D] ${r} \u72B6\u6001\u5DF2\u5B8C\u6210\u3002`),!0}catch{return console.error(`[\u7B49\u5F85\u9875\u9762\u52A0\u8F7D] ${r} \u72B6\u6001\u5931\u8D25\u6216\u8D85\u65F6\u3002`),!1}}function U(i,t,e,r={}){return new Promise(async(o,s)=>{let{frameAttachedTimeout:n=45e3,frameVisibleTimeout:c=1e4,frameBodyTimeout:a=15e3,frameInLocatorOptions:p={},waitForElementTimeout:l=15e3,timeout:u=2e3}=r;console.log(`[\u7B49\u5F85 ${String(t)} iframe \u5B8C\u5168\u52A0\u8F7D]`);try{console.log("\u7B49\u5F85 iframe \u5143\u7D20..."),await i.waitForSelector(String(t),{state:"attached",timeout:n}),console.log("\u7B49\u5F85 iframe \u53EF\u89C1..."),await i.waitForSelector(String(t),{state:"visible",timeout:c}),console.log("\u2705 iframe \u53EF\u89C1");let m=i.frameLocator(String(t));await m.locator("body").waitFor({state:"attached",timeout:a}),console.log("\u2705 iframe \u5185\u5BB9\u5DF2\u52A0\u8F7D"),console.log(`[\u7B49\u5F85\u6307\u5B9A\u5143\u7D20\u53EF\u89C1] ${String(e)}`),await m.locator(e,p).waitFor({timeout:l}),console.log("[\u7B49\u5F85\u5B8C\u5168\u52A0\u8F7D]"),await i.waitForTimeout(u),o(m)}catch(m){s(m)}})}function X(i,t={}){return we(async e=>{let r=Date.now();for(;e.signal.aborted===!1&&Date.now()-r<(t.timeout||3e4);){if(await i.isVisible().catch(()=>!1))return i;await D(100)}throw new Error("waitForAbort \u8D85\u65F6")})}import{rInt as W}from"@tocha688/utils";async function $(i,t,e,r,o){if(typeof e=="string"&&(e=i.locator(e)),!_(e))throw new Error("locator \u7C7B\u578B\u9519\u8BEF");let{clear:s=!0,delay:n={min:50,max:150},retries:c=3,...a}=o||{};if(await e.waitFor({state:"visible",...a}),await e.waitFor({state:"attached",...a}),await y(i,t,e,a),await D(50,100),s){let l=await e.inputValue().catch(()=>"");l&&l.length>0&&(await e.click({clickCount:3}),await D(20,50),await i.keyboard.press("Delete"),await D(20,50))}let p=R(r,5);for(let l=0;l<p.length;l++){let u=p[l];if(!await C(e)){await y(i,t,e,a);let w=await e.inputValue().catch(()=>"");w&&w.length>0&&await i.keyboard.press("End"),await D(30,60)}u&&await e.pressSequentially(u,{delay:W(n.min,n.max)}),l<p.length-1&&await D(50,150)}await D(100,200),await e.blur()}async function q(i,t,e,r,o){if(typeof e=="string"&&(e=i.locator(e)),!_(e))throw new Error("locator \u7C7B\u578B\u9519\u8BEF");let{clear:s=!0,delay:n={min:50,max:150},retries:c=3,...a}=o||{};if(await e.waitFor({state:"visible",...a}),await e.waitFor({state:"attached",...a}),await y(i,t,e,a),await D(50,100),s){let l=await e.inputValue().catch(()=>"");l&&l.length>0&&(await e.click({clickCount:3}),await D(20,50),await i.keyboard.press("Delete"),await D(20,50))}let p=R(r,5);for(let l=0;l<p.length;l++){let u=p[l];u&&await e.pressSequentially(u,{delay:W(n.min,n.max)}),l<p.length-1&&await D(50,150)}await D(100,200),await e.blur()}async function j(i,t,e,r,o){if(typeof e=="string"&&(e=i.locator(e)),!_(e))throw new Error("locator \u7C7B\u578B\u9519\u8BEF");let{retries:s=3,verify:n=!0,...c}=o||{};await e.waitFor({state:"visible",...c}),await e.waitFor({state:"attached",...c});try{let p=await e.inputValue(),l=typeof r=="string"?r:Array.isArray(r)?r[0]?.toString():r?.toString();if(p===l)return}catch(p){console.warn(`\u83B7\u53D6\u5F53\u524D\u9009\u62E9\u503C\u5931\u8D25: ${p}`)}let a=0;for(;a<s;)try{if(await y(i,t,e,c),await D(50,100),await e.selectOption(r,c),await D(100,200),n){let p=await e.inputValue(),l=typeof r=="string"?r:Array.isArray(r)?r[0]?.toString():r?.toString();if(p!==l)throw new Error(`\u9009\u62E9\u9A8C\u8BC1\u5931\u8D25: \u671F\u671B"${l}", \u5B9E\u9645"${p}"`)}await e.blur();return}catch(p){if(a++,a>=s)throw new Error(`\u9009\u62E9\u64CD\u4F5C\u5931\u8D25\uFF0C\u5DF2\u91CD\u8BD5${s}\u6B21: ${p}`);await D(200,400)}}async function z(i,t,e,r){if(typeof e=="string"&&(e=i.locator(e)),!_(e))throw new Error("locator \u7C7B\u578B\u9519\u8BEF");let{force:o=!1,retries:s=3,verify:n=!0,...c}=r||{};if(await e.waitFor({state:"visible",...c}),await e.waitFor({state:"attached",...c}),!o)try{if(await e.isChecked())return}catch(p){console.warn(`\u68C0\u67E5\u52FE\u9009\u72B6\u6001\u5931\u8D25: ${p}`)}let a=0;for(;a<s;)try{if(await y(i,t,e,c),await D(50,100),await e.check({force:o,...c}),await D(100,200),n&&!await e.isChecked())throw new Error("\u52FE\u9009\u9A8C\u8BC1\u5931\u8D25: \u5143\u7D20\u672A\u88AB\u6210\u529F\u52FE\u9009");await e.blur();return}catch(p){if(a++,a>=s)throw new Error(`\u52FE\u9009\u64CD\u4F5C\u5931\u8D25\uFF0C\u5DF2\u91CD\u8BD5${s}\u6B21: ${p}`);await D(200,400)}}async function J(i,t,e,r){if(typeof e=="string"&&(e=i.locator(e)),!_(e))throw new Error("locator \u7C7B\u578B\u9519\u8BEF");let{force:o=!1,retries:s=3,verify:n=!0,...c}=r||{};if(await e.waitFor({state:"visible",...c}),await e.waitFor({state:"attached",...c}),!o)try{if(!await e.isChecked())return}catch(p){console.warn(`\u68C0\u67E5\u52FE\u9009\u72B6\u6001\u5931\u8D25: ${p}`)}let a=0;for(;a<s;)try{if(await y(i,t,e,c),await D(50,100),await e.uncheck({force:o,...c}),await D(100,200),n&&await e.isChecked())throw new Error("\u53D6\u6D88\u52FE\u9009\u9A8C\u8BC1\u5931\u8D25: \u5143\u7D20\u4ECD\u7136\u88AB\u52FE\u9009");await e.blur();return}catch(p){if(a++,a>=s)throw new Error(`\u53D6\u6D88\u52FE\u9009\u64CD\u4F5C\u5931\u8D25\uFF0C\u5DF2\u91CD\u8BD5${s}\u6B21: ${p}`);await D(200,400)}}function K(i,t,e,r={}){let{interval:o=1e3,debug:s=!1}=r,n=[],c=!0,a=u=>{let m=u.url();(t instanceof RegExp?t.test(m):m.includes(t))&&(s&&console.log(`[Collector] \u6355\u83B7\u5230\u76EE\u6807\u8BF7\u6C42: ${m}`),n.push(u))};i.on("request",a);let p=setInterval(async()=>{if(c)for(s&&console.log(`[Poller] \u8F6E\u8BE2\u68C0\u67E5\u4E2D... \u5F53\u524D\u961F\u5217\u79EF\u538B: ${n.length}`);n.length>0;){let u=n.shift();if(u)if(e)await e(u);else{let m=`[Error] \u81F4\u547D\u9519\u8BEF: \u68C0\u6D4B\u5230\u88AB\u7981\u6B62\u7684\u8BF7\u6C42/\u672A\u5904\u7406\u7684\u8BF7\u6C42\u53D1\u9001! URL: ${u.url()}`;console.error(m),l()}}},o),l=()=>{c&&(c=!1,clearInterval(p),i.off("request",a),s&&console.log("[Poller] \u76D1\u542C\u5DF2\u505C\u6B62"))};return{stop:l}}function Y(i,t,e,r={}){let{interval:o=1e3,debug:s=!1}=r,n=!0,c=!1;s&&console.log(`[ElementMonitor] \u5F00\u59CB\u76D1\u542C\u5143\u7D20: "${t}"`);let a=setInterval(async()=>{if(!(!n||c))try{if(i.isClosed()){p();return}if(await i.isVisible(t))if(s&&console.log(`[ElementMonitor] \u53D1\u73B0\u76EE\u6807\u5143\u7D20: "${t}"`),c=!0,e)try{await e(i.locator(t))}catch(u){console.error(`[Callback Error] \u5904\u7406\u5143\u7D20 "${t}" \u56DE\u8C03\u5931\u8D25:`,u)}finally{c=!1}else{let u=`[Error] \u81F4\u547D\u9519\u8BEF: \u9875\u9762\u51FA\u73B0\u4E86\u4E0D\u8BE5\u51FA\u73B0\u7684\u5143\u7D20! Selector: "${t}"`;console.error(u),p()}}catch(l){s&&console.warn("[ElementMonitor] \u8F6E\u8BE2\u68C0\u67E5\u5F02\u5E38:",l)}},o),p=()=>{n&&(n=!1,clearInterval(a),s&&console.log(`[ElementMonitor] \u505C\u6B62\u76D1\u542C\u5143\u7D20: "${t}"`))};return{stop:p}}import{rInt as x,sleep as Q}from"@tocha688/utils";async function Z(i,t,e){let r=0,o=t+x(-100,100);if(console.log(`\u5F00\u59CB\u6A21\u62DF\u6EDA\u52A8\uFF0C\u76EE\u6807\u8DDD\u79BB: ${o}px`),e){let n=await e.boundingBox();if(n){let c=n.x+n.width/2+x(-10,10),a=n.y+n.height/2+x(-10,10);await i.mouse.move(c,a)}else console.warn("Target locator provided but element is not visible/present. Falling back to global scroll.")}let s=async n=>{await i.mouse.wheel(0,n),!e&&Math.random()<.3&&await i.mouse.move(x(100,500),x(100,500))};for(;r<o;){let n=x(50,150);r+n>o&&(n=o-r),await s(n),r+=n,Math.random()<.1?await Q(x(500,800)):await Q(x(30,100))}console.log("\u6EDA\u52A8\u5B8C\u6210")}var Ie="_ah_",P=class i{page;mouse;constructor(t){this.page=t,this.mouse=new B(t)}static create(t){let e=new i(t),r=Object.create(t);return Object.assign(r,t),Object.assign(r,e),["locator","getByRole","getByTestId","getByLabel","getByPlaceholder","getByText","getByAltText","getByTitle"].forEach(s=>{if(!t[s])return;let c=t[s].bind(t),a=Ie+s;r[a]=c,r[s]=function(...p){let l=r[a](...p);return l&&e.enhanceLocator(l)}}),r}enhanceLocator(t){let e=Object.create(t);return Object.assign(e,t),e._loc=t,e.click=this.click.bind(this,t),e.input=e.fill=this.input.bind(this,t),e.selectOption=e.select=this.select.bind(this,t),e.check=this.check.bind(this,t),e.uncheck=this.uncheck.bind(this,t),e}async click(t,e){return y(this.page,this.mouse,t,e)}async clickPoint(t,e,r){return O(this.mouse,t,e,r)}isLocator(t){return _(t)}async input(t,e,r){return $(this.page,this.mouse,t,e,r)}async inputFofce(t,e,r){return q(this.page,this.mouse,t,e,r)}async select(t,e,r){return j(this.page,this.mouse,t,e,r)}async check(t,e){return z(this.page,this.mouse,t,e)}async uncheck(t,e){return J(this.page,this.mouse,t,e)}async rWait(t=200,e=800){return D(t,e)}async safeWaitForLoadState(t="load",e=3e4){return H(this.page,t,e)}waitForIframeComplete(t,e,r={}){return U(this.page,t,e,r)}startRequestPolling(t,e,r={}){return K(this.page,t,e,r)}startElementPolling(t,e,r,o={}){return Y(t,e,r,o)}waitForAbort(t,e={}){return X(t,e)}async humanScroll(t,e){return Z(this.page,t,e)}};import ve from"path";var Et=ve.join(process.cwd(),"tmp","browser_cache");import Pe from"path";import{chromium as Le}from"patchright-core";function ee(){let i=`${Date.now()}-${Math.random().toString(36).slice(2)}`,t=Pe.join(process.cwd(),"tmps",`brw-session-${i}`);return{sessionId:i,userDataDir:t}}async function Ge(i){return(await fetch(`http://127.0.0.1:${i}/json/version`).then(e=>e.json()))?.webSocketDebuggerUrl||""}async function k(i,t){let e=await i({...t}),r=await Ge(e.port);if(!r)throw e.close(),new Error("\u65E0\u6CD5\u83B7\u53D6\u6D4F\u89C8\u5668WebSocket URL");try{let o=await Le.connectOverCDP(r),s=o.contexts()[0]?.pages()?.[0]??await o.newPage();s.setDefaultNavigationTimeout(6e4),s.setDefaultTimeout(6e4);let n=new P(s);return o._hk_close=o.close,o.close=async function(){await o._hk_close(),await e.close()},{page:s,auto:n,brw:o}}catch(o){return console.log(o),await e.close(),await k(i,t)}}import{createPool as Ee}from"generic-pool";var te=class{constructor(t,e,r={}){this.startFn=t;this.opts=e;this.pool=Ee({create:async()=>await k(this.startFn,this.opts),destroy:async o=>{await o.brw.close()},validate:async o=>o.brw.isConnected()},{min:r.min??1,max:r.max??5,testOnBorrow:r.testOnBorrow??!0,idleTimeoutMillis:r.idleTimeoutMillis??3e4})}pool;async acquire(){let t=await this.pool.acquire();return{...t,release:async()=>{await this.pool.release(t)}}}async drain(){await this.pool.drain(),await this.pool.clear()}async use(t){let e=await this.acquire();try{return await t(e)}finally{await e.release()}}};import"patchright-core";import g from"fs";import Ne from"path";import{createHash as Se}from"crypto";function re(i,t){let e=Se("md5").update(i).digest("hex"),r=Ne.join(t,e),o=r+".meta.json";return{cacheFile:r,metaFile:o}}async function zt(i,t){g.existsSync(t)||g.mkdirSync(t,{recursive:!0}),console.log("\u542F\u7528\u6D4F\u89C8\u5668\u7F13\u5B58"),await i.route("**/*",async e=>{let r=e.request();if(r.method()!=="GET")return e.continue();let o=r.resourceType();if(["xhr","fetch","websocket","document"].includes(o))return e.continue();let s=r.url(),{cacheFile:n,metaFile:c}=re(s,t);try{if(g.existsSync(n)&&g.existsSync(c)){let a=JSON.parse(g.readFileSync(c,"utf-8")),p=g.readFileSync(n);return Date.now()-a.timestamp>a.timeout?(g.unlinkSync(n),g.unlinkSync(c),e.continue()):e.fulfill({status:200,headers:a.headers,body:p,contentType:a.contentType})}}catch{}return e.continue()}),await i.on("response",async e=>{let r=e.request();if(r.method()!=="GET")return;let o=e.status();if(![200,201].includes(o))return;let s=e.url(),{cacheFile:n,metaFile:c}=re(s,t);if(g.existsSync(n)&&g.existsSync(c))return;let a=e.headers();if((a["content-type"]||"").includes("text/plain")||s.includes(";"))return;let l=a["cache-control"]||"",u=a.pragma||"";if(l.includes("no-store")||u.includes("no-cache"))return;let m=r.resourceType();if(!(!(u||l)&&(["xhr","fetch","websocket","document"].includes(m)||new URL(s).searchParams.toString().length>0)))try{let w=await e.body();g.writeFileSync(n,w),g.writeFileSync(c,JSON.stringify({url:s,headers:a,contentType:a["content-type"],timestamp:Date.now(),timeout:parseInt(a["cache-control"]?.match(/max-age=(\d+)/)?.[1]||"99999999")*1e3}))}catch{}})}async function Fe(i,t,e){return await fetch(t.url(),{method:t.method(),body:t.postData(),headers:t.headers()}).then(async r=>i.fulfill({status:r.status,headers:Object.fromEntries(r.headers.entries()),body:Buffer.from(await r.arrayBuffer())})).catch(()=>i.abort())}async function Yt(i){await i.route("**/*",async t=>{let e=t.request(),r=e.url(),o=e.resourceType();return["GET"].includes(e.method())?["xhr","fetch","websocket","document"].includes(o)||["script"].includes(o)&&r.includes("?")?await t.continue():await Fe(t,e,i):await t.continue()})}async function Qt(i){await i.route("**/*",async t=>{let e=t.request();if(e.method()!=="GET")return t.continue();let r=e.resourceType();return["xhr","fetch","websocket","document","script"].includes(r)?t.continue():t.abort()})}import*as oe from"chrome-launcher";async function tr(i){let{chromePath:t,headless:e=!1,proxy:r,userDataDir:o}=i,s=["--disable-blink-features=AutomationControlled","--no-sandbox","--disable-setuid-sandbox"];e&&s.push("--headless");let n=await oe.launch({chromePath:t,chromeFlags:s,userDataDir:o});return{userDataDir:o||"",port:n.port,browser:n,close:async()=>await n.kill()}}import b from"fs";import E from"path";import{faker as De}from"@faker-js/faker";function L(i){let t,e;t===void 0&&(t="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"),e===void 0&&(e="hTy1bfRJz4nLPcBCO7WtmNIaGvVeul5Zo8kq32UxrYw_-0gsjp96SDFXQiEMKdHA");var r=t,o=e,s=Buffer.from(i).toString("base64").split(""),n="";return s.map((function(c){var a=r.indexOf(c);return n+=a<0?c:o.substr(a,1),c})),n}function ie(i){let t,e;if(t===void 0&&(t="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"),e===void 0&&(e="hTy1bfRJz4nLPcBCO7WtmNIaGvVeul5Zo8kq32UxrYw_-0gsjp96SDFXQiEMKdHA"),!i)return"";var r=t,o=e,s=i.split(""),n="";return s.map((function(c){var a=o.indexOf(c);return n+=a<0?c:r.substr(a,1),c})),Buffer.from(n,"base64").toString()}import Re from"font-list";import{rInt as se}from"@tocha688/utils";var ne=["750 \xD7 1334","800 x 600","1024 x 600","1024 x 640","1024 x 768","1152 x 864","1280 x 720","1280 x 768","1280 x 800","1280 x 960","1280 x 1024","1360 x 768","808 \xD7 1792","828 \xD7 1792","1080 x 2340","1125 x 2436","1242 x 2208","1170 \xD7 2532","1284 x 2778","1366 x 768","1400 x 1050","1400 x 900","1440 x 900","1536 x 864","1600 x 900","1600 x 1200","1680 x 1050","1920 x 1080","1920 x 1200","2048 x 1152","2304 x 1440","2560 x 1440","2560 x 1600","2880 x 1800","4096 x 2304","5120 x 2880"],ae=["2","3","4","6","8","10","12","16","20","24","32","64"],ce=["2","4","6","8","16","32","64","128"],cr=[{name:"Google Inc. (AMD)",values:["ANGLE (AMD, RENOIR(renoir LLVM 15.0.7), OpenGL 4.6)"]},{name:"Google Inc. (Intel)",values:["ANGLE (Intel, Mesa Intel(R) Graphics (RPL-S), OpenGL 4.6)","ANGLE (Intel, Mesa Intel(R) Graphics (RPL-P), OpenGL 4.6)","ANGLE (Intel, Mesa Intel(R) Xe Graphics (TGL GT2), OpenGL 4.6)"]}],le=[{name:"Google Inc. (NVIDIA)",vendor:"nvidia",values:["ANGLE (NVIDIA, NVIDIA GeForce GTX 1660 SUPER (0x000021C4) Direct3D11 vs_5_0 ps_5_0, D3D11-27.21.14.6647)","ANGLE (NVIDIA, NVIDIA GeForce GTX 750 Ti (0x00001380) Direct3D11 vs_5_0 ps_5_0, D3D11-27.21.14.6647)","ANGLE (NVIDIA, NVIDIA GeForce GTX 650 (0x00002504) Direct3D11 vs_5_0 ps_5_0, D3D11-27.21.14.6140)","ANGLE (NVIDIA, NVIDIA GeForce GTX 1050 Ti (0x00001C8C) Direct3D9Ex vs_3_0 ps_3_0, D3D9Ex)","ANGLE (NVIDIA, NVIDIA GeForce GT 635M (0x00002504) Direct3D11 vs_5_0 ps_5_0, D3D11-10.18.13.6472)","ANGLE (NVIDIA, NVIDIA GeForce GT 710 (0x0000128B) Direct3D11 vs_5_0 ps_5_0, D3D11-26.21.14.3160)","ANGLE (NVIDIA, NVIDIA GeForce 410M (0x00001055) Direct3D11 vs_5_0 ps_5_0, D3D11)","ANGLE (NVIDIA, NVIDIA GeForce RTX 2060 (0x00001F51) Direct3D11 vs_5_0 ps_5_0, D3D11-27.21.14.6093)","ANGLE (NVIDIA, NVIDIA GeForce GTX 1060 (0x00001C20) Direct3D11 vs_5_0 ps_5_0, D3D11-27.21.14.5148)","ANGLE (NVIDIA, NVIDIA GeForce GTX 1660 (0x00002184) Direct3D11 vs_5_0 ps_5_0, D3D11-27.21.14.5751)","ANGLE (NVIDIA, NVIDIA GeForce RTX 2070 SUPER (0x00001E84) Direct3D11 vs_5_0 ps_5_0, D3D11)","ANGLE (NVIDIA, NVIDIA GeForce GTX 750 Ti (0x00001380) Direct3D9Ex vs_3_0 ps_3_0, nvd3dumx.dll-26.21.14.4219)","ANGLE (NVIDIA, NVIDIA GeForce GT 730 (0x00001287) Direct3D11 vs_5_0 ps_5_0, D3D11-27.21.14.5671)","ANGLE (NVIDIA, NVIDIA GeForce GTX 1650 (0x00001F9D) Direct3D11 vs_5_0 ps_5_0, D3D11-27.21.14.5751)","ANGLE (NVIDIA, NVIDIA GeForce GTX 1050 (0x00001C91) Direct3D11 vs_5_0 ps_5_0, D3D11-22.21.13.8476)","ANGLE (NVIDIA, NVIDIA GeForce GTX 950 (0x00001402) Direct3D11 vs_5_0 ps_5_0, D3D11-26.21.14.4187)","ANGLE (NVIDIA, NVIDIA GeForce GTX 960 (0x00001401) Direct3D11 vs_5_0 ps_5_0, D3D11)","ANGLE (NVIDIA, NVIDIA GeForce RTX 3070 (0x00002484) Direct3D11 vs_5_0 ps_5_0, D3D11-27.21.14.6611)","ANGLE (NVIDIA, NVIDIA GeForce RTX 2060 (0x00001F51) Direct3D11 vs_5_0 ps_5_0, D3D11-27.21.14.5256)","ANGLE (NVIDIA, NVIDIA GeForce GTX 660 (0x000011C0) Direct3D11 vs_5_0 ps_5_0, D3D11-27.21.14.5671)","ANGLE (NVIDIA, NVIDIA GeForce GTX 970 (0x000013C2) Direct3D11 vs_5_0 ps_5_0, D3D11-27.21.14.5671)","ANGLE (NVIDIA, NVIDIA GeForce GTX 1650 (0x00001F9D) Direct3D11 vs_5_0 ps_5_0, D3D11-27.21.14.5256)","ANGLE (NVIDIA, NVIDIA GeForce 205 (0x00002504) Direct3D11 vs_4_1 ps_4_1, D3D11)","ANGLE (NVIDIA, NVIDIA GeForce GTX 1070 (0x00001BA1) Direct3D11 vs_5_0 ps_5_0, D3D11)","ANGLE (NVIDIA, NVIDIA Quadro K620 (0x00002504) Direct3D11 vs_5_0 ps_5_0, D3D11)","ANGLE (NVIDIA, NVIDIA GeForce GTX 1060 3GB (0x00001C02) Direct3D9Ex vs_3_0 ps_3_0, D3D9Ex)","ANGLE (NVIDIA, NVIDIA GeForce GT 635M (0x00002504) Direct3D11 vs_5_0 ps_5_0, D3D11-23.21.13.9124)","ANGLE (NVIDIA, NVIDIA GeForce GTX 1050 (0x00001C91) Direct3D11 vs_5_0 ps_5_0, D3D11-26.21.14.3630)","ANGLE (NVIDIA, NVIDIA GeForce RTX 2060 (0x00001F51) Direct3D11 vs_5_0 ps_5_0, D3D11-26.21.14.4250)","ANGLE (NVIDIA, NVIDIA GeForce RTX 2060 SUPER (0x00001F47) Direct3D11 vs_5_0 ps_5_0, D3D11-27.21.14.5167)","ANGLE (NVIDIA, NVIDIA Quadro P600 (0x00001CB2) Direct3D11 vs_5_0 ps_5_0, D3D11-27.21.14.5239)","ANGLE (NVIDIA, NVIDIA Quadro M1000M (0x00002504) Direct3D11 vs_5_0 ps_5_0, D3D11)","ANGLE (NVIDIA, NVIDIA GeForce GTX 550 Ti (0x00001244) Direct3D11 vs_5_0 ps_5_0, D3D11)","ANGLE (NVIDIA, NVIDIA GeForce 210 (0x00000A65) Direct3D11 vs_4_0 ps_4_0, D3D11)","ANGLE (NVIDIA, NVIDIA GeForce GTX 1650 SUPER (0x00002187) Direct3D11 vs_5_0 ps_5_0, D3D11-26.21.14.4120)","ANGLE (NVIDIA, NVIDIA GeForce GTX 1660 Ti (0x00002191) Direct3D11 vs_5_0 ps_5_0, D3D11)","ANGLE (NVIDIA, NVIDIA GeForce GT 1030 (0x00001D01) Direct3D11 vs_5_0 ps_5_0, D3D11-27.21.14.5671)","ANGLE (NVIDIA, NVIDIA GeForce GTX 970 (0x000013C2) Direct3D11 vs_5_0 ps_5_0, D3D11)","ANGLE (NVIDIA, NVIDIA GeForce GTX 1070 (0x00001BA1) Direct3D11 vs_5_0 ps_5_0, D3D11-23.21.13.8813)","ANGLE (NVIDIA, NVIDIA GeForce GT 730 (0x00001287) Direct3D11 vs_5_0 ps_5_0, D3D11-9.18.13.4411)"]},{name:"Google Inc. (AMD)",vendor:"amd",values:["ANGLE (AMD, AMD Radeon(TM) RX 560 Series (0x00001636) Direct3D11 vs_5_0 ps_5_0, D3D11)","ANGLE (AMD, AMD Radeon(TM) Vega 8 Mobile Graphics (0x000015DD) Direct3D9Ex vs_3_0 ps_3_0, D3D11)","ANGLE (AMD, Radeon RX RX550/550 Series (0x00001636) Direct3D11 vs_5_0 ps_5_0, D3D11)","ANGLE (AMD, AMD Radeon R7 350 Series (0x00001636) Direct3D11 vs_5_0 ps_5_0, D3D11-26.20.15029.27017)","ANGLE (AMD, AMD Radeon(TM) R7 Graphics (0x0000130F) Direct3D11 vs_5_0 ps_5_0, D3D11-27.20.1034.6)","ANGLE (AMD, Radeon RX 560 Series (0x000067EF) Direct3D11 vs_5_0 ps_5_0, D3D11-26.20.15029.27017)","ANGLE (AMD, AMD Radeon HD 7800 Series (0x00006819) Direct3D9Ex vs_3_0 ps_3_0, aticfx64.dll-26.20.15029.15007)","ANGLE (AMD, AMD Radeon RX 580 2048SP (0x00006FDF) Direct3D11 vs_5_0 ps_5_0, D3D11-27.20.15003.5017)","ANGLE (AMD, AMD Radeon(TM) Vega 8 Graphics (0x000015DD) Direct3D11 vs_5_0 ps_5_0, D3D11-27.20.14501.18003)","ANGLE (AMD, AMD Radeon(TM) Graphics (0x0000164E) Direct3D11 vs_5_0 ps_5_0, D3D11-27.20.14044.2001)","ANGLE (AMD, AMD Radeon Series (0x00001636) Direct3D9Ex vs_3_0 ps_3_0, aticfx32.dll-23.20.15002.11)","ANGLE (AMD, Radeon (TM) RX 470 Graphics (0x00001636) Direct3D11 vs_5_0 ps_5_0, D3D11-26.20.13031.18002)","ANGLE (AMD, AMD Radeon HD 6530D (0x00001636) Direct3D11 vs_5_0 ps_5_0, D3D11)","ANGLE (AMD, Radeon RX 580 Series (0x000067DF) Direct3D11 vs_5_0 ps_5_0, D3D11-27.20.14534.2)","ANGLE (AMD, AMD Radeon(TM) RX Vega 10 Graphics (0x000015DD) Direct3D11 vs_5_0 ps_5_0, D3D11-25.20.14132.2002)","ANGLE (AMD, AMD Radeon R7 430 (0x00006611) Direct3D11 vs_5_0 ps_5_0, D3D11)","ANGLE (AMD, AMD Radeon (TM) R9 200 Series (0x00006811) Direct3D11 vs_5_0 ps_5_0, D3D11-27.20.1034.6)","ANGLE (AMD, AMD Radeon(TM) Vega 8 Graphics (0x000015DD) Direct3D11 vs_5_0 ps_5_0, D3D11-26.20.11008.3003)","ANGLE (AMD, AMD Radeon(TM) RX Vega 10 Graphics (0x000015DD) Direct3D11 vs_5_0 ps_5_0, D3D11-27.20.1028.1)","ANGLE (AMD, AMD Radeon(TM) Graphics (0x0000164E) Direct3D11 vs_5_0 ps_5_0, D3D11-27.20.1020.2002)","ANGLE (AMD, AMD Radeon(TM) Vega 8 Graphics (0x000015DD) Direct3D11 vs_5_0 ps_5_0, D3D11)","ANGLE (AMD, AMD Radeon R7 200 Series (0x00006658) Direct3D11 vs_5_0 ps_5_0, D3D11)"]},{name:"Google Inc. (Intel)",vendor:"Intel",values:["ANGLE (Intel, Intel(R) UHD Graphics 630 (0x00003E98) Direct3D11 vs_5_0 ps_5_0, D3D11-25.20.100.6617)","ANGLE (Intel, Intel(R) UHD Graphics 620 (0x00003EA0) Direct3D11 vs_5_0 ps_5_0, D3D11-24.20.100.6346)","ANGLE (Intel, Intel(R) UHD Graphics 630 (0x00003E98) Direct3D11 vs_5_0 ps_5_0, D3D11-26.20.100.7637)","ANGLE (Intel, Intel(R) UHD Graphics 630 (0x00003E98) Direct3D11 vs_5_0 ps_5_0, D3D11-27.20.100.8682)","ANGLE (Intel, Intel(R) HD Graphics Family (0x00000A16) Direct3D9Ex vs_3_0 ps_3_0, igdumdim64.dll-10.18.10.3907)","ANGLE (Intel, Intel(R) HD Graphics 4000 (0x00000162) Direct3D11 vs_5_0 ps_5_0, D3D11-10.18.10.4252)","ANGLE (Intel, Intel(R) HD Graphics 530 (0x0000191B) Direct3D11 vs_5_0 ps_5_0, D3D11-20.19.15.4364)","ANGLE (Intel, Intel(R) UHD Graphics 620 (0x00003EA0) Direct3D11 vs_5_0 ps_5_0, D3D11-27.20.100.9126)","ANGLE (Intel, Intel(R) UHD Graphics (0x00009BA4) Direct3D11 vs_5_0 ps_5_0, D3D11-26.20.100.7985)","ANGLE (Intel, Intel(R) HD Graphics Family (0x00000A16) Direct3D11 vs_5_0 ps_5_0, D3D11-20.19.15.5058)","ANGLE (Intel, Intel(R) UHD Graphics 610 (0x00003EA1) Direct3D11 vs_5_0 ps_5_0, D3D11-25.20.100.6471)","ANGLE (Intel, Intel(R) HD Graphics 4600 (0x00000416) Direct3D11 vs_5_0 ps_5_0, D3D11-10.18.14.5067)","ANGLE (Intel, Intel(R) HD Graphics (0x000022B0) Direct3D11 vs_5_0 ps_5_0, D3D11-10.18.10.5100)ANGLE (Intel, Intel(R) HD Graphics (0x000022B0) Direct3D11 vs_5_0 ps_5_0, D3D11-10.18.10.5100)","ANGLE (Intel, Intel(R) HD Graphics (0x000022B0) Direct3D11 vs_5_0 ps_5_0, D3D11-10.18.10.5100)","ANGLE (Intel, Intel(R) UHD Graphics 630 (0x00003E98) Direct3D11 vs_5_0 ps_5_0, D3D11-27.20.100.9466)","ANGLE (Intel, Intel(R) HD Graphics 4400 (0x0000041E) Direct3D11 vs_5_0 ps_5_0, D3D11-10.18.10.3412)","ANGLE (Intel, Intel(R) Iris(TM) Graphics 6100 (0x00007DD5) Direct3D11 vs_5_0 ps_5_0, D3D11)","ANGLE (Intel, Intel(R) Iris(R) Plus Graphics (0x00008A5A) Direct3D11 vs_5_0 ps_5_0, D3D11-27.20.100.8853)","ANGLE (Intel, Intel(R) HD Graphics 520 (0x00001921) Direct3D11 vs_5_0 ps_5_0, D3D11-21.20.16.4727)","ANGLE (Intel, Intel(R) Iris(R) Plus Graphics (0x00008A5A) Direct3D9Ex vs_3_0 ps_3_0, D3D9Ex)","ANGLE (Intel, Intel(R) HD Graphics (0x000022B0) Direct3D11 vs_5_0 ps_5_0, D3D11-10.18.10.5059)","ANGLE (Intel, Intel(R) HD Graphics 5300 (0x00007DD5) Direct3D11 vs_5_0 ps_5_0, D3D11-20.19.15.4531)","ANGLE (Intel, Intel(R) HD Graphics 4000 (0x00000162) Direct3D9Ex vs_3_0 ps_3_0, igdumd64.dll-9.17.10.2849)"]}];async function pe(){let t=(await Re.getFonts()).filter(o=>!/[\u4e00-\u9fa5]/.test(o)),e=se(5,Math.min(50,t.length)),r=[...t];for(let o=r.length-1;o>0;o--){let s=se(0,o),n=r[o];r[o]=r[s],r[s]=n}return r.slice(0,e)}import{checkAutoProxy as Me,rArrItem as v,rInt as Te,rAutoDigitInt as A}from"@tocha688/utils";import ke from"portfinder";import M from"fs";import*as ue from"chrome-launcher";import{tryCatch as T,tryLoop as me}from"@tocha688/utils";async function G(i,t){let{userDataDir:e}=ee();M.mkdirSync(e,{recursive:!0});let r;try{let o=await ke.getPortPromise({port:41e3,stopPort:49999});r=await t.prepare(e,o);let s=[`--user-data-dir=${e}`,`--remote-debugging-port=${o}`,"--remote-debugging-address=0.0.0.0",...r.args];i.headless!==!1&&!s.some(c=>c.startsWith("--headless"))&&s.push("--headless");let n=await ue.launch({userDataDir:e,port:o,chromePath:i.chromePath,chromeFlags:s,startingUrl:r.startingUrl||"about:blank"});return{userDataDir:e,port:n.port,browser:n,close:async()=>{await T(async()=>await n.kill()),r?.cleanup&&await T(r.cleanup),await me(async()=>M.rmSync(e,{recursive:!0,force:!0}))}}}catch(o){throw await me(async()=>M.rmSync(e,{recursive:!0,force:!0})),r?.cleanup&&await T(r.cleanup),o}}async function vr(i){return G(i,{prepare:async(t,e)=>{let r=E.join(t,"webgl.json"),o=E.join(t,"dynamic.config"),s=E.join(t,"static.config"),n=E.join(t,"params.config"),c,a;if(b.existsSync(n))c=b.readFileSync(n,"utf-8"),a=JSON.parse(ie(c)).ScreenSize;else{let l={},u;i.proxy&&(l=await Me(i.proxy),u=new URL(l.proxy));let m={fp:Te(1e5,999999),geop:l?.latitude?l?.latitude+","+l?.longitude:"",device_name:"PC"+De.string.alphanumeric(8).toUpperCase(),timezone:l?.timezone||"America/Los_Angeles",proxy:{protocol:u?.protocol.replace(":","")||"http",host:u?.hostname||"127.0.0.1",port:u?.port||"8080",username:u?.username||"",password:u?.password||""},mac:De.internet.mac(),scanPorts:"3389,1080",screenSize:v(ne),langs:l?.languages??"en-US,en"},w=v(le),N={UNMASKED_VENDOR_WEBGL:w.name,UNMASKED_RENDERER_WEBGL:v(w.values),GPUAdapterInfo:{vendor:w.vendor,architecture:"pascal"},SUPPORTED_EXTENSIONS:[]},de={BlockList:{Version:"1743148877",Domains:[]},StrongBlockList:{Version:"3",Domains:[]},TimeZone:m.timezone,Geoposition:m.geop},h={CookiesExportPath:"",SecurePreferenceSync:!0,PasswordExportPath:"",PasswordImportPath:"",RestoreLastSession:!0,BlockPage:"NDA0",FoceSafeBrowsing:!0,ExtensionSetting:[],DisCanvasUrl:"",MaxTouchPoints:0,MediaDevices:[{kind:"audioinput",label:"Microphone Array (Realtek(R) Audio)"},{kind:"videoinput",label:"Integrated Camera (98da:3959)"},{kind:"audiooutput",label:"Speakers (Realtek(R) Audio)"}],AudioFp:A(980,m.fp),WebGLMark:A("5001",m.fp).toString(),StartTime:Math.floor(Date.now()/1e3),GeolocationSetting:"ask",FlashPluginSetting:"block",Platform:"Win32",ScreenSize:m.screenSize,DisableBackgroundMode:!0,DisableWebRTC:!0,HardwareConcurrency:v(ae),DeviceMemory:v(ce),LoadExtensionErrorBox:!1,ClientRectFp:A("5001",m.fp).toString(),ForceProcessExit:!0,ProxyUser:m.proxy.username,ProxyPassword:m.proxy.password,Langs:m.langs,AcceptLang:m.langs?m.langs+",q=0.9":"en-US,en;q=0.9",DisabledFonts:(await pe()).join(",")};b.writeFileSync(r,JSON.stringify(N)),b.writeFileSync(o,L(JSON.stringify(de))),b.writeFileSync(s,L(JSON.stringify(h))),c=L(JSON.stringify({UserId:"1",CanvasMark:A("7949",m.fp).toString(),DisableContainer:!0,WebGLFP:r,AudioFp:h.AudioFp,WebGLMark:h.WebGLMark,StartTime:h.StartTime,AllowScanPorts:m.scanPorts,GeolocationSetting:h.GeolocationSetting,FlashPluginSetting:h.FlashPluginSetting,Platform:h.Platform,ScreenSize:h.ScreenSize,DisableBackgroundMode:h.DisableBackgroundMode,DisableWebRTC:h.DisableWebRTC,HardwareConcurrency:h.HardwareConcurrency,DeviceMemory:h.DeviceMemory,LoadExtensionErrorBox:h.LoadExtensionErrorBox,ClientRectFp:h.ClientRectFp,CanvasMarkEx:A("7949",m.fp).toString(),WebGLMarkEx:A("5001",m.fp).toString(),command_line:{"do-not-de-elevate":""},ProxyChain:[{scheme:m.proxy.protocol,host:m.proxy.host,port:m.proxy.port,account:m.proxy.username,password:m.proxy.password}],ForceProcessExit:h.ForceProcessExit,ProxyUser:h.ProxyUser,ProxyPassword:h.ProxyPassword,Langs:h.Langs,AcceptLang:h.AcceptLang,TimeZone:m.timezone,Geoposition:m.geop,DynamicConfig:o,StaticConfig:s})),b.writeFileSync(n,c),a=h.ScreenSize}return{args:["--disable-background-networking","--disable-client-side-phishing-detection","--disable-default-apps","--disable-hang-monitor","--disable-popup-blocking","--disable-prompt-on-repost","--disable-sync","--metrics-recording-only","--no-first-run","--safebrowsing-disable-auto-update","--password-store=basic","--no-service-autorun","--disable-features=Translate,AcceptCHFrame,MediaRouter,OptimizationHints,ProcessPerSiteUpToMainFrameThreshold,IsolateSandboxedIframes","--force-color-profile=srgb","--use-mock-keychain","--export-tagged-pdf","--no-default-browser-check","--window-position=0,0","--disable-background-mode","--ash-host-window-bounds="+a,"--window-size="+a,"--disable-renderer-accessibility","--disable-legacy-window","--fake-variations-channel=stable","--variations-server-url=https://clientservices.googleapis.com/chrome-variations/seed","--component-updater=initial-delay=6e5","--lang=en-US","--enable-features=NetworkService,NetworkServiceInProcess,LoadCryptoTokenExtension,PermuteTLSExtensions","--enable-blink-features=IdleDetection,Fledge","--extended-parameters="+c,"--flag-switches-begin","--flag-switches-end","--load-extension=","--no-sandbox"],startingUrl:"https://ipapi.co/json/"}}})}import{faker as Ve}from"@faker-js/faker";import{startProxyServer as Be}from"@tocha688/utils";import V from"fs";import Ce from"path";async function Oe(i){return G(i,{prepare:async(t,e)=>{let r;i.proxy&&(r=await Be(i.proxy),console.log(`Started proxy server on port ${r.port}`));let o=Ce.join(t,"fingerprint.config"),s;V.existsSync(o)?s=V.readFileSync(o,"utf-8"):(s=Ve.number.int({min:1e7,max:99999999}).toString(),V.writeFileSync(o,s));let n=["--allow-pre-commit-input","--disable-background-networking","--disable-background-timer-throttling","--disable-backgrounding-occluded-windows","--disable-breakpad","--disable-client-side-phishing-detection","--disable-component-extensions-with-background-pages","--disable-crash-reporter","--disable-default-apps","--disable-dev-shm-usage","--disable-hang-monitor","--disable-infobars","--disable-ipc-flooding-protection","--disable-popup-blocking","--disable-prompt-on-repost","--disable-renderer-backgrounding","--disable-search-engine-choice-screen","--disable-sync","--export-tagged-pdf","--force-color-profile=srgb","--generate-pdf-document-outline","--metrics-recording-only","--no-first-run","--password-store=basic","--use-mock-keychain","--disable-features=Translate,AcceptCHFrame,MediaRouter,OptimizationHints,ProcessPerSiteUpToMainFrameThreshold,IsolateSandboxedIframes","--enable-features=PdfOopif","--fingerprints="+s,"--window-size=1280,720","--window-position=0,0","--no-sandbox","--ignore-certificate-errors","--notice-number=1","--ignores=tls","--enable-logging","--timezone="+(r?.ipinfo?.timezone??"America/Los_Angeles"),"--lang=en-US"];return r&&r.port&&n.push(`--proxy-server=http://127.0.0.1:${r.port}`),{args:n,startingUrl:"https://ipapi.co/json/",cleanup:async()=>{r&&await r.server.close(!0)}}}})}async function Rr(i){return Oe(i)}import"chrome-launcher";import"proxy-chain";export{vr as AdsBrowserStartMain,P as AutoHelper,Et as BrowserCachePath,te as BrowserPool,ae as Cpus,F as HumanMouse,cr as LinuxWebGL,ce as Memorys,Rr as OKBrowserCreate,Oe as OKBrowserStartMain,ne as PcScreen,le as WindowsWebGL,k as createBrowser,Fe as fetchResource,Ge as getBrowserWebSocketUrl,C as isElementFocused,_ as isLocator,G as launchBrowserBase,ee as makeUniqueBrowserConfig,pe as rSysFonts,Qt as routeAssetsAbort,zt as routeAssetsCache,Yt as routeAssetsLocal,R as splitTextIntoChunks,tr as startLocalBrowser};
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@tocha688/browser",
3
+ "version": "0.0.1",
4
+ "main": "dist/index.cjs",
5
+ "module": "dist/index.js",
6
+ "exports": {
7
+ ".": {
8
+ "import": "./dist/index.js",
9
+ "require": "./dist/index.cjs"
10
+ }
11
+ },
12
+ "type": "module",
13
+ "publishConfig": {
14
+ "access": "public"
15
+ },
16
+ "devDependencies": {
17
+ "@types/bezier-js": "^4.1.3",
18
+ "@types/bun": "latest",
19
+ "@types/node": "^25.0.10",
20
+ "esbuild": "^0.27.2",
21
+ "fast-glob": "^3.3.3",
22
+ "tsup": "^8.5.1"
23
+ },
24
+ "peerDependencies": {
25
+ "typescript": "^5"
26
+ },
27
+ "dependencies": {
28
+ "@faker-js/faker": "^10.2.0",
29
+ "bezier-js": "^6.1.4",
30
+ "chrome-launcher": "^1.2.1",
31
+ "font-list": "^2.0.1",
32
+ "generic-pool": "^3.9.0",
33
+ "patchright-core": "^1.57.0",
34
+ "portfinder": "^1.0.38",
35
+ "proxy-chain": "^2.7.1",
36
+ "undici": "^7.18.2",
37
+ "@tocha688/utils": "0.0.1"
38
+ },
39
+ "scripts": {
40
+ "build": "tsup"
41
+ }
42
+ }
@@ -0,0 +1,59 @@
1
+ import type { Locator, Page } from "patchright-core";
2
+ import HumanMouse, { type ClickOptions } from "../../human/mouse";
3
+
4
+ export async function click(
5
+ page: Page,
6
+ mouse: HumanMouse,
7
+ locator: Locator | string,
8
+ options?: Parameters<Locator["waitFor"]>[0] &
9
+ Parameters<Locator["click"]>[0] & {
10
+ scrollTimeout?: number;
11
+ skipScroll?: boolean;
12
+ }
13
+ ) {
14
+ if (typeof locator === "string") {
15
+ locator = page.locator(locator);
16
+ }
17
+ const {
18
+ scrollTimeout = 60000,
19
+ skipScroll = false,
20
+ ...clickOptions
21
+ } = options || {};
22
+ // 等待元素可见和可用
23
+ await locator.waitFor({ state: "visible", ...options });
24
+ await locator.waitFor({ state: "attached", ...options });
25
+ // 滚动到元素可见
26
+ // 尝试滚动到元素可见带超时
27
+ if (!skipScroll) {
28
+ try {
29
+ // 设置滚动超时
30
+ await locator.scrollIntoViewIfNeeded({
31
+ timeout: scrollTimeout,
32
+ });
33
+ } catch (error: any) {
34
+ console.warn(
35
+ `滚动超时(${scrollTimeout}ms),尝试继续执行:`,
36
+ error.message
37
+ );
38
+
39
+ // 尝试简单的滚动
40
+ try {
41
+ const script = `
42
+ (el) => {
43
+ el.scrollIntoView({ behavior: "auto", block: "center" });
44
+ }
45
+ `;
46
+ await locator.evaluate(script);
47
+ await page.waitForTimeout(500); // 等待滚动完成
48
+ } catch (simpleError: any) {
49
+ // 如果还是失败,记录但继续
50
+ console.warn("简单滚动也失败,强制继续:", simpleError.message);
51
+ }
52
+ }
53
+ }
54
+ return await mouse.clickEl(locator, options);
55
+ }
56
+
57
+ export async function clickPoint(mouse: HumanMouse, x: number, y: number, options?: ClickOptions) {
58
+ return await mouse.click(x, y, options);
59
+ }