@crawlee/jsdom 4.0.0-beta.98 → 4.0.0-rc.0
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/internals/jsdom-crawler.d.ts +129 -118
- package/internals/jsdom-crawler.js +39 -63
- package/package.json +7 -7
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { AddRequestsBatchedResult, CrawlingContext, EnqueueLinksOptions, ErrorHandler, ExtractLinksOptions, GetUserDataFromRequest, HttpCrawlerOptions, InternalHttpCrawlingContext, InternalHttpHook, RequestHandler, RouterHandler, RouterRoutes, RouteSchemas, RoutesFromSchemas } from '@crawlee/http';
|
|
2
2
|
import { HttpCrawler } from '@crawlee/http';
|
|
3
3
|
import type { Dictionary } from '@crawlee/types';
|
|
4
|
-
import { type CheerioRoot
|
|
4
|
+
import { type CheerioRoot } from '@crawlee/utils/internal';
|
|
5
5
|
import type { DOMWindow } from 'jsdom';
|
|
6
6
|
import { VirtualConsole } from 'jsdom';
|
|
7
|
+
import { z } from 'zod';
|
|
7
8
|
export type JSDOMErrorHandler<UserData extends Dictionary = any, // with default to Dictionary we cant use a typed router in untyped crawler
|
|
8
9
|
JSONData extends Dictionary = any, // with default to Dictionary we cant use a typed router in untyped crawler
|
|
9
10
|
ContextExtension = Dictionary<never>> = ErrorHandler<CrawlingContext, JSDOMCrawlingContext<UserData, JSONData> & ContextExtension>;
|
|
10
11
|
export interface JSDOMCrawlerOptions<ContextExtension = Dictionary<never>, ExtendedContext extends JSDOMCrawlingContext = JSDOMCrawlingContext & ContextExtension, UserData extends Dictionary = any, // with default to Dictionary we cant use a typed router in untyped crawler
|
|
11
12
|
JSONData extends Dictionary = any, // with default to Dictionary we cant use a typed router in untyped crawler
|
|
12
|
-
Routes extends Record<keyof Routes, Dictionary> = Record<string, UserData
|
|
13
|
+
Routes extends Record<keyof Routes, Dictionary> = Record<string, UserData>, StatisticStateExtension extends object = {}> extends HttpCrawlerOptions<JSDOMCrawlingContext<UserData, JSONData>, ContextExtension, ExtendedContext, Routes, StatisticStateExtension> {
|
|
13
14
|
/**
|
|
14
15
|
* Download and run scripts.
|
|
15
16
|
*/
|
|
@@ -53,113 +54,142 @@ JSONData extends Dictionary = any> extends InternalHttpCrawlingContext<UserData,
|
|
|
53
54
|
* ```
|
|
54
55
|
*/
|
|
55
56
|
parseWithCheerio(selector?: string, timeoutMs?: number): Promise<CheerioRoot>;
|
|
57
|
+
/**
|
|
58
|
+
* Extracts URLs from the parsed DOM, without adding them to the request queue.
|
|
59
|
+
*/
|
|
60
|
+
extractLinks(options?: ExtractLinksOptions): Promise<string[]>;
|
|
61
|
+
/**
|
|
62
|
+
* Helper function for extracting URLs from the parsed DOM and adding them to the request queue.
|
|
63
|
+
*/
|
|
64
|
+
enqueueLinks(options?: EnqueueLinksOptions): Promise<AddRequestsBatchedResult>;
|
|
56
65
|
}
|
|
57
66
|
export type JSDOMRequestHandler<UserData extends Dictionary = any, // with default to Dictionary we cant use a typed router in untyped crawler
|
|
58
67
|
JSONData extends Dictionary = any> = RequestHandler<JSDOMCrawlingContext<UserData, JSONData>>;
|
|
59
|
-
export declare class JSDOMCrawler<ContextExtension = Dictionary<never>, ExtendedContext extends JSDOMCrawlingContext = JSDOMCrawlingContext & ContextExtension, Routes extends Record<keyof Routes, Dictionary> = Record<string, GetUserDataFromRequest<JSDOMCrawlingContext['request']
|
|
68
|
+
export declare class JSDOMCrawler<ContextExtension = Dictionary<never>, ExtendedContext extends JSDOMCrawlingContext = JSDOMCrawlingContext & ContextExtension, Routes extends Record<keyof Routes, Dictionary> = Record<string, GetUserDataFromRequest<JSDOMCrawlingContext['request']>>, StatisticStateExtension extends object = {}> extends HttpCrawler<JSDOMCrawlingContext, ContextExtension, ExtendedContext, Routes, StatisticStateExtension> {
|
|
69
|
+
#private;
|
|
60
70
|
protected static optionsShape: {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
statusMessageCallback: import("ow").Predicate<Function> & import("ow").BasePredicate<Function | undefined>;
|
|
117
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
118
|
-
additionalHttpErrorStatusCodes: import("ow").ArrayPredicate<number>;
|
|
119
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
120
|
-
ignoreHttpErrorStatusCodes: import("ow").ArrayPredicate<number>;
|
|
121
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
122
|
-
blockedStatusCodes: import("ow").ArrayPredicate<number>;
|
|
123
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
124
|
-
retryOnBlocked: import("ow").BooleanPredicate & import("ow").BasePredicate<boolean | undefined>;
|
|
125
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
126
|
-
respectRobotsTxtFile: import("ow").AnyPredicate<boolean | object>;
|
|
127
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
128
|
-
onSkippedRequest: import("ow").Predicate<Function> & import("ow").BasePredicate<Function | undefined>;
|
|
129
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
130
|
-
httpClient: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
|
|
131
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
132
|
-
configuration: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
|
|
133
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
134
|
-
storageBackend: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
|
|
135
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
136
|
-
eventManager: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
|
|
137
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
138
|
-
logger: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
|
|
139
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
140
|
-
minConcurrency: import("ow").NumberPredicate & import("ow").BasePredicate<number | undefined>;
|
|
141
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
142
|
-
maxConcurrency: import("ow").NumberPredicate & import("ow").BasePredicate<number | undefined>;
|
|
143
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
144
|
-
maxRequestsPerMinute: import("ow").NumberPredicate & import("ow").BasePredicate<number | undefined>;
|
|
145
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
146
|
-
keepAlive: import("ow").BooleanPredicate & import("ow").BasePredicate<boolean | undefined>;
|
|
147
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
148
|
-
statisticsOptions: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
|
|
149
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
150
|
-
id: import("ow").StringPredicate & import("ow").BasePredicate<string | undefined>;
|
|
71
|
+
runScripts: z.ZodOptional<z.ZodBoolean>;
|
|
72
|
+
hideInternalConsole: z.ZodOptional<z.ZodBoolean>;
|
|
73
|
+
navigationTimeoutSecs: z.ZodDefault<z.ZodCustom<number, number>>;
|
|
74
|
+
ignoreTlsErrors: z.ZodDefault<z.ZodBoolean>;
|
|
75
|
+
additionalMimeTypes: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
76
|
+
suggestResponseEncoding: z.ZodOptional<z.ZodString>;
|
|
77
|
+
forceResponseEncoding: z.ZodOptional<z.ZodString>;
|
|
78
|
+
saveResponseCookies: z.ZodDefault<z.ZodBoolean>;
|
|
79
|
+
preNavigationHooks: z.ZodDefault<z.ZodCustom<unknown[], unknown[]>>;
|
|
80
|
+
postNavigationHooks: z.ZodDefault<z.ZodCustom<unknown[], unknown[]>>;
|
|
81
|
+
contextPipelineBuilder: z.ZodOptional<z.ZodCustom<Dictionary, Dictionary>>;
|
|
82
|
+
extendContext: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
|
|
83
|
+
requestList: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
|
|
84
|
+
requestQueue: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
|
|
85
|
+
requestManager: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
|
|
86
|
+
requestHandler: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
|
|
87
|
+
requestHandlerTimeoutSecs: z.ZodOptional<z.ZodCustom<number, number>>;
|
|
88
|
+
errorHandler: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
|
|
89
|
+
failedRequestHandler: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
|
|
90
|
+
maxRequestRetries: z.ZodDefault<z.ZodCustom<number, number>>;
|
|
91
|
+
sameDomainDelaySecs: z.ZodDefault<z.ZodCustom<number, number>>;
|
|
92
|
+
maxRequestsPerCrawl: z.ZodOptional<z.ZodCustom<number, number>>;
|
|
93
|
+
maxCrawlDepth: z.ZodOptional<z.ZodCustom<number, number>>;
|
|
94
|
+
taskLoopOptions: z.ZodOptional<z.ZodCustom<Dictionary, Dictionary>>;
|
|
95
|
+
concurrencySystem: z.ZodOptional<z.ZodCustom<Dictionary, Dictionary>>;
|
|
96
|
+
sessionPool: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
|
|
97
|
+
proxyConfiguration: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
|
|
98
|
+
statusMessageLoggingInterval: z.ZodDefault<z.ZodCustom<number, number>>;
|
|
99
|
+
statusMessageCallback: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
|
|
100
|
+
additionalHttpErrorStatusCodes: z.ZodDefault<z.ZodArray<z.ZodCustom<number, number>>>;
|
|
101
|
+
ignoreHttpErrorStatusCodes: z.ZodDefault<z.ZodArray<z.ZodCustom<number, number>>>;
|
|
102
|
+
blockedStatusCodes: z.ZodOptional<z.ZodArray<z.ZodCustom<number, number>>>;
|
|
103
|
+
retryOnBlocked: z.ZodDefault<z.ZodBoolean>;
|
|
104
|
+
respectRobotsTxtFile: z.ZodDefault<z.ZodUnion<readonly [z.ZodBoolean, z.ZodCustom<Dictionary, Dictionary>]>>;
|
|
105
|
+
transactionalStorage: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodObject<{
|
|
106
|
+
requestQueue: z.ZodOptional<z.ZodEnum<{
|
|
107
|
+
deferred: "deferred";
|
|
108
|
+
writeThrough: "writeThrough";
|
|
109
|
+
}>>;
|
|
110
|
+
}, z.core.$strict>]>>;
|
|
111
|
+
onSkippedRequest: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
|
|
112
|
+
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
113
|
+
httpClient: z.ZodOptional<z.ZodCustom<import("@crawlee/http-client").BaseHttpClient, import("@crawlee/http-client").BaseHttpClient>>;
|
|
114
|
+
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
115
|
+
configuration: z.ZodOptional<z.ZodCustom<import("@crawlee/http").Configuration, import("@crawlee/http").Configuration>>;
|
|
116
|
+
storageBackend: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
|
|
117
|
+
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
118
|
+
eventManager: z.ZodOptional<z.ZodCustom<import("@crawlee/http").EventManager, import("@crawlee/http").EventManager>>;
|
|
119
|
+
logger: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
|
|
120
|
+
minConcurrency: z.ZodOptional<z.ZodCustom<number, number>>;
|
|
121
|
+
maxConcurrency: z.ZodOptional<z.ZodCustom<number, number>>;
|
|
122
|
+
maxRequestsPerMinute: z.ZodOptional<z.ZodCustom<number, number>>;
|
|
123
|
+
keepAlive: z.ZodOptional<z.ZodBoolean>;
|
|
124
|
+
statistics: z.ZodOptional<z.ZodCustom<Dictionary, Dictionary>>;
|
|
125
|
+
id: z.ZodOptional<z.ZodString>;
|
|
151
126
|
};
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
127
|
+
protected static optionsSchema: z.ZodObject<{
|
|
128
|
+
runScripts: z.ZodOptional<z.ZodBoolean>;
|
|
129
|
+
hideInternalConsole: z.ZodOptional<z.ZodBoolean>;
|
|
130
|
+
navigationTimeoutSecs: z.ZodDefault<z.ZodCustom<number, number>>;
|
|
131
|
+
ignoreTlsErrors: z.ZodDefault<z.ZodBoolean>;
|
|
132
|
+
additionalMimeTypes: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
133
|
+
suggestResponseEncoding: z.ZodOptional<z.ZodString>;
|
|
134
|
+
forceResponseEncoding: z.ZodOptional<z.ZodString>;
|
|
135
|
+
saveResponseCookies: z.ZodDefault<z.ZodBoolean>;
|
|
136
|
+
preNavigationHooks: z.ZodDefault<z.ZodCustom<unknown[], unknown[]>>;
|
|
137
|
+
postNavigationHooks: z.ZodDefault<z.ZodCustom<unknown[], unknown[]>>;
|
|
138
|
+
contextPipelineBuilder: z.ZodOptional<z.ZodCustom<Dictionary, Dictionary>>;
|
|
139
|
+
extendContext: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
|
|
140
|
+
requestList: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
|
|
141
|
+
requestQueue: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
|
|
142
|
+
requestManager: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
|
|
143
|
+
requestHandler: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
|
|
144
|
+
requestHandlerTimeoutSecs: z.ZodOptional<z.ZodCustom<number, number>>;
|
|
145
|
+
errorHandler: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
|
|
146
|
+
failedRequestHandler: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
|
|
147
|
+
maxRequestRetries: z.ZodDefault<z.ZodCustom<number, number>>;
|
|
148
|
+
sameDomainDelaySecs: z.ZodDefault<z.ZodCustom<number, number>>;
|
|
149
|
+
maxRequestsPerCrawl: z.ZodOptional<z.ZodCustom<number, number>>;
|
|
150
|
+
maxCrawlDepth: z.ZodOptional<z.ZodCustom<number, number>>;
|
|
151
|
+
taskLoopOptions: z.ZodOptional<z.ZodCustom<Dictionary, Dictionary>>;
|
|
152
|
+
concurrencySystem: z.ZodOptional<z.ZodCustom<Dictionary, Dictionary>>;
|
|
153
|
+
sessionPool: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
|
|
154
|
+
proxyConfiguration: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
|
|
155
|
+
statusMessageLoggingInterval: z.ZodDefault<z.ZodCustom<number, number>>;
|
|
156
|
+
statusMessageCallback: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
|
|
157
|
+
additionalHttpErrorStatusCodes: z.ZodDefault<z.ZodArray<z.ZodCustom<number, number>>>;
|
|
158
|
+
ignoreHttpErrorStatusCodes: z.ZodDefault<z.ZodArray<z.ZodCustom<number, number>>>;
|
|
159
|
+
blockedStatusCodes: z.ZodOptional<z.ZodArray<z.ZodCustom<number, number>>>;
|
|
160
|
+
retryOnBlocked: z.ZodDefault<z.ZodBoolean>;
|
|
161
|
+
respectRobotsTxtFile: z.ZodDefault<z.ZodUnion<readonly [z.ZodBoolean, z.ZodCustom<Dictionary, Dictionary>]>>;
|
|
162
|
+
transactionalStorage: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodObject<{
|
|
163
|
+
requestQueue: z.ZodOptional<z.ZodEnum<{
|
|
164
|
+
deferred: "deferred";
|
|
165
|
+
writeThrough: "writeThrough";
|
|
166
|
+
}>>;
|
|
167
|
+
}, z.core.$strict>]>>;
|
|
168
|
+
onSkippedRequest: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
|
|
169
|
+
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
170
|
+
httpClient: z.ZodOptional<z.ZodCustom<import("@crawlee/http-client").BaseHttpClient, import("@crawlee/http-client").BaseHttpClient>>;
|
|
171
|
+
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
172
|
+
configuration: z.ZodOptional<z.ZodCustom<import("@crawlee/http").Configuration, import("@crawlee/http").Configuration>>;
|
|
173
|
+
storageBackend: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
|
|
174
|
+
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
175
|
+
eventManager: z.ZodOptional<z.ZodCustom<import("@crawlee/http").EventManager, import("@crawlee/http").EventManager>>;
|
|
176
|
+
logger: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
|
|
177
|
+
minConcurrency: z.ZodOptional<z.ZodCustom<number, number>>;
|
|
178
|
+
maxConcurrency: z.ZodOptional<z.ZodCustom<number, number>>;
|
|
179
|
+
maxRequestsPerMinute: z.ZodOptional<z.ZodCustom<number, number>>;
|
|
180
|
+
keepAlive: z.ZodOptional<z.ZodBoolean>;
|
|
181
|
+
statistics: z.ZodOptional<z.ZodCustom<Dictionary, Dictionary>>;
|
|
182
|
+
id: z.ZodOptional<z.ZodString>;
|
|
183
|
+
}, z.core.$strict>;
|
|
184
|
+
constructor(options?: JSDOMCrawlerOptions<ContextExtension, ExtendedContext, any, any, Routes, StatisticStateExtension>);
|
|
156
185
|
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
157
186
|
protected buildContextPipeline(): import("@crawlee/http").ContextPipeline<CrawlingContext<Dictionary>, InternalHttpCrawlingContext<any, any> & {
|
|
158
187
|
readonly window: DOMWindow;
|
|
159
188
|
readonly body: string;
|
|
160
189
|
readonly document: Document;
|
|
161
190
|
} & {
|
|
162
|
-
|
|
191
|
+
extractLinks: (options?: ExtractLinksOptions) => Promise<string[]>;
|
|
192
|
+
enqueueLinks: (options?: EnqueueLinksOptions) => Promise<AddRequestsBatchedResult>;
|
|
163
193
|
waitForSelector(selector: string, timeoutMs?: number): Promise<void>;
|
|
164
194
|
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
165
195
|
parseWithCheerio(selector?: string, _timeoutMs?: number): Promise<import("cheerio").CheerioAPI>;
|
|
@@ -183,24 +213,6 @@ export declare class JSDOMCrawler<ContextExtension = Dictionary<never>, Extended
|
|
|
183
213
|
private parseContent;
|
|
184
214
|
private addHelpers;
|
|
185
215
|
}
|
|
186
|
-
interface EnqueueLinksInternalOptions {
|
|
187
|
-
options?: EnqueueLinksOptions;
|
|
188
|
-
window: DOMWindow | null;
|
|
189
|
-
requestManager: IRequestManager;
|
|
190
|
-
robotsTxtFile?: RobotsTxtFile;
|
|
191
|
-
onSkippedRequest?: SkippedRequestCallback;
|
|
192
|
-
originalRequestUrl: string;
|
|
193
|
-
finalRequestUrl?: string;
|
|
194
|
-
}
|
|
195
|
-
interface BoundEnqueueLinksInternalOptions {
|
|
196
|
-
enqueueLinks: BasicCrawlingContext['enqueueLinks'];
|
|
197
|
-
options?: EnqueueLinksOptions;
|
|
198
|
-
window: DOMWindow | null;
|
|
199
|
-
originalRequestUrl: string;
|
|
200
|
-
finalRequestUrl?: string;
|
|
201
|
-
}
|
|
202
|
-
/** @internal */
|
|
203
|
-
export declare function domCrawlerEnqueueLinks(options: EnqueueLinksInternalOptions | BoundEnqueueLinksInternalOptions): Promise<unknown>;
|
|
204
216
|
/**
|
|
205
217
|
* Creates new {@link Router} instance that works based on request labels.
|
|
206
218
|
* This instance can then serve as a `requestHandler` of your {@link JSDOMCrawler}.
|
|
@@ -228,4 +240,3 @@ export declare function domCrawlerEnqueueLinks(options: EnqueueLinksInternalOpti
|
|
|
228
240
|
export declare function createJSDOMRouter<Context extends JSDOMCrawlingContext = JSDOMCrawlingContext, Routes extends Record<keyof Routes, Dictionary> = Record<string, GetUserDataFromRequest<Context['request']>>>(routes?: RouterRoutes<Context, Routes>): RouterHandler<Context, Routes>;
|
|
229
241
|
export declare function createJSDOMRouter<Context extends JSDOMCrawlingContext = JSDOMCrawlingContext, UserData extends Dictionary = GetUserDataFromRequest<Context['request']>>(routes?: RouterRoutes<Context, Record<string, UserData>>): RouterHandler<Context, Record<string, UserData>>;
|
|
230
242
|
export declare function createJSDOMRouter<Context extends JSDOMCrawlingContext = JSDOMCrawlingContext, const Schemas extends RouteSchemas = RouteSchemas>(schemas: Schemas): RouterHandler<Context, RoutesFromSchemas<Schemas>>;
|
|
231
|
-
export {};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { EnqueueStrategy, HttpCrawler, NavigationSkippedError, parseArgument, resolveBaseUrlForEnqueueLinksFiltering, Router, tryAbsoluteURL, } from '@crawlee/http';
|
|
2
2
|
import { sleep } from '@crawlee/utils';
|
|
3
3
|
import { JSDOM, ResourceLoader, VirtualConsole } from 'jsdom';
|
|
4
|
-
import
|
|
4
|
+
import { z } from 'zod';
|
|
5
5
|
import { addTimeoutToPromise } from '@apify/timeout';
|
|
6
6
|
/**
|
|
7
7
|
* Provides a framework for the parallel crawling of web pages using plain HTTP requests and
|
|
@@ -86,20 +86,21 @@ const resources = new ResourceLoader({
|
|
|
86
86
|
export class JSDOMCrawler extends HttpCrawler {
|
|
87
87
|
static optionsShape = {
|
|
88
88
|
...HttpCrawler.optionsShape,
|
|
89
|
-
runScripts:
|
|
90
|
-
hideInternalConsole:
|
|
89
|
+
runScripts: z.boolean().optional(),
|
|
90
|
+
hideInternalConsole: z.boolean().optional(),
|
|
91
91
|
};
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
92
|
+
static optionsSchema = z.strictObject(JSDOMCrawler.optionsShape);
|
|
93
|
+
#runScripts;
|
|
94
|
+
#hideInternalConsole;
|
|
95
|
+
#virtualConsole = null;
|
|
95
96
|
constructor(options = {}) {
|
|
96
|
-
const { runScripts = false, hideInternalConsole = false, contextPipelineBuilder, ...httpOptions } = options;
|
|
97
|
+
const { runScripts = false, hideInternalConsole = false, contextPipelineBuilder, ...httpOptions } = parseArgument(options, JSDOMCrawler.optionsSchema, 'JSDOMCrawlerOptions');
|
|
97
98
|
super({
|
|
98
99
|
...httpOptions,
|
|
99
100
|
contextPipelineBuilder: contextPipelineBuilder ?? (() => this.buildContextPipeline()),
|
|
100
101
|
});
|
|
101
|
-
this
|
|
102
|
-
this
|
|
102
|
+
this.#runScripts = runScripts;
|
|
103
|
+
this.#hideInternalConsole = hideInternalConsole;
|
|
103
104
|
}
|
|
104
105
|
buildContextPipeline() {
|
|
105
106
|
return super
|
|
@@ -128,15 +129,15 @@ export class JSDOMCrawler extends HttpCrawler {
|
|
|
128
129
|
* ```
|
|
129
130
|
*/
|
|
130
131
|
getVirtualConsole() {
|
|
131
|
-
if (this
|
|
132
|
-
return this
|
|
132
|
+
if (this.#virtualConsole) {
|
|
133
|
+
return this.#virtualConsole;
|
|
133
134
|
}
|
|
134
|
-
this
|
|
135
|
-
if (!this
|
|
136
|
-
this
|
|
135
|
+
this.#virtualConsole = new VirtualConsole();
|
|
136
|
+
if (!this.#hideInternalConsole) {
|
|
137
|
+
this.#virtualConsole.sendTo(console, { omitJSDOMErrors: true });
|
|
137
138
|
}
|
|
138
|
-
this
|
|
139
|
-
return this
|
|
139
|
+
this.#virtualConsole.on('jsdomError', this.jsdomErrorHandler);
|
|
140
|
+
return this.#virtualConsole;
|
|
140
141
|
}
|
|
141
142
|
jsdomErrorHandler = (error) => this.log.debug('JSDOM error from console', { error });
|
|
142
143
|
async parseContent(crawlingContext) {
|
|
@@ -146,7 +147,7 @@ export class JSDOMCrawler extends HttpCrawler {
|
|
|
146
147
|
const { window } = new JSDOM(crawlingContext.body.toString(), {
|
|
147
148
|
url: crawlingContext.response.url,
|
|
148
149
|
contentType: isXml ? 'text/xml' : 'text/html',
|
|
149
|
-
runScripts: this
|
|
150
|
+
runScripts: this.#runScripts ? 'dangerously' : undefined,
|
|
150
151
|
resources,
|
|
151
152
|
virtualConsole: this.getVirtualConsole(),
|
|
152
153
|
pretendToBeVisual: true,
|
|
@@ -171,7 +172,7 @@ export class JSDOMCrawler extends HttpCrawler {
|
|
|
171
172
|
range.getClientRects = () => ({ item: () => null, length: 0 });
|
|
172
173
|
return range;
|
|
173
174
|
};
|
|
174
|
-
if (this
|
|
175
|
+
if (this.#runScripts) {
|
|
175
176
|
try {
|
|
176
177
|
await addTimeoutToPromise(async () => {
|
|
177
178
|
return new Promise((resolve) => {
|
|
@@ -213,19 +214,27 @@ export class JSDOMCrawler extends HttpCrawler {
|
|
|
213
214
|
}
|
|
214
215
|
}
|
|
215
216
|
async addHelpers(crawlingContext) {
|
|
217
|
+
const addRequests = crawlingContext.addRequests;
|
|
218
|
+
const extractLinks = async (options) => {
|
|
219
|
+
if (!crawlingContext.window) {
|
|
220
|
+
throw new Error('Cannot extract links because the JSDOM is not available.');
|
|
221
|
+
}
|
|
222
|
+
return extractUrlsFromWindow(crawlingContext.window, options?.selector ?? 'a', options?.baseUrl ?? crawlingContext.request.loadedUrl ?? crawlingContext.request.url);
|
|
223
|
+
};
|
|
216
224
|
return {
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
limit: await this.calculateEnqueuedRequestLimit(enqueueOptions?.limit),
|
|
222
|
-
},
|
|
223
|
-
window: crawlingContext.window,
|
|
224
|
-
requestManager: await this.getRequestManager(),
|
|
225
|
-
robotsTxtFile: await this.getRobotsTxtFileForUrl(crawlingContext.request.url),
|
|
226
|
-
onSkippedRequest: this.handleSkippedRequest,
|
|
227
|
-
originalRequestUrl: crawlingContext.request.url,
|
|
225
|
+
extractLinks,
|
|
226
|
+
enqueueLinks: async (options = {}) => {
|
|
227
|
+
const baseUrl = resolveBaseUrlForEnqueueLinksFiltering({
|
|
228
|
+
enqueueStrategy: options.strategy,
|
|
228
229
|
finalRequestUrl: crawlingContext.request.loadedUrl,
|
|
230
|
+
originalRequestUrl: crawlingContext.request.url,
|
|
231
|
+
userProvidedBaseUrl: options.baseUrl,
|
|
232
|
+
});
|
|
233
|
+
const urls = await extractLinks(options);
|
|
234
|
+
return addRequests(urls, {
|
|
235
|
+
...options,
|
|
236
|
+
baseUrl,
|
|
237
|
+
strategy: options.strategy ?? EnqueueStrategy.SameHostname,
|
|
229
238
|
});
|
|
230
239
|
},
|
|
231
240
|
async waitForSelector(selector, timeoutMs = 5_000) {
|
|
@@ -251,39 +260,6 @@ export class JSDOMCrawler extends HttpCrawler {
|
|
|
251
260
|
};
|
|
252
261
|
}
|
|
253
262
|
}
|
|
254
|
-
/** @internal */
|
|
255
|
-
function containsEnqueueLinks(options) {
|
|
256
|
-
return !!options.enqueueLinks;
|
|
257
|
-
}
|
|
258
|
-
/** @internal */
|
|
259
|
-
export async function domCrawlerEnqueueLinks(options) {
|
|
260
|
-
const { options: enqueueLinksOptions, window, originalRequestUrl, finalRequestUrl } = options;
|
|
261
|
-
if (!window) {
|
|
262
|
-
throw new Error('Cannot enqueue links because the JSDOM is not available.');
|
|
263
|
-
}
|
|
264
|
-
const baseUrl = resolveBaseUrlForEnqueueLinksFiltering({
|
|
265
|
-
enqueueStrategy: enqueueLinksOptions?.strategy,
|
|
266
|
-
finalRequestUrl,
|
|
267
|
-
originalRequestUrl,
|
|
268
|
-
userProvidedBaseUrl: enqueueLinksOptions?.baseUrl,
|
|
269
|
-
});
|
|
270
|
-
const urls = extractUrlsFromWindow(window, enqueueLinksOptions?.selector ?? 'a', enqueueLinksOptions?.baseUrl ?? finalRequestUrl ?? originalRequestUrl);
|
|
271
|
-
if (containsEnqueueLinks(options)) {
|
|
272
|
-
return options.enqueueLinks({
|
|
273
|
-
urls,
|
|
274
|
-
baseUrl,
|
|
275
|
-
...enqueueLinksOptions,
|
|
276
|
-
});
|
|
277
|
-
}
|
|
278
|
-
return enqueueLinks({
|
|
279
|
-
requestManager: options.requestManager,
|
|
280
|
-
robotsTxtFile: options.robotsTxtFile,
|
|
281
|
-
onSkippedRequest: options.onSkippedRequest,
|
|
282
|
-
urls,
|
|
283
|
-
baseUrl,
|
|
284
|
-
...enqueueLinksOptions,
|
|
285
|
-
});
|
|
286
|
-
}
|
|
287
263
|
/**
|
|
288
264
|
* Extracts URLs from a given Window object.
|
|
289
265
|
* @ignore
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crawlee/jsdom",
|
|
3
|
-
"version": "4.0.0-
|
|
3
|
+
"version": "4.0.0-rc.0",
|
|
4
4
|
"description": "The scalable web crawling and scraping library for JavaScript/Node.js. Enables development of data extraction and web automation jobs (not only) with headless Chrome and Puppeteer.",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=22.0.0"
|
|
@@ -49,14 +49,14 @@
|
|
|
49
49
|
"dependencies": {
|
|
50
50
|
"@apify/timeout": "^0.4.4",
|
|
51
51
|
"@apify/utilities": "^2.7.10",
|
|
52
|
-
"@crawlee/http": "4.0.0-
|
|
53
|
-
"@crawlee/types": "4.0.0-
|
|
54
|
-
"@crawlee/utils": "4.0.0-
|
|
52
|
+
"@crawlee/http": "4.0.0-rc.0",
|
|
53
|
+
"@crawlee/types": "4.0.0-rc.0",
|
|
54
|
+
"@crawlee/utils": "4.0.0-rc.0",
|
|
55
55
|
"@types/jsdom": "^21.1.7",
|
|
56
56
|
"cheerio": "^1.0.0",
|
|
57
57
|
"jsdom": "^26.1.0",
|
|
58
|
-
"
|
|
59
|
-
"
|
|
58
|
+
"tslib": "^2.8.1",
|
|
59
|
+
"zod": "^4.4.3"
|
|
60
60
|
},
|
|
61
61
|
"lerna": {
|
|
62
62
|
"command": {
|
|
@@ -65,5 +65,5 @@
|
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
},
|
|
68
|
-
"gitHead": "
|
|
68
|
+
"gitHead": "79ab33dacdacb83e0197e6516d145f3aceef80c7"
|
|
69
69
|
}
|