@crawlee/cheerio 4.0.0-beta.99 → 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/cheerio-crawler.d.ts +13 -27
- package/internals/cheerio-crawler.js +22 -49
- package/package.json +5 -5
|
@@ -1,7 +1,7 @@
|
|
|
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
|
-
import type {
|
|
4
|
-
import { type CheerioRoot
|
|
3
|
+
import type { Dictionary } from '@crawlee/types';
|
|
4
|
+
import { type CheerioRoot } from '@crawlee/utils/internal';
|
|
5
5
|
import type { CheerioAPI } from 'cheerio';
|
|
6
6
|
import * as cheerio from 'cheerio';
|
|
7
7
|
export type CheerioErrorHandler<UserData extends Dictionary = any, // with default to Dictionary we cant use a typed router in untyped crawler
|
|
@@ -9,7 +9,7 @@ JSONData extends Dictionary = any, // with default to Dictionary we cant use a t
|
|
|
9
9
|
ContextExtension = Dictionary<never>> = ErrorHandler<CrawlingContext, CheerioCrawlingContext<UserData, JSONData> & ContextExtension>;
|
|
10
10
|
export interface CheerioCrawlerOptions<ContextExtension = Dictionary<never>, ExtendedContext extends CheerioCrawlingContext = CheerioCrawlingContext & ContextExtension, UserData extends Dictionary = any, // with default to Dictionary we cant use a typed router in untyped crawler
|
|
11
11
|
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
|
|
12
|
+
Routes extends Record<keyof Routes, Dictionary> = Record<string, UserData>, StatisticStateExtension extends object = {}> extends HttpCrawlerOptions<CheerioCrawlingContext<UserData, JSONData>, ContextExtension, ExtendedContext, Routes, StatisticStateExtension> {
|
|
13
13
|
}
|
|
14
14
|
export type CheerioHook<UserData extends Dictionary = any, // with default to Dictionary we cant use a typed router in untyped crawler
|
|
15
15
|
JSONData extends Dictionary = any> = InternalHttpHook<CheerioCrawlingContext<UserData, JSONData>>;
|
|
@@ -52,10 +52,14 @@ JSONData extends Dictionary = any> extends InternalHttpCrawlingContext<UserData,
|
|
|
52
52
|
* ```
|
|
53
53
|
*/
|
|
54
54
|
parseWithCheerio(selector?: string, timeoutMs?: number): Promise<CheerioRoot>;
|
|
55
|
+
/**
|
|
56
|
+
* Extracts URLs from the parsed HTML, without adding them to the request queue.
|
|
57
|
+
*/
|
|
58
|
+
extractLinks(options?: ExtractLinksOptions): Promise<string[]>;
|
|
55
59
|
/**
|
|
56
60
|
* Helper function for extracting URLs from the parsed HTML and adding them to the request queue.
|
|
57
61
|
*/
|
|
58
|
-
enqueueLinks(options?: EnqueueLinksOptions): Promise<
|
|
62
|
+
enqueueLinks(options?: EnqueueLinksOptions): Promise<AddRequestsBatchedResult>;
|
|
59
63
|
}
|
|
60
64
|
export type CheerioRequestHandler<UserData extends Dictionary = any, // with default to Dictionary we cant use a typed router in untyped crawler
|
|
61
65
|
JSONData extends Dictionary = any> = RequestHandler<CheerioCrawlingContext<UserData, JSONData>>;
|
|
@@ -138,41 +142,24 @@ JSONData extends Dictionary = any> = RequestHandler<CheerioCrawlingContext<UserD
|
|
|
138
142
|
* ```
|
|
139
143
|
* @category Crawlers
|
|
140
144
|
*/
|
|
141
|
-
export declare class CheerioCrawler<ContextExtension = Dictionary<never>, ExtendedContext extends CheerioCrawlingContext = CheerioCrawlingContext & ContextExtension, Routes extends Record<keyof Routes, Dictionary> = Record<string, GetUserDataFromRequest<CheerioCrawlingContext['request']
|
|
145
|
+
export declare class CheerioCrawler<ContextExtension = Dictionary<never>, ExtendedContext extends CheerioCrawlingContext = CheerioCrawlingContext & ContextExtension, Routes extends Record<keyof Routes, Dictionary> = Record<string, GetUserDataFromRequest<CheerioCrawlingContext['request']>>, StatisticStateExtension extends object = {}> extends HttpCrawler<CheerioCrawlingContext, ContextExtension, ExtendedContext, Routes, StatisticStateExtension> {
|
|
142
146
|
/**
|
|
143
147
|
* All `CheerioCrawler` parameters are passed via an options object.
|
|
144
148
|
*/
|
|
145
|
-
constructor(options?: CheerioCrawlerOptions<ContextExtension, ExtendedContext, any, any, Routes>);
|
|
149
|
+
constructor(options?: CheerioCrawlerOptions<ContextExtension, ExtendedContext, any, any, Routes, StatisticStateExtension>);
|
|
146
150
|
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
147
151
|
protected buildContextPipeline(): import("@crawlee/http").ContextPipeline<CrawlingContext<Dictionary>, InternalHttpCrawlingContext<any, any> & {
|
|
148
152
|
readonly body: string;
|
|
149
153
|
readonly $: CheerioAPI;
|
|
150
154
|
} & {
|
|
151
|
-
|
|
155
|
+
extractLinks: (options?: ExtractLinksOptions) => Promise<string[]>;
|
|
156
|
+
enqueueLinks: (options?: EnqueueLinksOptions) => Promise<AddRequestsBatchedResult>;
|
|
152
157
|
waitForSelector: (selector: string, _timeoutMs?: number) => Promise<void>;
|
|
153
158
|
parseWithCheerio: (selector?: string, timeoutMs?: number) => Promise<CheerioAPI>;
|
|
154
159
|
}>;
|
|
155
160
|
private parseContent;
|
|
156
161
|
private addHelpers;
|
|
157
162
|
}
|
|
158
|
-
interface EnqueueLinksInternalOptions {
|
|
159
|
-
options?: EnqueueLinksOptions;
|
|
160
|
-
$: cheerio.CheerioAPI | null;
|
|
161
|
-
requestManager: IRequestManager;
|
|
162
|
-
robotsTxtFile?: RobotsTxtFile;
|
|
163
|
-
onSkippedRequest?: SkippedRequestCallback;
|
|
164
|
-
originalRequestUrl: string;
|
|
165
|
-
finalRequestUrl?: string;
|
|
166
|
-
}
|
|
167
|
-
interface BoundEnqueueLinksInternalOptions {
|
|
168
|
-
enqueueLinks: BasicCrawlingContext['enqueueLinks'];
|
|
169
|
-
options?: EnqueueLinksOptions;
|
|
170
|
-
$: cheerio.CheerioAPI | null;
|
|
171
|
-
originalRequestUrl: string;
|
|
172
|
-
finalRequestUrl?: string;
|
|
173
|
-
}
|
|
174
|
-
/** @internal */
|
|
175
|
-
export declare function cheerioCrawlerEnqueueLinks(options: EnqueueLinksInternalOptions | BoundEnqueueLinksInternalOptions): Promise<unknown>;
|
|
176
163
|
/**
|
|
177
164
|
* Creates new {@link Router} instance that works based on request labels.
|
|
178
165
|
* This instance can then serve as a `requestHandler` of your {@link CheerioCrawler}.
|
|
@@ -200,4 +187,3 @@ export declare function cheerioCrawlerEnqueueLinks(options: EnqueueLinksInternal
|
|
|
200
187
|
export declare function createCheerioRouter<Context extends CheerioCrawlingContext = CheerioCrawlingContext, Routes extends Record<keyof Routes, Dictionary> = Record<string, GetUserDataFromRequest<Context['request']>>>(routes?: RouterRoutes<Context, Routes>): RouterHandler<Context, Routes>;
|
|
201
188
|
export declare function createCheerioRouter<Context extends CheerioCrawlingContext = CheerioCrawlingContext, UserData extends Dictionary = GetUserDataFromRequest<Context['request']>>(routes?: RouterRoutes<Context, Record<string, UserData>>): RouterHandler<Context, Record<string, UserData>>;
|
|
202
189
|
export declare function createCheerioRouter<Context extends CheerioCrawlingContext = CheerioCrawlingContext, const Schemas extends RouteSchemas = RouteSchemas>(schemas: Schemas): RouterHandler<Context, RoutesFromSchemas<Schemas>>;
|
|
203
|
-
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { extractUrlsFromCheerio } from '@crawlee/utils';
|
|
1
|
+
import { EnqueueStrategy, HttpCrawler, NavigationSkippedError, resolveBaseUrlForEnqueueLinksFiltering, Router, } from '@crawlee/http';
|
|
2
|
+
import { extractUrlsFromCheerio } from '@crawlee/utils/internal';
|
|
3
3
|
import * as cheerio from 'cheerio';
|
|
4
4
|
import { parseDocument } from 'htmlparser2';
|
|
5
5
|
/**
|
|
@@ -130,22 +130,28 @@ export class CheerioCrawler extends HttpCrawler {
|
|
|
130
130
|
}
|
|
131
131
|
}
|
|
132
132
|
async addHelpers(crawlingContext) {
|
|
133
|
-
const
|
|
133
|
+
const addRequests = crawlingContext.addRequests;
|
|
134
|
+
const extractLinks = async (options) => {
|
|
135
|
+
if (!crawlingContext.$) {
|
|
136
|
+
throw new Error('Cannot extract links because the DOM is not available.');
|
|
137
|
+
}
|
|
138
|
+
return extractUrlsFromCheerio(crawlingContext.$, options?.selector ?? 'a', options?.baseUrl ?? crawlingContext.request.loadedUrl ?? crawlingContext.request.url);
|
|
139
|
+
};
|
|
134
140
|
return {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
limit: await this.calculateEnqueuedRequestLimit(enqueueOptions?.limit),
|
|
140
|
-
},
|
|
141
|
-
$: crawlingContext.$,
|
|
142
|
-
requestManager: await this.getRequestManager(),
|
|
143
|
-
robotsTxtFile: await this.getRobotsTxtFileForUrl(crawlingContext.request.url),
|
|
144
|
-
onSkippedRequest: this.handleSkippedRequest,
|
|
145
|
-
originalRequestUrl: crawlingContext.request.url,
|
|
141
|
+
extractLinks,
|
|
142
|
+
enqueueLinks: async (options = {}) => {
|
|
143
|
+
const baseUrl = resolveBaseUrlForEnqueueLinksFiltering({
|
|
144
|
+
enqueueStrategy: options.strategy,
|
|
146
145
|
finalRequestUrl: crawlingContext.request.loadedUrl,
|
|
147
|
-
|
|
148
|
-
|
|
146
|
+
originalRequestUrl: crawlingContext.request.url,
|
|
147
|
+
userProvidedBaseUrl: options.baseUrl,
|
|
148
|
+
});
|
|
149
|
+
const urls = await extractLinks(options);
|
|
150
|
+
return addRequests(urls, {
|
|
151
|
+
...options,
|
|
152
|
+
baseUrl,
|
|
153
|
+
strategy: options.strategy ?? EnqueueStrategy.SameHostname,
|
|
154
|
+
});
|
|
149
155
|
},
|
|
150
156
|
waitForSelector: async (selector, _timeoutMs) => {
|
|
151
157
|
if (crawlingContext.$(selector).get().length === 0) {
|
|
@@ -161,39 +167,6 @@ export class CheerioCrawler extends HttpCrawler {
|
|
|
161
167
|
};
|
|
162
168
|
}
|
|
163
169
|
}
|
|
164
|
-
/** @internal */
|
|
165
|
-
function containsEnqueueLinks(options) {
|
|
166
|
-
return !!options.enqueueLinks;
|
|
167
|
-
}
|
|
168
|
-
/** @internal */
|
|
169
|
-
export async function cheerioCrawlerEnqueueLinks(options) {
|
|
170
|
-
const { options: enqueueLinksOptions, $, originalRequestUrl, finalRequestUrl } = options;
|
|
171
|
-
if (!$) {
|
|
172
|
-
throw new Error('Cannot enqueue links because the DOM is not available.');
|
|
173
|
-
}
|
|
174
|
-
const baseUrl = resolveBaseUrlForEnqueueLinksFiltering({
|
|
175
|
-
enqueueStrategy: enqueueLinksOptions?.strategy,
|
|
176
|
-
finalRequestUrl,
|
|
177
|
-
originalRequestUrl,
|
|
178
|
-
userProvidedBaseUrl: enqueueLinksOptions?.baseUrl,
|
|
179
|
-
});
|
|
180
|
-
const urls = extractUrlsFromCheerio($, enqueueLinksOptions?.selector ?? 'a', enqueueLinksOptions?.baseUrl ?? finalRequestUrl ?? originalRequestUrl);
|
|
181
|
-
if (containsEnqueueLinks(options)) {
|
|
182
|
-
return options.enqueueLinks({
|
|
183
|
-
urls,
|
|
184
|
-
baseUrl,
|
|
185
|
-
...enqueueLinksOptions,
|
|
186
|
-
});
|
|
187
|
-
}
|
|
188
|
-
return enqueueLinks({
|
|
189
|
-
requestManager: options.requestManager,
|
|
190
|
-
robotsTxtFile: options.robotsTxtFile,
|
|
191
|
-
onSkippedRequest: options.onSkippedRequest,
|
|
192
|
-
urls,
|
|
193
|
-
baseUrl,
|
|
194
|
-
...enqueueLinksOptions,
|
|
195
|
-
});
|
|
196
|
-
}
|
|
197
170
|
export function createCheerioRouter(routesOrSchemas) {
|
|
198
171
|
return Router.create(routesOrSchemas);
|
|
199
172
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crawlee/cheerio",
|
|
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"
|
|
@@ -47,9 +47,9 @@
|
|
|
47
47
|
"access": "public"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@crawlee/http": "4.0.0-
|
|
51
|
-
"@crawlee/types": "4.0.0-
|
|
52
|
-
"@crawlee/utils": "4.0.0-
|
|
50
|
+
"@crawlee/http": "4.0.0-rc.0",
|
|
51
|
+
"@crawlee/types": "4.0.0-rc.0",
|
|
52
|
+
"@crawlee/utils": "4.0.0-rc.0",
|
|
53
53
|
"cheerio": "^1.0.0",
|
|
54
54
|
"htmlparser2": "^10.0.0",
|
|
55
55
|
"tslib": "^2.8.1"
|
|
@@ -61,5 +61,5 @@
|
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
63
|
},
|
|
64
|
-
"gitHead": "
|
|
64
|
+
"gitHead": "79ab33dacdacb83e0197e6516d145f3aceef80c7"
|
|
65
65
|
}
|