@crawlee/utils 4.0.0-beta.23 → 4.0.0-beta.230

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.
Files changed (78) hide show
  1. package/README.md +15 -15
  2. package/index.d.ts +10 -17
  3. package/index.js +8 -16
  4. package/internal.d.ts +10 -0
  5. package/internal.js +9 -0
  6. package/internals/blocked.d.ts +0 -1
  7. package/internals/blocked.js +0 -1
  8. package/internals/cheerio.d.ts +1 -3
  9. package/internals/cheerio.js +7 -6
  10. package/internals/extract-microdata.d.ts +24 -0
  11. package/internals/extract-microdata.js +118 -0
  12. package/internals/extract-urls.d.ts +1 -2
  13. package/internals/extract-urls.js +18 -17
  14. package/internals/general.d.ts +0 -25
  15. package/internals/general.js +2 -110
  16. package/internals/iterables.d.ts +0 -80
  17. package/internals/iterables.js +0 -126
  18. package/internals/{open_graph_parser.d.ts → open-graph-parser.d.ts} +2 -3
  19. package/internals/{open_graph_parser.js → open-graph-parser.js} +8 -9
  20. package/internals/robots.d.ts +33 -15
  21. package/internals/robots.js +64 -30
  22. package/internals/schemas.d.ts +114 -0
  23. package/internals/schemas.js +115 -0
  24. package/internals/sitemap.d.ts +44 -3
  25. package/internals/sitemap.js +171 -85
  26. package/internals/social.d.ts +2 -3
  27. package/internals/social.js +8 -6
  28. package/internals/url.d.ts +69 -1
  29. package/internals/url.js +120 -2
  30. package/internals/validation.d.ts +9 -0
  31. package/internals/validation.js +16 -0
  32. package/package.json +12 -11
  33. package/index.d.ts.map +0 -1
  34. package/index.js.map +0 -1
  35. package/internals/blocked.d.ts.map +0 -1
  36. package/internals/blocked.js.map +0 -1
  37. package/internals/cheerio.d.ts.map +0 -1
  38. package/internals/cheerio.js.map +0 -1
  39. package/internals/chunk.d.ts +0 -2
  40. package/internals/chunk.d.ts.map +0 -1
  41. package/internals/chunk.js +0 -40
  42. package/internals/chunk.js.map +0 -1
  43. package/internals/debug.d.ts +0 -32
  44. package/internals/debug.d.ts.map +0 -1
  45. package/internals/debug.js +0 -41
  46. package/internals/debug.js.map +0 -1
  47. package/internals/extract-urls.d.ts.map +0 -1
  48. package/internals/extract-urls.js.map +0 -1
  49. package/internals/general.d.ts.map +0 -1
  50. package/internals/general.js.map +0 -1
  51. package/internals/iterables.d.ts.map +0 -1
  52. package/internals/iterables.js.map +0 -1
  53. package/internals/open_graph_parser.d.ts.map +0 -1
  54. package/internals/open_graph_parser.js.map +0 -1
  55. package/internals/robots.d.ts.map +0 -1
  56. package/internals/robots.js.map +0 -1
  57. package/internals/sitemap.d.ts.map +0 -1
  58. package/internals/sitemap.js.map +0 -1
  59. package/internals/social.d.ts.map +0 -1
  60. package/internals/social.js.map +0 -1
  61. package/internals/system-info/cpu-info.d.ts +0 -64
  62. package/internals/system-info/cpu-info.d.ts.map +0 -1
  63. package/internals/system-info/cpu-info.js +0 -211
  64. package/internals/system-info/cpu-info.js.map +0 -1
  65. package/internals/system-info/memory-info.d.ts +0 -28
  66. package/internals/system-info/memory-info.d.ts.map +0 -1
  67. package/internals/system-info/memory-info.js +0 -118
  68. package/internals/system-info/memory-info.js.map +0 -1
  69. package/internals/system-info/ps-tree.d.ts +0 -18
  70. package/internals/system-info/ps-tree.d.ts.map +0 -1
  71. package/internals/system-info/ps-tree.js +0 -145
  72. package/internals/system-info/ps-tree.js.map +0 -1
  73. package/internals/typedefs.d.ts +0 -5
  74. package/internals/typedefs.d.ts.map +0 -1
  75. package/internals/typedefs.js +0 -9
  76. package/internals/typedefs.js.map +0 -1
  77. package/internals/url.d.ts.map +0 -1
  78. package/internals/url.js.map +0 -1
