@crawlee/utils 4.0.0-beta.112 → 4.0.0-beta.114
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/sitemap.js +11 -7
- package/package.json +4 -4
package/internals/sitemap.js
CHANGED
|
@@ -3,7 +3,6 @@ import { PassThrough, pipeline, Readable, Transform } from 'node:stream';
|
|
|
3
3
|
import { StringDecoder } from 'node:string_decoder';
|
|
4
4
|
import { createGunzip } from 'node:zlib';
|
|
5
5
|
import { FetchHttpClient } from '@crawlee/http-client';
|
|
6
|
-
import sax from 'sax';
|
|
7
6
|
import MIMEType from 'whatwg-mimetype';
|
|
8
7
|
import { mergeAsyncIterables } from './iterables.js';
|
|
9
8
|
import { RobotsTxtFile } from './robots.js';
|
|
@@ -47,11 +46,15 @@ class SitemapTxtParser extends Transform {
|
|
|
47
46
|
}
|
|
48
47
|
class SitemapXmlParser extends Transform {
|
|
49
48
|
#decoder = new StringDecoder('utf8');
|
|
50
|
-
#parser
|
|
49
|
+
#parser;
|
|
51
50
|
#rootTagName;
|
|
52
51
|
#currentTag = undefined;
|
|
53
52
|
#url = {};
|
|
54
|
-
|
|
53
|
+
static async create() {
|
|
54
|
+
const { SAXParser } = await import('sax');
|
|
55
|
+
return new SitemapXmlParser(new SAXParser(true));
|
|
56
|
+
}
|
|
57
|
+
constructor(parser) {
|
|
55
58
|
super({
|
|
56
59
|
readableObjectMode: true,
|
|
57
60
|
transform: (chunk, _encoding, callback) => {
|
|
@@ -67,6 +70,7 @@ class SitemapXmlParser extends Transform {
|
|
|
67
70
|
callback();
|
|
68
71
|
},
|
|
69
72
|
});
|
|
73
|
+
this.#parser = parser;
|
|
70
74
|
this.#parser.onopentag = this.onOpenTag.bind(this);
|
|
71
75
|
this.#parser.onclosetag = this.onCloseTag.bind(this);
|
|
72
76
|
this.#parser.ontext = this.onText.bind(this);
|
|
@@ -131,7 +135,7 @@ export async function* parseSitemap(initialSources, proxyUrl, options) {
|
|
|
131
135
|
const { httpClient = new FetchHttpClient(), emitNestedSitemaps = false, maxDepth = Infinity, sitemapRetries = 3, timeoutMillis: timeout = 30000, reportNetworkErrors = true, nestedSitemapFilter, logger, } = options ?? {};
|
|
132
136
|
const sources = [...initialSources];
|
|
133
137
|
const visitedSitemapUrls = new Set();
|
|
134
|
-
const createParser = (contentType = '', url) => {
|
|
138
|
+
const createParser = async (contentType = '', url) => {
|
|
135
139
|
let mimeType;
|
|
136
140
|
try {
|
|
137
141
|
mimeType = new MIMEType(contentType);
|
|
@@ -140,7 +144,7 @@ export async function* parseSitemap(initialSources, proxyUrl, options) {
|
|
|
140
144
|
mimeType = null;
|
|
141
145
|
}
|
|
142
146
|
if (mimeType?.isXML() || url?.pathname.endsWith('.xml')) {
|
|
143
|
-
return
|
|
147
|
+
return SitemapXmlParser.create();
|
|
144
148
|
}
|
|
145
149
|
if (mimeType?.essence === 'text/plain' || url?.pathname.endsWith('.txt')) {
|
|
146
150
|
return new SitemapTxtParser();
|
|
@@ -194,7 +198,7 @@ export async function* parseSitemap(initialSources, proxyUrl, options) {
|
|
|
194
198
|
sitemapUrl.pathname = sitemapUrl.pathname.substring(0, sitemapUrl.pathname.length - 3);
|
|
195
199
|
}
|
|
196
200
|
}
|
|
197
|
-
items = pipeline(streamWithType, isGzipped ? createGunzip() : new PassThrough(), createParser(contentType ?? undefined, sitemapUrl), (e) => {
|
|
201
|
+
items = pipeline(streamWithType, isGzipped ? createGunzip() : new PassThrough(), await createParser(contentType ?? undefined, sitemapUrl), (e) => {
|
|
198
202
|
if (e !== undefined && e !== null) {
|
|
199
203
|
error = { type: 'parser', error: e };
|
|
200
204
|
}
|
|
@@ -222,7 +226,7 @@ export async function* parseSitemap(initialSources, proxyUrl, options) {
|
|
|
222
226
|
}
|
|
223
227
|
}
|
|
224
228
|
else if (source.type === 'raw') {
|
|
225
|
-
items = pipeline(Readable.from([source.content]), createParser('text/xml'), (error) => {
|
|
229
|
+
items = pipeline(Readable.from([source.content]), await createParser('text/xml'), (error) => {
|
|
226
230
|
if (error !== undefined) {
|
|
227
231
|
logger?.warning(`Malformed sitemap content: ${error}`);
|
|
228
232
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crawlee/utils",
|
|
3
|
-
"version": "4.0.0-beta.
|
|
3
|
+
"version": "4.0.0-beta.114",
|
|
4
4
|
"description": "A set of shared utilities that can be used by crawlers",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=22.0.0"
|
|
@@ -43,8 +43,8 @@
|
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"@apify/ps-tree": "^1.2.0",
|
|
46
|
-
"@crawlee/http-client": "4.0.0-beta.
|
|
47
|
-
"@crawlee/types": "4.0.0-beta.
|
|
46
|
+
"@crawlee/http-client": "4.0.0-beta.114",
|
|
47
|
+
"@crawlee/types": "4.0.0-beta.114",
|
|
48
48
|
"@types/sax": "^1.2.7",
|
|
49
49
|
"cheerio": "^1.0.0",
|
|
50
50
|
"domhandler": "^5.0.3",
|
|
@@ -62,5 +62,5 @@
|
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
64
|
},
|
|
65
|
-
"gitHead": "
|
|
65
|
+
"gitHead": "e00fd1671498a90451e62730d58cae1f5d89f2be"
|
|
66
66
|
}
|