@crawlee/stagehand 4.0.0-beta.99 → 4.0.0-rc.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.
- package/README.md +1 -1
- package/index.d.ts +4 -3
- package/index.js +5 -3
- package/index.mjs +26 -15
- package/internals/stagehand-browser-pool.d.ts +63 -0
- package/internals/stagehand-browser-pool.js +55 -0
- package/internals/stagehand-controller.d.ts +1 -16
- package/internals/stagehand-controller.js +12 -12
- package/internals/stagehand-crawler.d.ts +140 -128
- package/internals/stagehand-crawler.js +45 -26
- package/internals/stagehand-launcher.d.ts +34 -36
- package/internals/stagehand-launcher.js +22 -13
- package/internals/stagehand-plugin.d.ts +3 -17
- package/internals/stagehand-plugin.js +20 -26
- package/package.json +12 -18
package/README.md
CHANGED
|
@@ -34,7 +34,7 @@ Crawlee is available as the [`crawlee`](https://www.npmjs.com/package/crawlee) N
|
|
|
34
34
|
|
|
35
35
|
We recommend visiting the [Introduction tutorial](https://crawlee.dev/js/docs/introduction) in Crawlee documentation for more information.
|
|
36
36
|
|
|
37
|
-
> Crawlee requires **Node.js
|
|
37
|
+
> Crawlee requires **Node.js 22.13 or higher**.
|
|
38
38
|
|
|
39
39
|
### With Crawlee CLI
|
|
40
40
|
|
package/index.d.ts
CHANGED
|
@@ -51,7 +51,8 @@
|
|
|
51
51
|
*/
|
|
52
52
|
export * from '@crawlee/browser';
|
|
53
53
|
export { StagehandCrawler, createStagehandRouter } from './internals/stagehand-crawler';
|
|
54
|
-
export
|
|
54
|
+
export { stagehandBrowserPool, remoteStagehandBrowserPool } from './internals/stagehand-browser-pool';
|
|
55
|
+
export type { StagehandBrowserPool, StagehandBrowserPoolOptions, RemoteStagehandBrowserPoolOptions, } from './internals/stagehand-browser-pool';
|
|
56
|
+
export type { StagehandOptions, StagehandPage, StagehandCrawlingContext, StagehandHook, StagehandGotoOptions, StagehandCrawlerOptions, } from './internals/stagehand-crawler';
|
|
55
57
|
export type { StagehandLaunchContext } from './internals/stagehand-launcher';
|
|
56
|
-
export
|
|
57
|
-
export type { ActOptions, ActResult, Action, AgentConfig, AgentResult, ExtractOptions, ModelConfiguration, ObserveOptions, Stagehand, } from '@browserbasehq/stagehand';
|
|
58
|
+
export type { ActOptions, ActResult, Action, AgentConfig, ExtractOptions, ModelConfiguration, ObserveOptions, Stagehand, } from '@browserbasehq/stagehand';
|
package/index.js
CHANGED
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
* @module @crawlee/stagehand
|
|
52
52
|
*/
|
|
53
53
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
54
|
-
exports.
|
|
54
|
+
exports.remoteStagehandBrowserPool = exports.stagehandBrowserPool = exports.createStagehandRouter = exports.StagehandCrawler = void 0;
|
|
55
55
|
const tslib_1 = require("tslib");
|
|
56
56
|
// Re-export everything from @crawlee/browser for convenience
|
|
57
57
|
tslib_1.__exportStar(require("@crawlee/browser"), exports);
|
|
@@ -59,5 +59,7 @@ tslib_1.__exportStar(require("@crawlee/browser"), exports);
|
|
|
59
59
|
var stagehand_crawler_1 = require("./internals/stagehand-crawler");
|
|
60
60
|
Object.defineProperty(exports, "StagehandCrawler", { enumerable: true, get: function () { return stagehand_crawler_1.StagehandCrawler; } });
|
|
61
61
|
Object.defineProperty(exports, "createStagehandRouter", { enumerable: true, get: function () { return stagehand_crawler_1.createStagehandRouter; } });
|
|
62
|
-
// Export
|
|
63
|
-
|
|
62
|
+
// Export the browser pool factories, which are how a pool with non-default options reaches the crawler
|
|
63
|
+
var stagehand_browser_pool_1 = require("./internals/stagehand-browser-pool");
|
|
64
|
+
Object.defineProperty(exports, "stagehandBrowserPool", { enumerable: true, get: function () { return stagehand_browser_pool_1.stagehandBrowserPool; } });
|
|
65
|
+
Object.defineProperty(exports, "remoteStagehandBrowserPool", { enumerable: true, get: function () { return stagehand_browser_pool_1.remoteStagehandBrowserPool; } });
|
package/index.mjs
CHANGED
|
@@ -2,14 +2,15 @@ import mod from "./index.js";
|
|
|
2
2
|
|
|
3
3
|
export default mod;
|
|
4
4
|
export const API_PROCESSED_REQUESTS_DELAY_MILLIS = mod.API_PROCESSED_REQUESTS_DELAY_MILLIS;
|
|
5
|
+
export const AfterCommitError = mod.AfterCommitError;
|
|
5
6
|
export const ApifyLogAdapter = mod.ApifyLogAdapter;
|
|
7
|
+
export const ArgumentValidationError = mod.ArgumentValidationError;
|
|
6
8
|
export const AutoscaledPool = mod.AutoscaledPool;
|
|
7
9
|
export const BLOCKED_STATUS_CODES = mod.BLOCKED_STATUS_CODES;
|
|
8
10
|
export const BaseCrawleeLogger = mod.BaseCrawleeLogger;
|
|
9
11
|
export const BasicCrawler = mod.BasicCrawler;
|
|
10
12
|
export const BrowserCrawler = mod.BrowserCrawler;
|
|
11
13
|
export const BrowserLauncher = mod.BrowserLauncher;
|
|
12
|
-
export const ClientLoadSignal = mod.ClientLoadSignal;
|
|
13
14
|
export const ConcurrencySystem = mod.ConcurrencySystem;
|
|
14
15
|
export const Configuration = mod.Configuration;
|
|
15
16
|
export const ContextPipeline = mod.ContextPipeline;
|
|
@@ -18,13 +19,13 @@ export const ContextPipelineInitializationError = mod.ContextPipelineInitializat
|
|
|
18
19
|
export const ContextPipelineInterruptedError = mod.ContextPipelineInterruptedError;
|
|
19
20
|
export const CookieParseError = mod.CookieParseError;
|
|
20
21
|
export const CpuLoadSignal = mod.CpuLoadSignal;
|
|
22
|
+
export const CrawlingRequest = mod.CrawlingRequest;
|
|
21
23
|
export const CriticalError = mod.CriticalError;
|
|
22
24
|
export const DATASET_ITERATORS_DEFAULT_LIMIT = mod.DATASET_ITERATORS_DEFAULT_LIMIT;
|
|
23
25
|
export const DEFAULT_CURRENT_HISTORY_SECS = mod.DEFAULT_CURRENT_HISTORY_SECS;
|
|
24
26
|
export const DEFAULT_SNAPSHOT_HISTORY_SECS = mod.DEFAULT_SNAPSHOT_HISTORY_SECS;
|
|
25
27
|
export const Dataset = mod.Dataset;
|
|
26
28
|
export const EnqueueStrategy = mod.EnqueueStrategy;
|
|
27
|
-
export const ErrorSnapshotter = mod.ErrorSnapshotter;
|
|
28
29
|
export const ErrorTracker = mod.ErrorTracker;
|
|
29
30
|
export const EventLoopLoadSignal = mod.EventLoopLoadSignal;
|
|
30
31
|
export const EventManager = mod.EventManager;
|
|
@@ -36,7 +37,6 @@ export const LogLevel = mod.LogLevel;
|
|
|
36
37
|
export const Logger = mod.Logger;
|
|
37
38
|
export const LoggerJson = mod.LoggerJson;
|
|
38
39
|
export const LoggerText = mod.LoggerText;
|
|
39
|
-
export const MAX_POOL_SIZE = mod.MAX_POOL_SIZE;
|
|
40
40
|
export const MAX_QUERIES_FOR_CONSISTENCY = mod.MAX_QUERIES_FOR_CONSISTENCY;
|
|
41
41
|
export const MemoryLoadSignal = mod.MemoryLoadSignal;
|
|
42
42
|
export const MemoryStorageBackend = mod.MemoryStorageBackend;
|
|
@@ -45,20 +45,19 @@ export const MissingSessionError = mod.MissingSessionError;
|
|
|
45
45
|
export const NavigationSkippedError = mod.NavigationSkippedError;
|
|
46
46
|
export const NonRetryableError = mod.NonRetryableError;
|
|
47
47
|
export const OwnedOrInjected = mod.OwnedOrInjected;
|
|
48
|
-
export const
|
|
48
|
+
export const PersistentRateLimitError = mod.PersistentRateLimitError;
|
|
49
49
|
export const ProxyConfiguration = mod.ProxyConfiguration;
|
|
50
|
-
export const PseudoUrl = mod.PseudoUrl;
|
|
51
50
|
export const QUERY_HEAD_BUFFER = mod.QUERY_HEAD_BUFFER;
|
|
52
51
|
export const QUERY_HEAD_MIN_LENGTH = mod.QUERY_HEAD_MIN_LENGTH;
|
|
53
52
|
export const REQUESTS_PERSISTENCE_KEY = mod.REQUESTS_PERSISTENCE_KEY;
|
|
54
53
|
export const RecoverableState = mod.RecoverableState;
|
|
55
54
|
export const Request = mod.Request;
|
|
56
55
|
export const RequestHandlerError = mod.RequestHandlerError;
|
|
57
|
-
export const RequestHandlerResult = mod.RequestHandlerResult;
|
|
58
56
|
export const RequestList = mod.RequestList;
|
|
59
57
|
export const RequestManagerTandem = mod.RequestManagerTandem;
|
|
60
58
|
export const RequestQueue = mod.RequestQueue;
|
|
61
59
|
export const RequestState = mod.RequestState;
|
|
60
|
+
export const RequestThrottledError = mod.RequestThrottledError;
|
|
62
61
|
export const RequestValidationError = mod.RequestValidationError;
|
|
63
62
|
export const RetryRequestError = mod.RetryRequestError;
|
|
64
63
|
export const Router = mod.Router;
|
|
@@ -69,25 +68,30 @@ export const ServiceLocator = mod.ServiceLocator;
|
|
|
69
68
|
export const Session = mod.Session;
|
|
70
69
|
export const SessionError = mod.SessionError;
|
|
71
70
|
export const SessionPool = mod.SessionPool;
|
|
71
|
+
export const SessionRetiredError = mod.SessionRetiredError;
|
|
72
72
|
export const SitemapRequestLoader = mod.SitemapRequestLoader;
|
|
73
73
|
export const SnapshotStore = mod.SnapshotStore;
|
|
74
74
|
export const Snapshotter = mod.Snapshotter;
|
|
75
75
|
export const StagehandCrawler = mod.StagehandCrawler;
|
|
76
|
+
export const StateValidationError = mod.StateValidationError;
|
|
76
77
|
export const Statistics = mod.Statistics;
|
|
78
|
+
export const StorageBackendLoadSignal = mod.StorageBackendLoadSignal;
|
|
77
79
|
export const StorageInstanceManager = mod.StorageInstanceManager;
|
|
78
|
-
export const
|
|
80
|
+
export const StorageTransaction = mod.StorageTransaction;
|
|
79
81
|
export const SystemStatus = mod.SystemStatus;
|
|
82
|
+
export const ThrottlingRequestManager = mod.ThrottlingRequestManager;
|
|
83
|
+
export const activeStorageTransaction = mod.activeStorageTransaction;
|
|
80
84
|
export const applyRequestTransform = mod.applyRequestTransform;
|
|
81
85
|
export const assertJsonSerializable = mod.assertJsonSerializable;
|
|
82
86
|
export const bindMethodsToServiceLocator = mod.bindMethodsToServiceLocator;
|
|
83
|
-
export const browserCrawlerEnqueueLinks = mod.browserCrawlerEnqueueLinks;
|
|
84
87
|
export const browserPoolCookieToToughCookie = mod.browserPoolCookieToToughCookie;
|
|
85
|
-
export const
|
|
88
|
+
export const buildEnqueueStrategyPatterns = mod.buildEnqueueStrategyPatterns;
|
|
86
89
|
export const coerceBoolean = mod.coerceBoolean;
|
|
87
90
|
export const coerceNumber = mod.coerceNumber;
|
|
88
91
|
export const constructGlobObjectsFromGlobs = mod.constructGlobObjectsFromGlobs;
|
|
89
|
-
export const constructRegExpObjectsFromPseudoUrls = mod.constructRegExpObjectsFromPseudoUrls;
|
|
90
92
|
export const constructRegExpObjectsFromRegExps = mod.constructRegExpObjectsFromRegExps;
|
|
93
|
+
export const constructUrlPatternObjects = mod.constructUrlPatternObjects;
|
|
94
|
+
export const convertStateSync = mod.convertStateSync;
|
|
91
95
|
export const cookieStringToToughCookie = mod.cookieStringToToughCookie;
|
|
92
96
|
export const crawleeConfigFields = mod.crawleeConfigFields;
|
|
93
97
|
export const createBasicRouter = mod.createBasicRouter;
|
|
@@ -95,10 +99,12 @@ export const createDeserialize = mod.createDeserialize;
|
|
|
95
99
|
export const createDualIterable = mod.createDualIterable;
|
|
96
100
|
export const createRequestDebugInfo = mod.createRequestDebugInfo;
|
|
97
101
|
export const createRequestOptions = mod.createRequestOptions;
|
|
102
|
+
export const createSkippedRequestArgs = mod.createSkippedRequestArgs;
|
|
98
103
|
export const createStagehandRouter = mod.createStagehandRouter;
|
|
104
|
+
export const createStorageTransaction = mod.createStorageTransaction;
|
|
105
|
+
export const currentStorageTransaction = mod.currentStorageTransaction;
|
|
99
106
|
export const defaultRoute = mod.defaultRoute;
|
|
100
107
|
export const deserializeArray = mod.deserializeArray;
|
|
101
|
-
export const enqueueLinks = mod.enqueueLinks;
|
|
102
108
|
export const evaluateLoadSignalSample = mod.evaluateLoadSignalSample;
|
|
103
109
|
export const extractUrlsFromPage = mod.extractUrlsFromPage;
|
|
104
110
|
export const field = mod.field;
|
|
@@ -111,20 +117,25 @@ export const inspectValue = mod.inspectValue;
|
|
|
111
117
|
export const log = mod.log;
|
|
112
118
|
export const mergeCookies = mod.mergeCookies;
|
|
113
119
|
export const navigationDeadlineKey = mod.navigationDeadlineKey;
|
|
120
|
+
export const operationRejectedInTransaction = mod.operationRejectedInTransaction;
|
|
121
|
+
export const parseRetryAfterHeader = mod.parseRetryAfterHeader;
|
|
114
122
|
export const parseValue = mod.parseValue;
|
|
115
123
|
export const purgeDefaultStorages = mod.purgeDefaultStorages;
|
|
124
|
+
export const rejectOperationInTransaction = mod.rejectOperationInTransaction;
|
|
116
125
|
export const remainingNavigationWindowMillis = mod.remainingNavigationWindowMillis;
|
|
126
|
+
export const remoteStagehandBrowserPool = mod.remoteStagehandBrowserPool;
|
|
117
127
|
export const resolveBaseUrlForEnqueueLinksFiltering = mod.resolveBaseUrlForEnqueueLinksFiltering;
|
|
118
|
-
export const resolveStorageIdentifier = mod.resolveStorageIdentifier;
|
|
119
128
|
export const serializeArray = mod.serializeArray;
|
|
120
129
|
export const serializeValue = mod.serializeValue;
|
|
121
130
|
export const serviceLocator = mod.serviceLocator;
|
|
122
|
-
export const
|
|
131
|
+
export const snapshotValue = mod.snapshotValue;
|
|
132
|
+
export const stagehandBrowserPool = mod.stagehandBrowserPool;
|
|
123
133
|
export const toughCookieToBrowserPoolCookie = mod.toughCookieToBrowserPoolCookie;
|
|
124
|
-
export const tryAbsoluteURL = mod.tryAbsoluteURL;
|
|
125
134
|
export const updateEnqueueLinksPatternCache = mod.updateEnqueueLinksPatternCache;
|
|
135
|
+
export const urlPatternSchema = mod.urlPatternSchema;
|
|
126
136
|
export const useState = mod.useState;
|
|
127
137
|
export const validateGlobPattern = mod.validateGlobPattern;
|
|
128
138
|
export const validateUserData = mod.validateUserData;
|
|
129
139
|
export const validators = mod.validators;
|
|
130
|
-
export const
|
|
140
|
+
export const withDirectStorageAccess = mod.withDirectStorageAccess;
|
|
141
|
+
export const withStorageTransaction = mod.withStorageTransaction;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { Configuration } from '@crawlee/browser';
|
|
2
|
+
import type { BrowserPool, BrowserPoolHooks, BrowserPoolOptions, RemoteBrowserPool, RemoteBrowserPoolOptions } from '@crawlee/browser-pool';
|
|
3
|
+
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
4
|
+
import type { Page } from 'playwright';
|
|
5
|
+
import type { StagehandOptions } from './stagehand-crawler';
|
|
6
|
+
import type { StagehandLaunchContext } from './stagehand-launcher';
|
|
7
|
+
import type { StagehandPlugin } from './stagehand-plugin';
|
|
8
|
+
/** A {@link BrowserPool} of Stagehand browsers, as built by {@link stagehandBrowserPool}. */
|
|
9
|
+
export type StagehandBrowserPool = BrowserPool<{
|
|
10
|
+
browserPlugins: [StagehandPlugin];
|
|
11
|
+
}, [StagehandPlugin]>;
|
|
12
|
+
export interface StagehandBrowserPoolOptions extends Omit<BrowserPoolOptions, 'browserPlugins'>, BrowserPoolHooks<ReturnType<StagehandPlugin['createController']>, ReturnType<StagehandPlugin['createLaunchContext']>, Page> {
|
|
13
|
+
/** How to launch the browser: which Playwright browser type, proxy, user data dir, ... */
|
|
14
|
+
launchContext?: StagehandLaunchContext;
|
|
15
|
+
/** Stagehand configuration for the AI behavior and Browserbase integration. */
|
|
16
|
+
stagehandOptions?: StagehandOptions;
|
|
17
|
+
/**
|
|
18
|
+
* Whether to run the browser in headless mode. Shorthand for `launchContext.launchOptions.headless`.
|
|
19
|
+
* Defaults to `true`, and can also be set via {@link Configuration}.
|
|
20
|
+
*/
|
|
21
|
+
headless?: boolean;
|
|
22
|
+
/** Configuration to read the browser defaults from. Defaults to the global configuration. */
|
|
23
|
+
configuration?: Configuration;
|
|
24
|
+
}
|
|
25
|
+
export interface RemoteStagehandBrowserPoolOptions extends Pick<StagehandBrowserPoolOptions, 'launchContext' | 'stagehandOptions' | 'headless' | 'configuration'>, Omit<RemoteBrowserPoolOptions, 'browserPlugins'> {
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Builds a {@link BrowserPool} of Stagehand browsers to pass to a {@link StagehandCrawler} as its
|
|
29
|
+
* {@link BrowserCrawlerOptions.browserPool|`browserPool`}.
|
|
30
|
+
*
|
|
31
|
+
* It accepts every {@link BrowserPoolOptions|`BrowserPool` option} plus the crawler's own `launchContext`,
|
|
32
|
+
* `stagehandOptions` and `headless`, and derives the browser plugin from them - so a pool built here always
|
|
33
|
+
* matches the crawler it is given to, and configuring one never means assembling a {@link StagehandPlugin}
|
|
34
|
+
* by hand.
|
|
35
|
+
*
|
|
36
|
+
* **Example usage:**
|
|
37
|
+
*
|
|
38
|
+
* ```javascript
|
|
39
|
+
* const crawler = new StagehandCrawler({
|
|
40
|
+
* browserPool: stagehandBrowserPool({
|
|
41
|
+
* maxOpenPagesPerBrowser: 1,
|
|
42
|
+
* stagehandOptions: { env: 'LOCAL', model: 'openai/gpt-4.1-mini' },
|
|
43
|
+
* }),
|
|
44
|
+
* requestHandler: async ({ page }) => { ... },
|
|
45
|
+
* });
|
|
46
|
+
* ```
|
|
47
|
+
*
|
|
48
|
+
* The returned pool is *not* torn down by the crawler, which is what makes it shareable between crawlers.
|
|
49
|
+
*
|
|
50
|
+
* @category Browser management
|
|
51
|
+
*/
|
|
52
|
+
export declare function stagehandBrowserPool(options?: StagehandBrowserPoolOptions): StagehandBrowserPool;
|
|
53
|
+
/**
|
|
54
|
+
* The {@link RemoteBrowserPool} counterpart of {@link stagehandBrowserPool}: connects to a remote browser
|
|
55
|
+
* service with a Stagehand plugin derived from `launchContext` and `stagehandOptions`.
|
|
56
|
+
*
|
|
57
|
+
* A {@link StagehandCrawler} accepts the same connection details directly via
|
|
58
|
+
* {@link BrowserCrawlerOptions.remoteBrowser|`remoteBrowser`}; reach for this factory when you also need to
|
|
59
|
+
* tune the wrapping pool, or to share one remote pool between crawlers.
|
|
60
|
+
*
|
|
61
|
+
* @category Browser management
|
|
62
|
+
*/
|
|
63
|
+
export declare function remoteStagehandBrowserPool(options: RemoteStagehandBrowserPoolOptions): RemoteBrowserPool<Page>;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.stagehandBrowserPool = stagehandBrowserPool;
|
|
4
|
+
exports.remoteStagehandBrowserPool = remoteStagehandBrowserPool;
|
|
5
|
+
const stagehand_launcher_1 = require("./stagehand-launcher");
|
|
6
|
+
/**
|
|
7
|
+
* Builds a {@link BrowserPool} of Stagehand browsers to pass to a {@link StagehandCrawler} as its
|
|
8
|
+
* {@link BrowserCrawlerOptions.browserPool|`browserPool`}.
|
|
9
|
+
*
|
|
10
|
+
* It accepts every {@link BrowserPoolOptions|`BrowserPool` option} plus the crawler's own `launchContext`,
|
|
11
|
+
* `stagehandOptions` and `headless`, and derives the browser plugin from them - so a pool built here always
|
|
12
|
+
* matches the crawler it is given to, and configuring one never means assembling a {@link StagehandPlugin}
|
|
13
|
+
* by hand.
|
|
14
|
+
*
|
|
15
|
+
* **Example usage:**
|
|
16
|
+
*
|
|
17
|
+
* ```javascript
|
|
18
|
+
* const crawler = new StagehandCrawler({
|
|
19
|
+
* browserPool: stagehandBrowserPool({
|
|
20
|
+
* maxOpenPagesPerBrowser: 1,
|
|
21
|
+
* stagehandOptions: { env: 'LOCAL', model: 'openai/gpt-4.1-mini' },
|
|
22
|
+
* }),
|
|
23
|
+
* requestHandler: async ({ page }) => { ... },
|
|
24
|
+
* });
|
|
25
|
+
* ```
|
|
26
|
+
*
|
|
27
|
+
* The returned pool is *not* torn down by the crawler, which is what makes it shareable between crawlers.
|
|
28
|
+
*
|
|
29
|
+
* @category Browser management
|
|
30
|
+
*/
|
|
31
|
+
function stagehandBrowserPool(options = {}) {
|
|
32
|
+
const { launchContext, stagehandOptions, headless, configuration, ...poolOptions } = options;
|
|
33
|
+
return stagehandLauncher(launchContext, stagehandOptions, headless, configuration).createBrowserPool(poolOptions);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* The {@link RemoteBrowserPool} counterpart of {@link stagehandBrowserPool}: connects to a remote browser
|
|
37
|
+
* service with a Stagehand plugin derived from `launchContext` and `stagehandOptions`.
|
|
38
|
+
*
|
|
39
|
+
* A {@link StagehandCrawler} accepts the same connection details directly via
|
|
40
|
+
* {@link BrowserCrawlerOptions.remoteBrowser|`remoteBrowser`}; reach for this factory when you also need to
|
|
41
|
+
* tune the wrapping pool, or to share one remote pool between crawlers.
|
|
42
|
+
*
|
|
43
|
+
* @category Browser management
|
|
44
|
+
*/
|
|
45
|
+
function remoteStagehandBrowserPool(options) {
|
|
46
|
+
const { launchContext, stagehandOptions, headless, configuration, ...remoteOptions } = options;
|
|
47
|
+
return stagehandLauncher(launchContext, stagehandOptions, headless, configuration).createRemoteBrowserPool(remoteOptions);
|
|
48
|
+
}
|
|
49
|
+
function stagehandLauncher(launchContext = {}, stagehandOptions = {}, headless, configuration) {
|
|
50
|
+
return new stagehand_launcher_1.StagehandLauncher({
|
|
51
|
+
...launchContext,
|
|
52
|
+
stagehandOptions,
|
|
53
|
+
...(headless == null ? {} : { launchOptions: { ...launchContext.launchOptions, headless } }),
|
|
54
|
+
}, configuration);
|
|
55
|
+
}
|
|
@@ -18,8 +18,7 @@ import type { StagehandPlugin } from './stagehand-plugin';
|
|
|
18
18
|
* @ignore
|
|
19
19
|
*/
|
|
20
20
|
export declare class StagehandController extends BrowserController<BrowserType, LaunchOptions, PlaywrightBrowser> {
|
|
21
|
-
private
|
|
22
|
-
private readonly stagehandInstances;
|
|
21
|
+
#private;
|
|
23
22
|
constructor(browserPlugin: StagehandPlugin, stagehandInstances: WeakMap<PlaywrightBrowser, Stagehand>);
|
|
24
23
|
/**
|
|
25
24
|
* Gets the Stagehand instance associated with this controller's browser.
|
|
@@ -30,20 +29,6 @@ export declare class StagehandController extends BrowserController<BrowserType,
|
|
|
30
29
|
* We use Playwright's browser API directly since we connected via CDP.
|
|
31
30
|
*/
|
|
32
31
|
protected _newPage(_contextOptions?: unknown): Promise<Page>;
|
|
33
|
-
/**
|
|
34
|
-
* Waits until Stagehand knows about the page, so that `act()`/`extract()`/`observe()` can resolve it.
|
|
35
|
-
*
|
|
36
|
-
* Stagehand only learns about pages from CDP `Target.attachedToTarget` events on its own connection,
|
|
37
|
-
* and it maps them by main frame id. We create pages through a separate `connectOverCDP()` handle, so
|
|
38
|
-
* `context.newPage()` resolves before Stagehand has processed that event — the page is unresolvable for
|
|
39
|
-
* a short window, and the AI methods fail with 'Failed to resolve V3 Page from Playwright page'.
|
|
40
|
-
* Stagehand's own `newPage()` polls for the same reason.
|
|
41
|
-
*/
|
|
42
|
-
private waitForStagehandToRegisterPage;
|
|
43
|
-
/**
|
|
44
|
-
* Reads the page's main frame id, which is the key Stagehand resolves pages by.
|
|
45
|
-
*/
|
|
46
|
-
private getMainFrameId;
|
|
47
32
|
/**
|
|
48
33
|
* Normalizes proxy options for Playwright.
|
|
49
34
|
*/
|
|
@@ -18,23 +18,23 @@ const utils_1 = require("@crawlee/utils");
|
|
|
18
18
|
* @ignore
|
|
19
19
|
*/
|
|
20
20
|
class StagehandController extends browser_pool_1.BrowserController {
|
|
21
|
-
stagehand = null;
|
|
22
|
-
stagehandInstances;
|
|
21
|
+
#stagehand = null;
|
|
22
|
+
#stagehandInstances;
|
|
23
23
|
constructor(browserPlugin, stagehandInstances) {
|
|
24
24
|
super(browserPlugin);
|
|
25
|
-
this
|
|
25
|
+
this.#stagehandInstances = stagehandInstances;
|
|
26
26
|
}
|
|
27
27
|
/**
|
|
28
28
|
* Gets the Stagehand instance associated with this controller's browser.
|
|
29
29
|
*/
|
|
30
30
|
getStagehand() {
|
|
31
|
-
if (!this
|
|
32
|
-
this
|
|
33
|
-
if (!this
|
|
31
|
+
if (!this.#stagehand) {
|
|
32
|
+
this.#stagehand = this.#stagehandInstances.get(this.browser);
|
|
33
|
+
if (!this.#stagehand) {
|
|
34
34
|
throw new Error('Stagehand instance not found for browser');
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
|
-
return this
|
|
37
|
+
return this.#stagehand;
|
|
38
38
|
}
|
|
39
39
|
/**
|
|
40
40
|
* Creates a new page using the browser's default context.
|
|
@@ -51,10 +51,10 @@ class StagehandController extends browser_pool_1.BrowserController {
|
|
|
51
51
|
const page = await context.newPage();
|
|
52
52
|
// Track active pages
|
|
53
53
|
page.once('close', () => {
|
|
54
|
-
this.
|
|
54
|
+
this.registerPageClosed(page);
|
|
55
55
|
});
|
|
56
56
|
try {
|
|
57
|
-
await this
|
|
57
|
+
await this.#waitForStagehandToRegisterPage(page);
|
|
58
58
|
}
|
|
59
59
|
catch (error) {
|
|
60
60
|
await page.close().catch(() => { });
|
|
@@ -77,9 +77,9 @@ class StagehandController extends browser_pool_1.BrowserController {
|
|
|
77
77
|
* a short window, and the AI methods fail with 'Failed to resolve V3 Page from Playwright page'.
|
|
78
78
|
* Stagehand's own `newPage()` polls for the same reason.
|
|
79
79
|
*/
|
|
80
|
-
async waitForStagehandToRegisterPage(page, timeoutMs = 10_000) {
|
|
80
|
+
async #waitForStagehandToRegisterPage(page, timeoutMs = 10_000) {
|
|
81
81
|
const stagehand = this.getStagehand();
|
|
82
|
-
const mainFrameId = await this
|
|
82
|
+
const mainFrameId = await this.#getMainFrameId(page);
|
|
83
83
|
const deadline = Date.now() + timeoutMs;
|
|
84
84
|
while (Date.now() < deadline) {
|
|
85
85
|
if (stagehand.context.resolvePageByMainFrameId(mainFrameId)) {
|
|
@@ -94,7 +94,7 @@ class StagehandController extends browser_pool_1.BrowserController {
|
|
|
94
94
|
/**
|
|
95
95
|
* Reads the page's main frame id, which is the key Stagehand resolves pages by.
|
|
96
96
|
*/
|
|
97
|
-
async getMainFrameId(page) {
|
|
97
|
+
async #getMainFrameId(page) {
|
|
98
98
|
const cdpSession = await page.context().newCDPSession(page);
|
|
99
99
|
try {
|
|
100
100
|
const { frameTree } = await cdpSession.send('Page.getFrameTree');
|