@@ -26,85 +26,6 @@ export declare function isIterable<T>(value: unknown): value is Iterable<T>;
26
26
  * ```
27
27
  */
28
28
  export declare function isAsyncIterable<T>(value: unknown): value is AsyncIterable<T>;
29
- /**
30
- * Converts any iterable or async iterable to an async iterable.
31
- * @internal
32
- *
33
- * @yields Each item from the input iterable
34
- *
35
- * **Example usage:**
36
- * ```ts
37
- * const syncArray = [1, 2, 3];
38
- * for await (const item of asyncifyIterable(syncArray)) {
39
- * console.log(item); // 1, 2, 3
40
- * }
41
- * ```
42
- */
43
- export declare function asyncifyIterable<T>(iterable: Iterable<T> | AsyncIterable<T>): AsyncIterable<T>;
44
- /**
45
- * Lazily splits the input async iterable into chunks of specified size.
46
- * The last chunk may contain fewer items if the total number of items
47
- * is not evenly divisible by the chunk size.
48
- * @internal
49
- *
50
- * @yields Arrays of items, each containing up to chunkSize items
51
- *
52
- * **Example usage:**
53
- * ```ts
54
- * const numbers = async function* () {
55
- * for (let i = 1; i <= 10; i++) yield i;
56
- * };
57
- *
58
- * for await (const chunk of chunkedAsyncIterable(numbers(), 3)) {
59
- * console.log(chunk); // [1, 2, 3], [4, 5, 6], [7, 8, 9], [10]
60
- * }
61
- * ```
62
- */
63
- export declare function chunkedAsyncIterable<T>(iterable: AsyncIterable<T> | Iterable<T>, chunkSize: number): AsyncIterable<T[]>;
64
- /**
65
- * An async iterator that also supports peeking at the next value without consuming it.
66
- * Extends both AsyncIterator and AsyncIterable interfaces.
67
- * @internal
68
- */
69
- export interface PeekableAsyncIterator<T> extends AsyncIterator<T>, AsyncIterable<T> {
70
- /**
71
- * Peeks at the next value without consuming it from the iterator.
72
- * Subsequent calls to peek() will return the same value until next() is called.
73
- *
74
- * @returns Promise that resolves to the next value, or undefined if the iterator is exhausted
75
- */
76
- peek(): Promise<T | undefined>;
77
- }
78
- /**
79
- * An async iterable that yields peekable async iterators.
80
- * @internal
81
- */
82
- export interface PeekableAsyncIterable<T> extends AsyncIterable<T> {
83
- [Symbol.asyncIterator](): PeekableAsyncIterator<T>;
84
- }
85
- /**
86
- * Wraps an async iterable to provide peek functionality, allowing you to look at
87
- * the next value without consuming it from the iterator.
88
- * @internal
89
- *
90
- * @param iterable - The async iterable to make peekable
91
- *
92
- * **Example usage:**
93
- * ```ts
94
- * const numbers = async function* () {
95
- * yield 1; yield 2; yield 3;
96
- * };
97
- *
98
- * const peekable = peekableAsyncIterable(numbers());
99
- * const iterator = peekable[Symbol.asyncIterator]();
100
- *
101
- * console.log(await iterator.peek()); // 1 (doesn't consume)
102
- * console.log(await iterator.peek()); // 1 (still doesn't consume)
103
- * console.log(await iterator.next()); // { value: 1, done: false } (now consumed)
104
- * console.log(await iterator.peek()); // 2 (next value)
105
- * ```
106
- */
107
- export declare function peekableAsyncIterable<T>(iterable: AsyncIterable<T> | Iterable<T>): PeekableAsyncIterable<T>;
108
29
  /**
109
30
  * Merges multiple async iterables into a single async iterable, yielding values concurrently.
110
31
  *
@@ -124,4 +45,3 @@ export declare function peekableAsyncIterable<T>(iterable: AsyncIterable<T> | It
124
45
  * ```
125
46
  */
126
47
  export declare function mergeAsyncIterables<T>(...iterables: AsyncIterable<T>[]): AsyncIterable<T>;
