webpeel 0.1.2 → 0.2.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/README.md +1 -1
- package/dist/cli.js +271 -13
- package/dist/cli.js.map +1 -1
- package/dist/core/fetcher.d.ts +7 -1
- package/dist/core/fetcher.d.ts.map +1 -1
- package/dist/core/fetcher.js +85 -23
- package/dist/core/fetcher.js.map +1 -1
- package/dist/core/markdown.d.ts +5 -0
- package/dist/core/markdown.d.ts.map +1 -1
- package/dist/core/markdown.js +19 -0
- package/dist/core/markdown.js.map +1 -1
- package/dist/core/strategies.d.ts +8 -0
- package/dist/core/strategies.d.ts.map +1 -1
- package/dist/core/strategies.js +14 -4
- package/dist/core/strategies.js.map +1 -1
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +64 -7
- package/dist/index.js.map +1 -1
- package/dist/mcp/server.js +147 -3
- package/dist/mcp/server.js.map +1 -1
- package/dist/types.d.ts +14 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -408,7 +408,7 @@ A: WebPeel runs locally for free (Firecrawl is cloud-only). We also have smart e
|
|
|
408
408
|
A: Yes! Run `npm run serve` to start the API server. See [docs/self-hosting.md](docs/self-hosting.md) (coming soon).
|
|
409
409
|
|
|
410
410
|
**Q: Does this violate websites' Terms of Service?**
|
|
411
|
-
A: WebPeel
|
|
411
|
+
A: WebPeel is a tool — how you use it is up to you. Always check a site's ToS before fetching at scale. We recommend respecting `robots.txt` in your own workflows.
|
|
412
412
|
|
|
413
413
|
**Q: What about CAPTCHA and Cloudflare?**
|
|
414
414
|
A: WebPeel handles most Cloudflare challenges automatically. For CAPTCHAs, you'll need a solving service (not included).
|
package/dist/cli.js
CHANGED
|
@@ -14,12 +14,14 @@
|
|
|
14
14
|
*/
|
|
15
15
|
import { Command } from 'commander';
|
|
16
16
|
import ora from 'ora';
|
|
17
|
-
import {
|
|
17
|
+
import { writeFileSync } from 'fs';
|
|
18
|
+
import { peel, peelBatch, cleanup } from './index.js';
|
|
18
19
|
const program = new Command();
|
|
19
20
|
program
|
|
20
21
|
.name('webpeel')
|
|
21
22
|
.description('Fast web fetcher for AI agents')
|
|
22
|
-
.version('0.
|
|
23
|
+
.version('0.2.0')
|
|
24
|
+
.enablePositionalOptions();
|
|
23
25
|
program
|
|
24
26
|
.argument('[url]', 'URL to fetch')
|
|
25
27
|
.option('-r, --render', 'Use headless browser (for JS-heavy sites)')
|
|
@@ -30,6 +32,12 @@ program
|
|
|
30
32
|
.option('-t, --timeout <ms>', 'Request timeout (ms)', parseInt, 30000)
|
|
31
33
|
.option('--ua <agent>', 'Custom user agent')
|
|
32
34
|
.option('-s, --silent', 'Silent mode (no spinner)')
|
|
35
|
+
.option('--screenshot [path]', 'Take a screenshot (optionally save to file path)')
|
|
36
|
+
.option('--full-page', 'Full-page screenshot (use with --screenshot)')
|
|
37
|
+
.option('--selector <css>', 'CSS selector to extract (e.g., "article", ".content")')
|
|
38
|
+
.option('--exclude <selectors...>', 'CSS selectors to exclude (e.g., ".sidebar" ".ads")')
|
|
39
|
+
.option('-H, --header <header...>', 'Custom headers (e.g., "Authorization: Bearer token")')
|
|
40
|
+
.option('--cookie <cookie...>', 'Cookies to set (e.g., "session=abc123")')
|
|
33
41
|
.action(async (url, options) => {
|
|
34
42
|
if (!url) {
|
|
35
43
|
console.error('Error: URL is required\n');
|
|
@@ -65,12 +73,34 @@ program
|
|
|
65
73
|
console.error('Error: Wait time must be between 0 and 60000ms');
|
|
66
74
|
process.exit(1);
|
|
67
75
|
}
|
|
76
|
+
// Parse custom headers
|
|
77
|
+
let headers;
|
|
78
|
+
if (options.header && options.header.length > 0) {
|
|
79
|
+
headers = {};
|
|
80
|
+
for (const header of options.header) {
|
|
81
|
+
const colonIndex = header.indexOf(':');
|
|
82
|
+
if (colonIndex === -1) {
|
|
83
|
+
console.error(`Error: Invalid header format: ${header}`);
|
|
84
|
+
console.error('Expected format: "Key: Value"');
|
|
85
|
+
process.exit(1);
|
|
86
|
+
}
|
|
87
|
+
const key = header.slice(0, colonIndex).trim();
|
|
88
|
+
const value = header.slice(colonIndex + 1).trim();
|
|
89
|
+
headers[key] = value;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
68
92
|
// Build peel options
|
|
69
93
|
const peelOptions = {
|
|
70
94
|
render: options.render || false,
|
|
71
95
|
wait: options.wait || 0,
|
|
72
96
|
timeout: options.timeout,
|
|
73
97
|
userAgent: options.ua,
|
|
98
|
+
screenshot: options.screenshot !== undefined,
|
|
99
|
+
screenshotFullPage: options.fullPage || false,
|
|
100
|
+
selector: options.selector,
|
|
101
|
+
exclude: options.exclude,
|
|
102
|
+
headers,
|
|
103
|
+
cookies: options.cookie,
|
|
74
104
|
};
|
|
75
105
|
// Determine format
|
|
76
106
|
if (options.html) {
|
|
@@ -87,12 +117,42 @@ program
|
|
|
87
117
|
if (spinner) {
|
|
88
118
|
spinner.succeed(`Fetched in ${result.elapsed}ms using ${result.method} method`);
|
|
89
119
|
}
|
|
90
|
-
//
|
|
120
|
+
// Handle screenshot saving
|
|
121
|
+
if (options.screenshot && result.screenshot) {
|
|
122
|
+
const screenshotPath = typeof options.screenshot === 'string'
|
|
123
|
+
? options.screenshot
|
|
124
|
+
: 'screenshot.png';
|
|
125
|
+
const screenshotBuffer = Buffer.from(result.screenshot, 'base64');
|
|
126
|
+
writeFileSync(screenshotPath, screenshotBuffer);
|
|
127
|
+
if (!options.silent) {
|
|
128
|
+
console.error(`Screenshot saved to: ${screenshotPath}`);
|
|
129
|
+
}
|
|
130
|
+
// Remove screenshot from JSON output if saving to file
|
|
131
|
+
if (typeof options.screenshot === 'string') {
|
|
132
|
+
delete result.screenshot;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
// Output results with proper stdout flushing
|
|
91
136
|
if (options.json) {
|
|
92
|
-
|
|
137
|
+
const jsonStr = JSON.stringify(result, null, 2);
|
|
138
|
+
await new Promise((resolve, reject) => {
|
|
139
|
+
process.stdout.write(jsonStr + '\n', (err) => {
|
|
140
|
+
if (err)
|
|
141
|
+
reject(err);
|
|
142
|
+
else
|
|
143
|
+
resolve();
|
|
144
|
+
});
|
|
145
|
+
});
|
|
93
146
|
}
|
|
94
147
|
else {
|
|
95
|
-
|
|
148
|
+
await new Promise((resolve, reject) => {
|
|
149
|
+
process.stdout.write(result.content + '\n', (err) => {
|
|
150
|
+
if (err)
|
|
151
|
+
reject(err);
|
|
152
|
+
else
|
|
153
|
+
resolve();
|
|
154
|
+
});
|
|
155
|
+
});
|
|
96
156
|
}
|
|
97
157
|
// Clean up and exit
|
|
98
158
|
await cleanup();
|
|
@@ -112,15 +172,213 @@ program
|
|
|
112
172
|
process.exit(1);
|
|
113
173
|
}
|
|
114
174
|
});
|
|
115
|
-
//
|
|
175
|
+
// Search command
|
|
116
176
|
program
|
|
117
|
-
.command('search')
|
|
118
|
-
.
|
|
119
|
-
.
|
|
120
|
-
.
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
177
|
+
.command('search <query>')
|
|
178
|
+
.description('Search using DuckDuckGo')
|
|
179
|
+
.option('-n, --count <n>', 'Number of results (1-10)', '5')
|
|
180
|
+
.option('--json', 'Output as JSON')
|
|
181
|
+
.option('-s, --silent', 'Silent mode')
|
|
182
|
+
.action(async (query, options) => {
|
|
183
|
+
const isJson = options.json;
|
|
184
|
+
const isSilent = options.silent;
|
|
185
|
+
const count = parseInt(options.count) || 5;
|
|
186
|
+
const spinner = isSilent ? null : ora('Searching...').start();
|
|
187
|
+
try {
|
|
188
|
+
// Import the search function dynamically
|
|
189
|
+
const { fetch: undiciFetch } = await import('undici');
|
|
190
|
+
const { load } = await import('cheerio');
|
|
191
|
+
const searchUrl = `https://html.duckduckgo.com/html/?q=${encodeURIComponent(query)}`;
|
|
192
|
+
const response = await undiciFetch(searchUrl, {
|
|
193
|
+
headers: {
|
|
194
|
+
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36',
|
|
195
|
+
},
|
|
196
|
+
});
|
|
197
|
+
if (!response.ok) {
|
|
198
|
+
throw new Error(`Search failed: HTTP ${response.status}`);
|
|
199
|
+
}
|
|
200
|
+
const html = await response.text();
|
|
201
|
+
const $ = load(html);
|
|
202
|
+
const results = [];
|
|
203
|
+
$('.result').each((_i, elem) => {
|
|
204
|
+
if (results.length >= count)
|
|
205
|
+
return;
|
|
206
|
+
const $result = $(elem);
|
|
207
|
+
const title = $result.find('.result__title').text().trim();
|
|
208
|
+
const rawUrl = $result.find('.result__a').attr('href') || '';
|
|
209
|
+
const snippet = $result.find('.result__snippet').text().trim();
|
|
210
|
+
if (!title || !rawUrl)
|
|
211
|
+
return;
|
|
212
|
+
// Extract actual URL from DuckDuckGo redirect
|
|
213
|
+
let url = rawUrl;
|
|
214
|
+
try {
|
|
215
|
+
const ddgUrl = new URL(rawUrl, 'https://duckduckgo.com');
|
|
216
|
+
const uddg = ddgUrl.searchParams.get('uddg');
|
|
217
|
+
if (uddg) {
|
|
218
|
+
url = decodeURIComponent(uddg);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
catch {
|
|
222
|
+
// Use raw URL if parsing fails
|
|
223
|
+
}
|
|
224
|
+
// Validate final URL
|
|
225
|
+
try {
|
|
226
|
+
const parsed = new URL(url);
|
|
227
|
+
if (!['http:', 'https:'].includes(parsed.protocol)) {
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
url = parsed.href;
|
|
231
|
+
}
|
|
232
|
+
catch {
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
results.push({
|
|
236
|
+
title: title.slice(0, 200),
|
|
237
|
+
url,
|
|
238
|
+
snippet: snippet.slice(0, 500)
|
|
239
|
+
});
|
|
240
|
+
});
|
|
241
|
+
if (spinner) {
|
|
242
|
+
spinner.succeed(`Found ${results.length} results`);
|
|
243
|
+
}
|
|
244
|
+
if (isJson) {
|
|
245
|
+
const jsonStr = JSON.stringify(results, null, 2);
|
|
246
|
+
await new Promise((resolve, reject) => {
|
|
247
|
+
process.stdout.write(jsonStr + '\n', (err) => {
|
|
248
|
+
if (err)
|
|
249
|
+
reject(err);
|
|
250
|
+
else
|
|
251
|
+
resolve();
|
|
252
|
+
});
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
else {
|
|
256
|
+
for (const result of results) {
|
|
257
|
+
console.log(`\n${result.title}`);
|
|
258
|
+
console.log(result.url);
|
|
259
|
+
console.log(result.snippet);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
process.exit(0);
|
|
263
|
+
}
|
|
264
|
+
catch (error) {
|
|
265
|
+
if (spinner) {
|
|
266
|
+
spinner.fail('Search failed');
|
|
267
|
+
}
|
|
268
|
+
if (error instanceof Error) {
|
|
269
|
+
console.error(`\nError: ${error.message}`);
|
|
270
|
+
}
|
|
271
|
+
else {
|
|
272
|
+
console.error('\nError: Unknown error occurred');
|
|
273
|
+
}
|
|
274
|
+
process.exit(1);
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
// Batch command
|
|
278
|
+
program
|
|
279
|
+
.command('batch <file>')
|
|
280
|
+
.description('Fetch multiple URLs')
|
|
281
|
+
.option('-c, --concurrency <n>', 'Max concurrent fetches (default: 3)', '3')
|
|
282
|
+
.option('-o, --output <dir>', 'Output directory (one file per URL)')
|
|
283
|
+
.option('--json', 'Output as JSON array')
|
|
284
|
+
.option('-s, --silent', 'Silent mode')
|
|
285
|
+
.option('-r, --render', 'Use headless browser')
|
|
286
|
+
.option('--selector <css>', 'CSS selector to extract')
|
|
287
|
+
.action(async (file, options) => {
|
|
288
|
+
const isJson = options.json;
|
|
289
|
+
const isSilent = options.silent;
|
|
290
|
+
const shouldRender = options.render;
|
|
291
|
+
const selector = options.selector;
|
|
292
|
+
const spinner = isSilent ? null : ora('Loading URLs...').start();
|
|
293
|
+
try {
|
|
294
|
+
const { readFileSync } = await import('fs');
|
|
295
|
+
// Read URLs from file
|
|
296
|
+
let urls;
|
|
297
|
+
try {
|
|
298
|
+
const content = readFileSync(file, 'utf-8');
|
|
299
|
+
urls = content.split('\n')
|
|
300
|
+
.map(line => line.trim())
|
|
301
|
+
.filter(line => line && !line.startsWith('#'));
|
|
302
|
+
}
|
|
303
|
+
catch (error) {
|
|
304
|
+
throw new Error(`Failed to read file: ${file}`);
|
|
305
|
+
}
|
|
306
|
+
if (urls.length === 0) {
|
|
307
|
+
throw new Error('No URLs found in file');
|
|
308
|
+
}
|
|
309
|
+
if (spinner) {
|
|
310
|
+
spinner.text = `Fetching ${urls.length} URLs (concurrency: ${options.concurrency})...`;
|
|
311
|
+
}
|
|
312
|
+
// Batch fetch
|
|
313
|
+
const results = await peelBatch(urls, {
|
|
314
|
+
concurrency: parseInt(options.concurrency) || 3,
|
|
315
|
+
render: shouldRender,
|
|
316
|
+
selector: selector,
|
|
317
|
+
});
|
|
318
|
+
if (spinner) {
|
|
319
|
+
const successCount = results.filter(r => 'content' in r).length;
|
|
320
|
+
spinner.succeed(`Completed: ${successCount}/${urls.length} successful`);
|
|
321
|
+
}
|
|
322
|
+
// Output results
|
|
323
|
+
if (isJson) {
|
|
324
|
+
const jsonStr = JSON.stringify(results, null, 2);
|
|
325
|
+
await new Promise((resolve, reject) => {
|
|
326
|
+
process.stdout.write(jsonStr + '\n', (err) => {
|
|
327
|
+
if (err)
|
|
328
|
+
reject(err);
|
|
329
|
+
else
|
|
330
|
+
resolve();
|
|
331
|
+
});
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
else if (options.output) {
|
|
335
|
+
const { writeFileSync, mkdirSync } = await import('fs');
|
|
336
|
+
const { join } = await import('path');
|
|
337
|
+
// Create output directory
|
|
338
|
+
mkdirSync(options.output, { recursive: true });
|
|
339
|
+
results.forEach((result, i) => {
|
|
340
|
+
const urlObj = new URL(urls[i]);
|
|
341
|
+
const filename = `${i + 1}_${urlObj.hostname.replace(/[^a-z0-9]/gi, '_')}.md`;
|
|
342
|
+
const filepath = join(options.output, filename);
|
|
343
|
+
if ('content' in result) {
|
|
344
|
+
writeFileSync(filepath, result.content);
|
|
345
|
+
}
|
|
346
|
+
else {
|
|
347
|
+
writeFileSync(filepath, `Error: ${result.error}`);
|
|
348
|
+
}
|
|
349
|
+
});
|
|
350
|
+
if (!isSilent) {
|
|
351
|
+
console.log(`\nResults saved to: ${options.output}`);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
else {
|
|
355
|
+
// Print results to stdout
|
|
356
|
+
results.forEach((result, i) => {
|
|
357
|
+
console.log(`\n=== ${urls[i]} ===\n`);
|
|
358
|
+
if ('content' in result) {
|
|
359
|
+
console.log(result.content.slice(0, 500) + '...');
|
|
360
|
+
}
|
|
361
|
+
else {
|
|
362
|
+
console.log(`Error: ${result.error}`);
|
|
363
|
+
}
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
await cleanup();
|
|
367
|
+
process.exit(0);
|
|
368
|
+
}
|
|
369
|
+
catch (error) {
|
|
370
|
+
if (spinner) {
|
|
371
|
+
spinner.fail('Batch fetch failed');
|
|
372
|
+
}
|
|
373
|
+
if (error instanceof Error) {
|
|
374
|
+
console.error(`\nError: ${error.message}`);
|
|
375
|
+
}
|
|
376
|
+
else {
|
|
377
|
+
console.error('\nError: Unknown error occurred');
|
|
378
|
+
}
|
|
379
|
+
await cleanup();
|
|
380
|
+
process.exit(1);
|
|
381
|
+
}
|
|
124
382
|
});
|
|
125
383
|
program
|
|
126
384
|
.command('serve')
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/core/fetcher.d.ts
CHANGED
|
@@ -5,13 +5,15 @@ export interface FetchResult {
|
|
|
5
5
|
html: string;
|
|
6
6
|
url: string;
|
|
7
7
|
statusCode?: number;
|
|
8
|
+
screenshot?: Buffer;
|
|
9
|
+
contentType?: string;
|
|
8
10
|
}
|
|
9
11
|
/**
|
|
10
12
|
* Simple HTTP fetch using native fetch + Cheerio
|
|
11
13
|
* Fast and lightweight, but can be blocked by Cloudflare/bot detection
|
|
12
14
|
* SECURITY: Manual redirect handling with SSRF re-validation
|
|
13
15
|
*/
|
|
14
|
-
export declare function simpleFetch(url: string, userAgent?: string, timeoutMs?: number): Promise<FetchResult>;
|
|
16
|
+
export declare function simpleFetch(url: string, userAgent?: string, timeoutMs?: number, customHeaders?: Record<string, string>): Promise<FetchResult>;
|
|
15
17
|
/**
|
|
16
18
|
* Fetch using headless Chromium via Playwright
|
|
17
19
|
* Slower but can handle JavaScript-heavy sites and bypass some bot detection
|
|
@@ -20,6 +22,10 @@ export declare function browserFetch(url: string, options?: {
|
|
|
20
22
|
userAgent?: string;
|
|
21
23
|
waitMs?: number;
|
|
22
24
|
timeoutMs?: number;
|
|
25
|
+
screenshot?: boolean;
|
|
26
|
+
screenshotFullPage?: boolean;
|
|
27
|
+
headers?: Record<string, string>;
|
|
28
|
+
cookies?: string[];
|
|
23
29
|
}): Promise<FetchResult>;
|
|
24
30
|
/**
|
|
25
31
|
* Retry a fetch operation with exponential backoff
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetcher.d.ts","sourceRoot":"","sources":["../../src/core/fetcher.ts"],"names":[],"mappings":"AAAA;;GAEG;AA2PH,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"fetcher.d.ts","sourceRoot":"","sources":["../../src/core/fetcher.ts"],"names":[],"mappings":"AAAA;;GAEG;AA2PH,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;GAIG;AACH,wBAAsB,WAAW,CAC/B,GAAG,EAAE,MAAM,EACX,SAAS,CAAC,EAAE,MAAM,EAClB,SAAS,GAAE,MAAc,EACzB,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACrC,OAAO,CAAC,WAAW,CAAC,CA2JtB;AAuBD;;;GAGG;AACH,wBAAsB,YAAY,CAChC,GAAG,EAAE,MAAM,EACX,OAAO,GAAE;IACP,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACf,GACL,OAAO,CAAC,WAAW,CAAC,CAiKtB;AAED;;GAEG;AACH,wBAAsB,UAAU,CAAC,CAAC,EAChC,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,WAAW,GAAE,MAAU,EACvB,WAAW,GAAE,MAAa,GACzB,OAAO,CAAC,CAAC,CAAC,CAsBZ;AAED;;GAEG;AACH,wBAAsB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAK7C"}
|
package/dist/core/fetcher.js
CHANGED
|
@@ -224,11 +224,31 @@ function validateUserAgent(userAgent) {
|
|
|
224
224
|
* Fast and lightweight, but can be blocked by Cloudflare/bot detection
|
|
225
225
|
* SECURITY: Manual redirect handling with SSRF re-validation
|
|
226
226
|
*/
|
|
227
|
-
export async function simpleFetch(url, userAgent, timeoutMs = 30000) {
|
|
227
|
+
export async function simpleFetch(url, userAgent, timeoutMs = 30000, customHeaders) {
|
|
228
228
|
// SECURITY: Validate URL to prevent SSRF
|
|
229
229
|
validateUrl(url);
|
|
230
230
|
// Validate user agent if provided
|
|
231
231
|
const validatedUserAgent = userAgent ? validateUserAgent(userAgent) : getRandomUserAgent();
|
|
232
|
+
// SECURITY: Merge custom headers with defaults, block Host header override
|
|
233
|
+
const defaultHeaders = {
|
|
234
|
+
'User-Agent': validatedUserAgent,
|
|
235
|
+
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
|
|
236
|
+
'Accept-Language': 'en-US,en;q=0.9',
|
|
237
|
+
'Accept-Encoding': 'gzip, deflate, br',
|
|
238
|
+
'DNT': '1',
|
|
239
|
+
'Connection': 'keep-alive',
|
|
240
|
+
'Upgrade-Insecure-Requests': '1',
|
|
241
|
+
};
|
|
242
|
+
const mergedHeaders = { ...defaultHeaders };
|
|
243
|
+
if (customHeaders) {
|
|
244
|
+
for (const [key, value] of Object.entries(customHeaders)) {
|
|
245
|
+
// SECURITY: Block Host header override
|
|
246
|
+
if (key.toLowerCase() === 'host') {
|
|
247
|
+
throw new WebPeelError('Custom Host header is not allowed');
|
|
248
|
+
}
|
|
249
|
+
mergedHeaders[key] = value;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
232
252
|
const MAX_REDIRECTS = 10;
|
|
233
253
|
let redirectCount = 0;
|
|
234
254
|
let currentUrl = url;
|
|
@@ -245,15 +265,7 @@ export async function simpleFetch(url, userAgent, timeoutMs = 30000) {
|
|
|
245
265
|
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
246
266
|
try {
|
|
247
267
|
const response = await fetch(currentUrl, {
|
|
248
|
-
headers:
|
|
249
|
-
'User-Agent': validatedUserAgent,
|
|
250
|
-
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
|
|
251
|
-
'Accept-Language': 'en-US,en;q=0.9',
|
|
252
|
-
'Accept-Encoding': 'gzip, deflate, br',
|
|
253
|
-
'DNT': '1',
|
|
254
|
-
'Connection': 'keep-alive',
|
|
255
|
-
'Upgrade-Insecure-Requests': '1',
|
|
256
|
-
},
|
|
268
|
+
headers: mergedHeaders,
|
|
257
269
|
signal: controller.signal,
|
|
258
270
|
redirect: 'manual', // SECURITY: Manual redirect handling
|
|
259
271
|
});
|
|
@@ -277,8 +289,10 @@ export async function simpleFetch(url, userAgent, timeoutMs = 30000) {
|
|
|
277
289
|
}
|
|
278
290
|
// SECURITY: Validate Content-Type
|
|
279
291
|
const contentType = response.headers.get('content-type') || '';
|
|
280
|
-
if (!contentType.includes('text/html') &&
|
|
281
|
-
|
|
292
|
+
if (!contentType.includes('text/html') &&
|
|
293
|
+
!contentType.includes('application/xhtml+xml') &&
|
|
294
|
+
!contentType.includes('application/pdf')) {
|
|
295
|
+
throw new WebPeelError(`Unsupported content type: ${contentType}. Supported: HTML, PDF`);
|
|
282
296
|
}
|
|
283
297
|
// SECURITY: Stream response with size limit (prevent memory exhaustion)
|
|
284
298
|
const chunks = [];
|
|
@@ -323,6 +337,7 @@ export async function simpleFetch(url, userAgent, timeoutMs = 30000) {
|
|
|
323
337
|
html,
|
|
324
338
|
url: currentUrl,
|
|
325
339
|
statusCode: response.status,
|
|
340
|
+
contentType,
|
|
326
341
|
};
|
|
327
342
|
}
|
|
328
343
|
catch (error) {
|
|
@@ -364,13 +379,25 @@ async function getBrowser() {
|
|
|
364
379
|
export async function browserFetch(url, options = {}) {
|
|
365
380
|
// SECURITY: Validate URL to prevent SSRF
|
|
366
381
|
validateUrl(url);
|
|
367
|
-
const { userAgent, waitMs = 0, timeoutMs = 30000 } = options;
|
|
382
|
+
const { userAgent, waitMs = 0, timeoutMs = 30000, screenshot = false, screenshotFullPage = false, headers, cookies } = options;
|
|
368
383
|
// Validate user agent if provided
|
|
369
384
|
const validatedUserAgent = userAgent ? validateUserAgent(userAgent) : getRandomUserAgent();
|
|
370
385
|
// Validate wait time
|
|
371
386
|
if (waitMs < 0 || waitMs > 60000) {
|
|
372
387
|
throw new WebPeelError('Wait time must be between 0 and 60000ms');
|
|
373
388
|
}
|
|
389
|
+
// SECURITY: Validate custom headers if provided
|
|
390
|
+
if (headers) {
|
|
391
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
392
|
+
// Block Host header override
|
|
393
|
+
if (key.toLowerCase() === 'host') {
|
|
394
|
+
throw new WebPeelError('Custom Host header is not allowed');
|
|
395
|
+
}
|
|
396
|
+
if (typeof value !== 'string' || value.length > 500) {
|
|
397
|
+
throw new WebPeelError('Invalid header value');
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
}
|
|
374
401
|
// SECURITY: Limit concurrent browser pages with timeout
|
|
375
402
|
const queueStartTime = Date.now();
|
|
376
403
|
const QUEUE_TIMEOUT_MS = 30000; // 30 second max wait
|
|
@@ -387,16 +414,42 @@ export async function browserFetch(url, options = {}) {
|
|
|
387
414
|
page = await browser.newPage({
|
|
388
415
|
userAgent: validatedUserAgent,
|
|
389
416
|
});
|
|
390
|
-
//
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
417
|
+
// Set custom headers if provided
|
|
418
|
+
if (headers && Object.keys(headers).length > 0) {
|
|
419
|
+
await page.setExtraHTTPHeaders(headers);
|
|
420
|
+
}
|
|
421
|
+
// Set cookies if provided
|
|
422
|
+
if (cookies && cookies.length > 0) {
|
|
423
|
+
const parsedCookies = cookies.map(cookie => {
|
|
424
|
+
const [nameValue] = cookie.split(';').map(s => s.trim());
|
|
425
|
+
const [name, value] = nameValue.split('=');
|
|
426
|
+
if (!name || value === undefined) {
|
|
427
|
+
throw new WebPeelError(`Invalid cookie format: ${cookie}`);
|
|
428
|
+
}
|
|
429
|
+
return {
|
|
430
|
+
name: name.trim(),
|
|
431
|
+
value: value.trim(),
|
|
432
|
+
url,
|
|
433
|
+
};
|
|
434
|
+
});
|
|
435
|
+
await page.context().addCookies(parsedCookies);
|
|
436
|
+
}
|
|
437
|
+
// Block images, fonts, and other heavy resources for speed (unless screenshot is requested)
|
|
438
|
+
if (!screenshot) {
|
|
439
|
+
await page.route('**/*', (route) => {
|
|
440
|
+
const resourceType = route.request().resourceType();
|
|
441
|
+
if (['image', 'font', 'media', 'stylesheet'].includes(resourceType)) {
|
|
442
|
+
route.abort();
|
|
443
|
+
}
|
|
444
|
+
else {
|
|
445
|
+
route.continue();
|
|
446
|
+
}
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
else {
|
|
450
|
+
// For screenshots, allow all resources
|
|
451
|
+
await page.route('**/*', (route) => route.continue());
|
|
452
|
+
}
|
|
400
453
|
// SECURITY: Wrap entire operation in timeout
|
|
401
454
|
const fetchPromise = (async () => {
|
|
402
455
|
await page.goto(url, {
|
|
@@ -422,9 +475,18 @@ export async function browserFetch(url, options = {}) {
|
|
|
422
475
|
if (!html || html.length < 100) {
|
|
423
476
|
throw new BlockedError('Empty or suspiciously small response from browser.');
|
|
424
477
|
}
|
|
478
|
+
// Capture screenshot if requested
|
|
479
|
+
let screenshotBuffer;
|
|
480
|
+
if (screenshot) {
|
|
481
|
+
screenshotBuffer = await page.screenshot({
|
|
482
|
+
fullPage: screenshotFullPage,
|
|
483
|
+
type: 'png'
|
|
484
|
+
});
|
|
485
|
+
}
|
|
425
486
|
return {
|
|
426
487
|
html,
|
|
427
488
|
url: finalUrl,
|
|
489
|
+
screenshot: screenshotBuffer,
|
|
428
490
|
};
|
|
429
491
|
}
|
|
430
492
|
catch (error) {
|