127
- //# sourceMappingURL=iterables.d.ts.map
@@ -1,4 +1,3 @@
1
- import { inspect } from 'node:util';
2
1
  /**
3
2
  * Type guard that checks if a value is iterable (has Symbol.iterator).
4
3
  * @internal
@@ -40,130 +39,6 @@ export function isAsyncIterable(value) {
40
39
  }
41
40
  return typeof Object(value)[Symbol.asyncIterator] === 'function';
42
41
  }
43
- /**
44
- * Converts any iterable or async iterable to an async iterable.
45
- * @internal
46
- *
47
- * @yields Each item from the input iterable
48
- *
49
- * **Example usage:**
50
- * ```ts
51
- * const syncArray = [1, 2, 3];
52
- * for await (const item of asyncifyIterable(syncArray)) {
53
- * console.log(item); // 1, 2, 3
54
- * }
55
- * ```
56
- */
57
- export async function* asyncifyIterable(iterable) {
58
- yield* iterable;
59
- }
60
- /**
61
- * Lazily splits the input async iterable into chunks of specified size.
62
- * The last chunk may contain fewer items if the total number of items
63
- * is not evenly divisible by the chunk size.
64
- * @internal
65
- *
66
- * @yields Arrays of items, each containing up to chunkSize items
67
- *
68
- * **Example usage:**
69
- * ```ts
70
- * const numbers = async function* () {
71
- * for (let i = 1; i <= 10; i++) yield i;
72
- * };
73
- *
74
- * for await (const chunk of chunkedAsyncIterable(numbers(), 3)) {
75
- * console.log(chunk); // [1, 2, 3], [4, 5, 6], [7, 8, 9], [10]
76
- * }
77
- * ```
78
- */
79
- export async function* chunkedAsyncIterable(iterable, chunkSize) {
80
- if (typeof chunkSize !== 'number' || chunkSize < 1) {
81
- throw new Error(`Chunk size must be a positive number (${inspect(chunkSize)}) received`);
82
- }
83
- let chunk = [];
84
- for await (const item of iterable) {
85
- chunk.push(item);
86
- if (chunk.length >= chunkSize) {
87
- yield chunk;
88
- chunk = [];
89
- }
90
- }
91
- if (chunk.length) {
92
- yield chunk;
93
- }
94
- }
95
- /**
96
- * Wraps an async iterable to provide peek functionality, allowing you to look at
97
- * the next value without consuming it from the iterator.
98
- * @internal
99
- *
100
- * @param iterable - The async iterable to make peekable
101
- *
102
- * **Example usage:**
103
- * ```ts
104
- * const numbers = async function* () {
105
- * yield 1; yield 2; yield 3;
106
- * };
107
- *
108
- * const peekable = peekableAsyncIterable(numbers());
109
- * const iterator = peekable[Symbol.asyncIterator]();
110
- *
111
- * console.log(await iterator.peek()); // 1 (doesn't consume)
112
- * console.log(await iterator.peek()); // 1 (still doesn't consume)
113
- * console.log(await iterator.next()); // { value: 1, done: false } (now consumed)
114
- * console.log(await iterator.peek()); // 2 (next value)
115
- * ```
116
- */
117
- export function peekableAsyncIterable(iterable) {
118
- const iterator = asyncifyIterable(iterable)[Symbol.asyncIterator]();
119
- let peekedValue;
120
- let isExhausted = false;
121
- const peekableIterator = {
122
- async next() {
123
- // If we have peeked a value, return it and clear the peek
124
- if (peekedValue !== undefined) {
125
- const result = peekedValue;
126
- peekedValue = undefined;
127
- if (result.done) {
128
- isExhausted = true;
129
- return { done: true, value: undefined };
130
- }
131
- return { done: false, value: result.value };
132
- }
133
- if (isExhausted) {
134
- return { done: true, value: undefined };
135
- }
136
- const result = await iterator.next();
137
- if (result.done) {
138
- isExhausted = true;
139
- }
140
- return result;
141
- },
142
- async peek() {
143
- if (peekedValue !== undefined) {
144
- return peekedValue.done ? undefined : peekedValue.value;
145
- }
146
- if (isExhausted) {
147
- return undefined;
148
- }
149
- const result = await iterator.next();
150
- peekedValue = { done: result.done ?? false, value: result.value };
151
- if (result.done) {
152
- isExhausted = true;
153
- return undefined;
154
- }
155
- return result.value;
156
- },
157
- [Symbol.asyncIterator]() {
158
- return this;
159
- },
160
- };
161
- return {
162
- [Symbol.asyncIterator]() {
163
- return peekableIterator;
164
- },
165
- };
166
- }
167
42
  // Source - https://stackoverflow.com/a/71288323
168
43
  /**
169
44
  * Merges multiple async iterables into a single async iterable, yielding values concurrently.
@@ -219,4 +94,3 @@ export async function* mergeAsyncIterables(...iterables) {
219
94
  }
220
95
  return results;
221
96
  }
222
- //# sourceMappingURL=iterables.js.map
@@ -14,7 +14,6 @@ type OpenGraphResult = string | string[] | Dictionary<string | Dictionary>;
14
14
  * Currently existing properties are kept up to date.
15
15
  * @returns Scraped OpenGraph properties as an object.
16
16
  */
17
- export declare function parseOpenGraph(raw: string, additionalProperties?: OpenGraphProperty[]): Dictionary<OpenGraphResult>;
18
- export declare function parseOpenGraph($: CheerioAPI, additionalProperties?: OpenGraphProperty[]): Dictionary<OpenGraphResult>;
17
+ export declare function parseOpenGraph(raw: string, additionalProperties?: OpenGraphProperty[]): Promise<Dictionary<OpenGraphResult>>;
18
+ export declare function parseOpenGraph($: CheerioAPI, additionalProperties?: OpenGraphProperty[]): Promise<Dictionary<OpenGraphResult>>;
19
19
  export {};
20
- //# sourceMappingURL=open_graph_parser.d.ts.map
@@ -1,4 +1,3 @@
1
- import { load } from 'cheerio';
2
1
  /**
3
2
  * To be used with the spread operator. Ensures that the item is defined, and is not empty.
4
3
  *
@@ -255,32 +254,32 @@ const OPEN_GRAPH_PROPERTIES = [
255
254
  outputName: 'articleInfo',
256
255
  children: [
257
256
  {
258
- name: 'music:published_time',
257
+ name: 'article:published_time',
259
258
  outputName: 'publishedTime',
260
259
  children: [],
261
260
  },
262
261
  {
263
- name: 'music:modified_time',
262
+ name: 'article:modified_time',
264
263
  outputName: 'modifiedTime',
265
264
  children: [],
266
265
  },
267
266
  {
268
- name: 'music:expiration_time',
267
+ name: 'article:expiration_time',
269
268
  outputName: 'expirationTime',
270
269
  children: [],
271
270
  },
272
271
  {
273
- name: 'music:author',
272
+ name: 'article:author',
274
273
  outputName: 'author',
275
274
  children: [],
276
275
  },
277
276
  {
278
- name: 'music:section',
277
+ name: 'article:section',
279
278
  outputName: 'section',
280
279
  children: [],
281
280
  },
282
281
  {
283
- name: 'music:tag',
282
+ name: 'article:tag',
284
283
  outputName: 'tag',
285
284
  children: [],
286
285
  },
@@ -366,7 +365,8 @@ const parseOpenGraphProperty = (property, $) => {
366
365
  }, {}),
367
366
  };
368
367
  };
369
- export function parseOpenGraph(item, additionalProperties) {
368
+ export async function parseOpenGraph(item, additionalProperties) {
369
+ const { load } = await import('cheerio/slim');
370
370
  const $ = typeof item === 'string' ? load(item) : item;
371
371
  return [...(additionalProperties || []), ...OPEN_GRAPH_PROPERTIES].reduce((acc, curr) => {
372
372
  return {
@@ -375,4 +375,3 @@ export function parseOpenGraph(item, additionalProperties) {
375
375
  };
376
376
  }, {});
377
377
  }
378
- //# sourceMappingURL=open_graph_parser.js.map
@@ -1,5 +1,15 @@
1
- import type { BaseHttpClient } from '@crawlee/types';
1
+ import type { BaseHttpClient } from '@crawlee/http-client';
2
+ import type { CrawleeLogger } from '@crawlee/types';
2
3
  import { Sitemap } from './sitemap.js';
4
+ import { type EnqueueStrategy } from './url.js';
5
+ export interface RobotsTxtFileSitemapsOptions {
6
+ /**
7
+ * Keep only sitemap URLs matching this strategy relative to the robots.txt host; non-`http(s)` schemes
8
+ * are always dropped. Pass `'all'` to disable host filtering.
9
+ * @default 'same-hostname'
10
+ */
11
+ enqueueStrategy?: EnqueueStrategy | `${EnqueueStrategy}`;
12
+ }
3
13
  /**
4
14
  * Loads and queries information from a [robots.txt file](https://en.wikipedia.org/wiki/Robots.txt).
5
15
  *
@@ -19,17 +29,22 @@ import { Sitemap } from './sitemap.js';
19
29
  * ```
20
30
  */
21
31
  export declare class RobotsTxtFile {
22
- private robots;
23
- private proxyUrl?;
32
+ #private;
24
33
  private constructor();
25
34
  /**
26
35
  * Determine the location of a robots.txt file for a URL and fetch it.
27
36
  * @param url the URL to fetch robots.txt for
28
- * @param [proxyUrl] a proxy to be used for fetching the robots.txt file
37
+ * @param [options] additional options
38
+ * @param [options.signal] an AbortSignal to cancel the request
39
+ * @param [options.timeoutMillis] timeout in milliseconds for the request
40
+ * @param [options.proxyUrl] a proxy to be used for fetching the robots.txt file
29
41
  */
30
42
  static find(url: string, options?: {
43
+ signal?: AbortSignal;
44
+ timeoutMillis?: number;
31
45
  proxyUrl?: string;
32
46
  httpClient?: BaseHttpClient;
47
+ logger?: CrawleeLogger;
33
48
  }): Promise<RobotsTxtFile>;
34
49
  /**
35
50
  * Allows providing the URL and robots.txt content explicitly instead of loading it from the target site.
@@ -38,10 +53,11 @@ export declare class RobotsTxtFile {
38
53
  * @param [proxyUrl] a proxy to be used for fetching the robots.txt file
39
54
  */
40
55
  static from(url: string, content: string, proxyUrl?: string): RobotsTxtFile;
41
- protected static load(url: string, options?: {
42
- proxyUrl?: string;
43
- httpClient?: BaseHttpClient;
44
- }): Promise<RobotsTxtFile>;
56
+ /**
57
+ * Get crawl delay for a given user agent.
58
+ * @param [userAgent] relevant user agent, default to `*`
59
+ */
60
+ getCrawlDelay(userAgent?: string): number | undefined;
45
61
  /**
46
62
  * Check if a URL should be crawled by robots.
47
63
  * @param url the URL to check against the rules in robots.txt
@@ -49,17 +65,19 @@ export declare class RobotsTxtFile {
49
65
  */
50
66
  isAllowed(url: string, userAgent?: string): boolean;
51
67
  /**
52
- * Get URLs of sitemaps referenced in the robots file.
68
+ * Get URLs of sitemaps referenced in the robots file, filtered by `options.enqueueStrategy` relative to
69
+ * the robots.txt host (default `'same-hostname'`; pass `'all'` to disable). Non-`http(s)` schemes are
70
+ * always dropped.
53
71
  */
54
- getSitemaps(): string[];
72
+ getSitemaps(options?: RobotsTxtFileSitemapsOptions): string[];
55
73
  /**
56
- * Parse all the sitemaps referenced in the robots file.
74
+ * Parse all the sitemaps referenced in the robots file. `options` are forwarded to `getSitemaps`
75
+ * and the sitemap parser.
57
76
  */
58
- parseSitemaps(): Promise<Sitemap>;
77
+ parseSitemaps(options?: RobotsTxtFileSitemapsOptions): Promise<Sitemap>;
59
78
  /**
60
79
  * Get all URLs from all the sitemaps referenced in the robots file. A shorthand for `(await robots.parseSitemaps()).urls`.
80
+ * `options` are forwarded to `parseSitemaps`.
61
81
  */
62
- parseUrlsFromSitemaps(): Promise<string[]>;
82
+ parseUrlsFromSitemaps(options?: RobotsTxtFileSitemapsOptions): Promise<string[]>;
63
83
  }
64
- export { RobotsTxtFile as RobotsFile };
65
- //# sourceMappingURL=robots.d.ts.map
@@ -1,6 +1,7 @@
1
1
  import { FetchHttpClient } from '@crawlee/http-client';
2
2
  import robotsParser from 'robots-parser';
3
3
  import { Sitemap } from './sitemap.js';
4
+ import { filterUrl } from './url.js';
4
5
  /**
5
6
  * Loads and queries information from a [robots.txt file](https://en.wikipedia.org/wiki/Robots.txt).
6
7
  *
@@ -20,22 +21,29 @@ import { Sitemap } from './sitemap.js';
20
21
  * ```
21
22
  */
22
23
  export class RobotsTxtFile {
23
- robots;
24
- proxyUrl;
25
- constructor(robots, proxyUrl) {
26
- this.robots = robots;
27
- this.proxyUrl = proxyUrl;
24
+ #url;
25
+ #robots;
26
+ #proxyUrl;
27
+ #logger;
28
+ constructor(url, robots, proxyUrl, logger) {
29
+ this.#url = url;
30
+ this.#robots = robots;
31
+ this.#proxyUrl = proxyUrl;
32
+ this.#logger = logger;
28
33
  }
29
34
  /**
30
35
  * Determine the location of a robots.txt file for a URL and fetch it.
31
36
  * @param url the URL to fetch robots.txt for
32
- * @param [proxyUrl] a proxy to be used for fetching the robots.txt file
37
+ * @param [options] additional options
38
+ * @param [options.signal] an AbortSignal to cancel the request
39
+ * @param [options.timeoutMillis] timeout in milliseconds for the request
40
+ * @param [options.proxyUrl] a proxy to be used for fetching the robots.txt file
33
41
  */
34
42
  static async find(url, options) {
35
43
  const robotsTxtFileUrl = new URL(url);
36
44
  robotsTxtFileUrl.pathname = '/robots.txt';
37
45
  robotsTxtFileUrl.search = '';
38
- return RobotsTxtFile.load(robotsTxtFileUrl.toString(), options);
46
+ return RobotsTxtFile.#load(robotsTxtFileUrl.toString(), options);
39
47
  }
40
48
  /**
41
49
  * Allows providing the URL and robots.txt content explicitly instead of loading it from the target site.
@@ -45,28 +53,42 @@ export class RobotsTxtFile {
45
53
  */
46
54
  static from(url, content, proxyUrl) {
47
55
  // @ts-ignore
48
- return new RobotsTxtFile(robotsParser(url, content), proxyUrl);
56
+ return new RobotsTxtFile(url, robotsParser(url, content), proxyUrl);
49
57
  }
50
- static async load(url, options) {
51
- const { proxyUrl, httpClient = new FetchHttpClient() } = options || {};
58
+ static async #load(url, options) {
59
+ const { proxyUrl, logger, httpClient = new FetchHttpClient() } = options || {};
52
60
  const response = await httpClient.sendRequest(new Request(url, { method: 'GET' }), {
53
61
  proxyUrl,
62
+ timeoutMillis: options?.timeoutMillis,
63
+ signal: options?.signal,
54
64
  });
55
- if (response.status < 200 || response.status >= 300) {
56
- throw new Error(`Failed to load robots.txt from ${url}: HTTP ${response.status}`);
57
- }
58
- if (response.status === 404) {
59
- return new RobotsTxtFile({
65
+ // RFC 9309: an unavailable (4xx) robots.txt allows everything, an unreachable (5xx) one disallows everything.
66
+ if (response.status >= 400 && response.status < 600) {
67
+ const allowed = response.status < 500;
68
+ return new RobotsTxtFile(url, {
60
69
  isAllowed() {
61
- return true;
70
+ return allowed;
62
71
  },
63
72
  getSitemaps() {
64
73
  return [];
65
74
  },
66
- }, proxyUrl);
75
+ getCrawlDelay() {
76
+ return undefined;
77
+ },
78
+ }, proxyUrl, logger);
79
+ }
80
+ if (response.status < 200 || response.status >= 300) {
81
+ throw new Error(`Failed to load robots.txt from ${url}: HTTP ${response.status}`);
67
82
  }
68
83
  // @ts-ignore
69
- return new RobotsTxtFile(robotsParser(url.toString(), await response.text()), proxyUrl);
84
+ return new RobotsTxtFile(url, robotsParser(url.toString(), await response.text()), proxyUrl, logger);
85
+ }
86
+ /**
87
+ * Get crawl delay for a given user agent.
88
+ * @param [userAgent] relevant user agent, default to `*`
89
+ */
90
+ getCrawlDelay(userAgent = '*') {
91
+ return this.#robots.getCrawlDelay(userAgent);
70
92
  }
71
93
  /**
72
94
  * Check if a URL should be crawled by robots.
@@ -74,27 +96,39 @@ export class RobotsTxtFile {
74
96
  * @param [userAgent] relevant user agent, default to `*`
75
97
  */
76
98
  isAllowed(url, userAgent = '*') {
77
- return this.robots.isAllowed(url, userAgent) ?? true; // `undefined` means that there is no explicit rule for the requested URL - assume it's allowed
99
+ return this.#robots.isAllowed(url, userAgent) ?? true; // `undefined` means that there is no explicit rule for the requested URL - assume it's allowed
78
100
  }
79
101
  /**
80
- * Get URLs of sitemaps referenced in the robots file.
102
+ * Get URLs of sitemaps referenced in the robots file, filtered by `options.enqueueStrategy` relative to
103
+ * the robots.txt host (default `'same-hostname'`; pass `'all'` to disable). Non-`http(s)` schemes are
104
+ * always dropped.
81
105
  */
82
- getSitemaps() {
83
- return this.robots.getSitemaps();
106
+ getSitemaps(options = {}) {
107
+ const { enqueueStrategy = 'same-hostname' } = options;
108
+ const sitemaps = [];
109
+ for (const sitemapUrl of this.#robots.getSitemaps()) {
110
+ // `filterUrl` tolerates an unparseable origin (returns not-allowed) rather than throwing.
111
+ const { allowed, reason } = filterUrl(sitemapUrl, this.#url, enqueueStrategy);
112
+ if (!allowed) {
113
+ this.#logger?.warning(`Skipping sitemap ${sitemapUrl} listed in robots.txt at ${this.#url}: ${reason}.`);
114
+ continue;
115
+ }
116
+ sitemaps.push(sitemapUrl);
117
+ }
118
+ return sitemaps;
84
119
  }
85
120
  /**
86
- * Parse all the sitemaps referenced in the robots file.
121
+ * Parse all the sitemaps referenced in the robots file. `options` are forwarded to `getSitemaps`
122
+ * and the sitemap parser.
87
123
  */
88
- async parseSitemaps() {
89
- return Sitemap.load(this.robots.getSitemaps(), this.proxyUrl);
124
+ async parseSitemaps(options = {}) {
125
+ return Sitemap.load(this.getSitemaps(options), this.#proxyUrl, { ...options, logger: this.#logger });
90
126
  }
91
127
  /**
92
128
  * Get all URLs from all the sitemaps referenced in the robots file. A shorthand for `(await robots.parseSitemaps()).urls`.
129
+ * `options` are forwarded to `parseSitemaps`.
93
130
  */
94
- async parseUrlsFromSitemaps() {
95
- return (await this.parseSitemaps()).urls;
131
+ async parseUrlsFromSitemaps(options = {}) {
132
+ return (await this.parseSitemaps(options)).urls;
96
133
  }
97
134
  }
98
- // to stay backwards compatible
99
- export { RobotsTxtFile as RobotsFile };
100
- //# sourceMappingURL=robots.js.map
@@ -0,0 +1,114 @@
1
+ import { BaseHttpClient } from '@crawlee/http-client';
2
+ import type { Dictionary } from '@crawlee/types';
3
+ import { z } from 'zod';
4
+ /**
5
+ * Accepts any object (including arrays and functions).
6
+ * @internal
7
+ */
8
+ export declare const anyObject: z.ZodCustom<Dictionary, Dictionary>;
9
+ /**
10
+ * Accepts any array without validating its items (cheap for huge arrays).
11
+ * @internal
12
+ */
13
+ export declare const anyArray: z.ZodCustom<unknown[], unknown[]>;
14
+ /**
15
+ * Accepts any function.
16
+ * @internal
17
+ */
18
+ export declare const anyFunction: z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>;
19
+ /**
20
+ * Mirrors `ow.number`: `Infinity` is a valid number, `NaN` is not.
21
+ * @internal
22
+ */
23
+ export declare const anyNumber: z.ZodCustom<number, number>;
24
+ /**
25
+ * Accepts any object (including functions) that has all the given keys, own or inherited.
26
+ * @internal
27
+ */
28
+ export declare function objectWithKeys(keys: string[], message?: string): z.ZodType<Dictionary>;
29
+ /**
30
+ * Accepts only instances of {@link BaseHttpClient} (all Crawlee HTTP clients extend it).
31
+ * @internal
32
+ */
33
+ export declare const httpClient: z.ZodInstanceOf<BaseHttpClient>;
34
+ /**
35
+ * Accepts any object implementing the CrawleeLogger interface.
36
+ * @internal
37
+ */
38
+ export declare const logger: z.ZodType<Dictionary, unknown, z.core.$ZodTypeInternals<Dictionary, unknown>>;
39
+ /**
40
+ * Accepts any typed array (`Uint8Array`, `Float64Array`, ...), but not a `DataView`.
41
+ * @internal
42
+ */
43
+ export declare const typedArray: z.ZodCustom<NodeJS.TypedArray<ArrayBufferLike>, NodeJS.TypedArray<ArrayBufferLike>>;
44
+ /**
45
+ * Accepts any non-null, non-array object.
46
+ * @internal
47
+ */
48
+ export declare const plainObject: z.ZodCustom<Record<string, unknown>, Record<string, unknown>>;
49
+ /**
50
+ * Shape of a request stored in a request queue. Compiled: storage clients validate every request with it.
51
+ * @internal
52
+ */
53
+ export declare const storageRequest: z.ZodObject<{
54
+ id: z.ZodString;
55
+ url: z.ZodURL;
56
+ uniqueKey: z.ZodString;
57
+ method: z.ZodOptional<z.ZodString>;
58
+ retryCount: z.ZodOptional<z.ZodNumber>;
59
+ handledAt: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodDate]>>;
60
+ }, z.core.$loose>;
61
+ /**
62
+ * {@link storageRequest} before an id is assigned.
63
+ * @internal
64
+ */
65
+ export declare const storageRequestWithoutId: z.ZodObject<{
66
+ url: z.ZodURL;
67
+ uniqueKey: z.ZodString;
68
+ method: z.ZodOptional<z.ZodString>;
69
+ retryCount: z.ZodOptional<z.ZodNumber>;
70
+ handledAt: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodDate]>>;
71
+ }, z.core.$loose>;
72
+ /**
73
+ * `z.array(item)` whose top-level type error names the element type — ``expected an array of numbers`` —
74
+ * instead of zod's bare `expected array`. Element failures keep zod's per-index messages, and `elements`
75
+ * is a human-readable plural (`'numbers'`, `'URL patterns'`), since element types cannot be introspected.
76
+ * @internal
77
+ */
78
+ export declare function arrayOf<TItem extends z.ZodType>(item: TItem, elements: string): z.ZodArray<TItem>;
79
+ /**
80
+ * Batch of {@link storageRequestWithoutId}.
81
+ * @internal
82
+ */
83
+ export declare const storageRequestBatch: z.ZodArray<z.ZodObject<{
84
+ url: z.ZodURL;
85
+ uniqueKey: z.ZodString;
86
+ method: z.ZodOptional<z.ZodString>;
87
+ retryCount: z.ZodOptional<z.ZodNumber>;
88
+ handledAt: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodDate]>>;
89
+ }, z.core.$loose>>;
90
+ /**
91
+ * Options of request queue add/update operations.
92
+ * @internal
93
+ */
94
+ export declare const requestQueueOperationOptions: z.ZodObject<{
95
+ forefront: z.ZodOptional<z.ZodBoolean>;
96
+ }, z.core.$strip>;
97
+ /**
98
+ * Options of key-value store `listKeys`.
99
+ * @internal
100
+ */
101
+ export declare const keyValueStoreListKeysOptions: z.ZodObject<{
102
+ prefix: z.ZodOptional<z.ZodString>;
103
+ exclusiveStartKey: z.ZodOptional<z.ZodString>;
104
+ limit: z.ZodOptional<z.ZodNumber>;
105
+ }, z.core.$strip>;
106
+ /**
107
+ * Options of dataset item listing.
108
+ * @internal
109
+ */
110
+ export declare const datasetListItemsOptions: z.ZodObject<{
111
+ desc: z.ZodOptional<z.ZodBoolean>;
112
+ limit: z.ZodOptional<z.ZodNumber>;
113
+ offset: z.ZodOptional<z.ZodNumber>;
114
+ }, z.core.$strip>;