webcrawlerapi-js 1.0.8 → 1.0.10
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 +3 -2
- package/api.ts +30 -54
- package/constants.ts +14 -0
- package/dist/constants.d.ts +13 -0
- package/dist/constants.js +16 -0
- package/dist/errors.d.ts +12 -0
- package/dist/errors.js +19 -0
- package/errors.ts +25 -0
- package/index.ts +4 -1
- package/package.json +8 -7
- package/dist/api.js +0 -238
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -17
package/README.md
CHANGED
|
@@ -16,10 +16,10 @@ Install WebcrawlerAPI js package:
|
|
|
16
16
|
## Request example
|
|
17
17
|
|
|
18
18
|
```javascript
|
|
19
|
-
import
|
|
19
|
+
import { WebcrawlerClient } from "webcrawlerapi-js"
|
|
20
20
|
|
|
21
21
|
async function main() {
|
|
22
|
-
const client = new
|
|
22
|
+
const client = new WebcrawlerClient(
|
|
23
23
|
"YOUR API ACCESS KEY HERE",
|
|
24
24
|
)
|
|
25
25
|
// sync way - promise will be resolved with the all the data
|
|
@@ -79,6 +79,7 @@ main().catch(console.error);
|
|
|
79
79
|
status: 'new',
|
|
80
80
|
title: '',
|
|
81
81
|
last_error: '',
|
|
82
|
+
error_code: '',
|
|
82
83
|
created_at: '2024-12-28T21:36:04.468Z',
|
|
83
84
|
updated_at: '2024-12-28T21:36:04.435Z',
|
|
84
85
|
cost: 0,
|
package/api.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import {CrawlRequest, Job, JobId, ScrapeRequest, ScrapeResponse} from "./model";
|
|
2
|
+
import { JobStatus } from "./constants";
|
|
3
|
+
import { WebcrawlerApiError, createErrorFromResponse } from "./errors";
|
|
2
4
|
|
|
3
5
|
const BASE_PATH = "https://api.webcrawlerapi.com"
|
|
4
6
|
const initialPullDelayMs = 2000
|
|
@@ -28,18 +30,7 @@ export class WebcrawlerClient {
|
|
|
28
30
|
'body': JSON.stringify(scrapeRequest),
|
|
29
31
|
};
|
|
30
32
|
|
|
31
|
-
|
|
32
|
-
if (response.ok) {
|
|
33
|
-
return response.json();
|
|
34
|
-
}
|
|
35
|
-
try {
|
|
36
|
-
const data = await response.json();
|
|
37
|
-
throw new Error(
|
|
38
|
-
`failed to scrape, response returned ${response.status} ${response.statusText}: ${data?.error}`
|
|
39
|
-
);
|
|
40
|
-
} catch (e) {
|
|
41
|
-
throw e;
|
|
42
|
-
}
|
|
33
|
+
return await this.sendRequest(url, requestOptions);
|
|
43
34
|
}
|
|
44
35
|
|
|
45
36
|
public async scrapeWithMeta(scrapeRequest: ScrapeRequest, maxPollingRetries: number = MaxPullRetries): Promise<ScrapeResponse> {
|
|
@@ -57,7 +48,7 @@ export class WebcrawlerClient {
|
|
|
57
48
|
const jobIdResponse: JobId = await this.sendRequest(url, requestOptions);
|
|
58
49
|
|
|
59
50
|
if (jobIdResponse.id === '') {
|
|
60
|
-
throw new
|
|
51
|
+
throw new WebcrawlerApiError('invalid_response', 'Failed to fetch job status', 0);
|
|
61
52
|
}
|
|
62
53
|
|
|
63
54
|
let delayIntervalMs = initialPullDelayMs;
|
|
@@ -67,14 +58,14 @@ export class WebcrawlerClient {
|
|
|
67
58
|
if (scrapeRequest.debug) {
|
|
68
59
|
console.log(`Scrape result: ${JSON.stringify(scrapeResult)}`);
|
|
69
60
|
}
|
|
70
|
-
if (scrapeResult.status !==
|
|
61
|
+
if (scrapeResult.status !== JobStatus.IN_PROGRESS && scrapeResult.status !== JobStatus.NEW) {
|
|
71
62
|
return scrapeResult;
|
|
72
63
|
}
|
|
73
64
|
if (scrapeResult.recommended_pull_delay_ms > 0) {
|
|
74
65
|
delayIntervalMs = scrapeResult.recommended_pull_delay_ms;
|
|
75
66
|
}
|
|
76
67
|
}
|
|
77
|
-
throw new
|
|
68
|
+
throw new WebcrawlerApiError('timeout', 'Scraping took too long, please retry or increase the number of polling retries', 0);
|
|
78
69
|
}
|
|
79
70
|
|
|
80
71
|
public async scrape(scrapeRequest: ScrapeRequest, maxPollingRetries: number = MaxPullRetries): Promise<any> {
|
|
@@ -95,21 +86,7 @@ export class WebcrawlerClient {
|
|
|
95
86
|
'Expires': '0'
|
|
96
87
|
},
|
|
97
88
|
};
|
|
98
|
-
|
|
99
|
-
if (response.ok) {
|
|
100
|
-
return response.json();
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
try {
|
|
104
|
-
const data = await response.json();
|
|
105
|
-
throw new Error(
|
|
106
|
-
`failed to fetch job status ${response.status} ${response.statusText}: ${JSON.stringify(data)}`
|
|
107
|
-
);
|
|
108
|
-
} catch (e) {
|
|
109
|
-
throw new Error(
|
|
110
|
-
`failed to fetch job status ${response.status} ${response.statusText}`
|
|
111
|
-
);
|
|
112
|
-
}
|
|
89
|
+
return await this.sendRequest(url, requestOptions);
|
|
113
90
|
}
|
|
114
91
|
|
|
115
92
|
public async crawl(crawlRequest: CrawlRequest): Promise<Job> {
|
|
@@ -131,7 +108,7 @@ export class WebcrawlerClient {
|
|
|
131
108
|
const jobIdResponse: JobId = await this.sendRequest(url, requestOptions);
|
|
132
109
|
|
|
133
110
|
if (jobIdResponse.id === '') {
|
|
134
|
-
throw new
|
|
111
|
+
throw new WebcrawlerApiError('invalid_response', 'Failed to fetch job status', 0);
|
|
135
112
|
}
|
|
136
113
|
|
|
137
114
|
let delayIntervalMs = initialPullDelayMs;
|
|
@@ -139,12 +116,12 @@ export class WebcrawlerClient {
|
|
|
139
116
|
await new Promise(resolve => setTimeout(resolve, delayIntervalMs));
|
|
140
117
|
const timestamp = new Date().getTime();
|
|
141
118
|
const job = await this.getJob(`${jobIdResponse.id}?t=${timestamp}`);
|
|
142
|
-
if (job.status !==
|
|
119
|
+
if (job.status !== JobStatus.IN_PROGRESS && job.status !== JobStatus.NEW) {
|
|
143
120
|
// Transform each job item to include getContent method
|
|
144
121
|
job.job_items = job.job_items.map(item => ({
|
|
145
122
|
...item,
|
|
146
123
|
getContent: async function(): Promise<string | null> {
|
|
147
|
-
if (this.status !==
|
|
124
|
+
if (job.status !== JobStatus.DONE || this.status !== JobStatus.DONE) {
|
|
148
125
|
return null;
|
|
149
126
|
}
|
|
150
127
|
|
|
@@ -185,7 +162,7 @@ export class WebcrawlerClient {
|
|
|
185
162
|
delayIntervalMs = job.recommended_pull_delay_ms;
|
|
186
163
|
}
|
|
187
164
|
}
|
|
188
|
-
throw new
|
|
165
|
+
throw new WebcrawlerApiError('timeout', 'Crawling took too long, please retry or increase the number of polling retries', 0);
|
|
189
166
|
}
|
|
190
167
|
|
|
191
168
|
public async crawlAsync(crawlRequest: CrawlRequest): Promise<JobId> {
|
|
@@ -215,36 +192,35 @@ export class WebcrawlerClient {
|
|
|
215
192
|
'Pragma': 'no-cache',
|
|
216
193
|
'Expires': '0'
|
|
217
194
|
}
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
if (response.ok) {
|
|
221
|
-
return response.json();
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
try {
|
|
225
|
-
const data = await response.json();
|
|
226
|
-
throw new Error(
|
|
227
|
-
`failed to fetch job status ${response.status} ${response.statusText}: ${JSON.stringify(data)}`
|
|
228
|
-
);
|
|
229
|
-
} catch (e) {
|
|
230
|
-
throw new Error(
|
|
231
|
-
`failed to fetch job status ${response.status} ${response.statusText}`
|
|
232
|
-
);
|
|
233
|
-
}
|
|
195
|
+
};
|
|
196
|
+
return await this.sendRequest(url, requestOptions);
|
|
234
197
|
}
|
|
235
198
|
|
|
236
|
-
|
|
237
199
|
private async sendRequest(url: string, requestOptions: any): Promise<any> {
|
|
238
200
|
let response: Response;
|
|
239
201
|
try {
|
|
240
202
|
response = await fetch(url, requestOptions);
|
|
241
203
|
} catch (e) {
|
|
242
|
-
throw new
|
|
204
|
+
throw new WebcrawlerApiError('network_error', `Failed to send request: ${e}`, 0);
|
|
243
205
|
}
|
|
206
|
+
|
|
244
207
|
if (!response.ok) {
|
|
245
|
-
|
|
246
|
-
|
|
208
|
+
try {
|
|
209
|
+
const errorData = await response.json();
|
|
210
|
+
throw createErrorFromResponse(response, errorData);
|
|
211
|
+
} catch (e) {
|
|
212
|
+
if (e instanceof WebcrawlerApiError) {
|
|
213
|
+
throw e;
|
|
214
|
+
}
|
|
215
|
+
// If we can't parse the error response, create a generic error
|
|
216
|
+
throw new WebcrawlerApiError(
|
|
217
|
+
'unknown_error',
|
|
218
|
+
`Request failed with status ${response.status} ${response.statusText}`,
|
|
219
|
+
response.status
|
|
220
|
+
);
|
|
221
|
+
}
|
|
247
222
|
}
|
|
223
|
+
|
|
248
224
|
return response.json();
|
|
249
225
|
}
|
|
250
226
|
}
|
package/constants.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export const JobStatus = {
|
|
2
|
+
IN_PROGRESS: 'in_progress',
|
|
3
|
+
NEW: 'new',
|
|
4
|
+
DONE: 'done'
|
|
5
|
+
} as const;
|
|
6
|
+
|
|
7
|
+
export const HttpStatus = {
|
|
8
|
+
OK: 200,
|
|
9
|
+
BAD_REQUEST: 400,
|
|
10
|
+
UNAUTHORIZED: 401,
|
|
11
|
+
FORBIDDEN: 403,
|
|
12
|
+
NOT_FOUND: 404,
|
|
13
|
+
INTERNAL_SERVER_ERROR: 500
|
|
14
|
+
} as const;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare const JobStatus: {
|
|
2
|
+
readonly IN_PROGRESS: "in_progress";
|
|
3
|
+
readonly NEW: "new";
|
|
4
|
+
readonly DONE: "done";
|
|
5
|
+
};
|
|
6
|
+
export declare const HttpStatus: {
|
|
7
|
+
readonly OK: 200;
|
|
8
|
+
readonly BAD_REQUEST: 400;
|
|
9
|
+
readonly UNAUTHORIZED: 401;
|
|
10
|
+
readonly FORBIDDEN: 403;
|
|
11
|
+
readonly NOT_FOUND: 404;
|
|
12
|
+
readonly INTERNAL_SERVER_ERROR: 500;
|
|
13
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.HttpStatus = exports.JobStatus = void 0;
|
|
4
|
+
exports.JobStatus = {
|
|
5
|
+
IN_PROGRESS: 'in_progress',
|
|
6
|
+
NEW: 'new',
|
|
7
|
+
DONE: 'done'
|
|
8
|
+
};
|
|
9
|
+
exports.HttpStatus = {
|
|
10
|
+
OK: 200,
|
|
11
|
+
BAD_REQUEST: 400,
|
|
12
|
+
UNAUTHORIZED: 401,
|
|
13
|
+
FORBIDDEN: 403,
|
|
14
|
+
NOT_FOUND: 404,
|
|
15
|
+
INTERNAL_SERVER_ERROR: 500
|
|
16
|
+
};
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare class WebcrawlerApiError extends Error {
|
|
2
|
+
errorCode: string;
|
|
3
|
+
errorMessage: string;
|
|
4
|
+
statusCode?: number;
|
|
5
|
+
constructor(errorCode: string, errorMessage: string, statusCode?: number);
|
|
6
|
+
}
|
|
7
|
+
export interface ErrorResponse {
|
|
8
|
+
error_code?: string;
|
|
9
|
+
error_message?: string;
|
|
10
|
+
error?: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function createErrorFromResponse(response: Response, data: ErrorResponse): WebcrawlerApiError;
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WebcrawlerApiError = void 0;
|
|
4
|
+
exports.createErrorFromResponse = createErrorFromResponse;
|
|
5
|
+
class WebcrawlerApiError extends Error {
|
|
6
|
+
constructor(errorCode, errorMessage, statusCode) {
|
|
7
|
+
super(errorMessage);
|
|
8
|
+
this.name = 'WebcrawlerApiError';
|
|
9
|
+
this.errorCode = errorCode;
|
|
10
|
+
this.errorMessage = errorMessage;
|
|
11
|
+
this.statusCode = statusCode;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
exports.WebcrawlerApiError = WebcrawlerApiError;
|
|
15
|
+
function createErrorFromResponse(response, data) {
|
|
16
|
+
const errorCode = data.error_code || 'unknown_error';
|
|
17
|
+
const errorMessage = data.error_message || data.error || 'Unknown error';
|
|
18
|
+
return new WebcrawlerApiError(errorCode, errorMessage, response.status);
|
|
19
|
+
}
|
package/errors.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export class WebcrawlerApiError extends Error {
|
|
2
|
+
public errorCode: string;
|
|
3
|
+
public errorMessage: string;
|
|
4
|
+
public statusCode?: number;
|
|
5
|
+
|
|
6
|
+
constructor(errorCode: string, errorMessage: string, statusCode?: number) {
|
|
7
|
+
super(errorMessage);
|
|
8
|
+
this.name = 'WebcrawlerApiError';
|
|
9
|
+
this.errorCode = errorCode;
|
|
10
|
+
this.errorMessage = errorMessage;
|
|
11
|
+
this.statusCode = statusCode;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface ErrorResponse {
|
|
16
|
+
error_code?: string;
|
|
17
|
+
error_message?: string;
|
|
18
|
+
error?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function createErrorFromResponse(response: Response, data: ErrorResponse): WebcrawlerApiError {
|
|
22
|
+
const errorCode = data.error_code || 'unknown_error';
|
|
23
|
+
const errorMessage = data.error_message || data.error || 'Unknown error';
|
|
24
|
+
return new WebcrawlerApiError(errorCode, errorMessage, response.status);
|
|
25
|
+
}
|
package/index.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "webcrawlerapi-js",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
|
|
3
|
+
"version": "1.0.10",
|
|
4
|
+
|
|
5
|
+
"description": "JS client for WebcrawlerAPI",
|
|
5
6
|
"main": "./dist/index.js",
|
|
6
7
|
"types": "./dist/index.d.ts",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"build": "tsc --outDir dist/"
|
|
10
|
+
},
|
|
7
11
|
"keywords": [
|
|
8
12
|
"scraping",
|
|
9
13
|
"scraper",
|
|
@@ -19,8 +23,5 @@
|
|
|
19
23
|
},
|
|
20
24
|
"author": "Andrew <sdk@webcrawlerapi.com>",
|
|
21
25
|
"license": "MIT",
|
|
22
|
-
"dependencies": {}
|
|
23
|
-
|
|
24
|
-
"build": "tsc --outDir dist/"
|
|
25
|
-
}
|
|
26
|
-
}
|
|
26
|
+
"dependencies": {}
|
|
27
|
+
}
|
package/dist/api.js
DELETED
|
@@ -1,238 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.WebcrawlerClient = void 0;
|
|
13
|
-
const BASE_PATH = "https://api.webcrawlerapi.com";
|
|
14
|
-
const initialPullDelayMs = 2000;
|
|
15
|
-
const MaxPullRetries = 100;
|
|
16
|
-
class WebcrawlerClient {
|
|
17
|
-
constructor(apiKey, basePath = BASE_PATH, apiVersion = "v1") {
|
|
18
|
-
this.apiVersion = "v1";
|
|
19
|
-
this.apiKey = apiKey;
|
|
20
|
-
this.basePath = basePath;
|
|
21
|
-
this.apiVersion = apiVersion;
|
|
22
|
-
}
|
|
23
|
-
scrapeAsync(scrapeRequest) {
|
|
24
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
25
|
-
const url = `${this.basePath}/${this.apiVersion}/scrape`;
|
|
26
|
-
const requestOptions = {
|
|
27
|
-
'method': 'POST',
|
|
28
|
-
'headers': {
|
|
29
|
-
'Content-Type': 'application/json',
|
|
30
|
-
'Authorization': `Bearer ${this.apiKey}`,
|
|
31
|
-
"User-Agent": "WebcrawlerAPI-NodeJS-Client"
|
|
32
|
-
},
|
|
33
|
-
'body': JSON.stringify(scrapeRequest),
|
|
34
|
-
};
|
|
35
|
-
const response = yield fetch(url, requestOptions);
|
|
36
|
-
if (response.ok) {
|
|
37
|
-
return response.json();
|
|
38
|
-
}
|
|
39
|
-
try {
|
|
40
|
-
const data = yield response.json();
|
|
41
|
-
throw new Error(`failed to scrape, response returned ${response.status} ${response.statusText}: ${data === null || data === void 0 ? void 0 : data.error}`);
|
|
42
|
-
}
|
|
43
|
-
catch (e) {
|
|
44
|
-
throw e;
|
|
45
|
-
}
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
scrapeWithMeta(scrapeRequest_1) {
|
|
49
|
-
return __awaiter(this, arguments, void 0, function* (scrapeRequest, maxPollingRetries = MaxPullRetries) {
|
|
50
|
-
const url = `${this.basePath}/${this.apiVersion}/scrape`;
|
|
51
|
-
const requestOptions = {
|
|
52
|
-
'method': 'POST',
|
|
53
|
-
'headers': {
|
|
54
|
-
'Content-Type': 'application/json',
|
|
55
|
-
'Authorization': `Bearer ${this.apiKey}`
|
|
56
|
-
},
|
|
57
|
-
'body': JSON.stringify(scrapeRequest),
|
|
58
|
-
};
|
|
59
|
-
const jobIdResponse = yield this.sendRequest(url, requestOptions);
|
|
60
|
-
if (jobIdResponse.id === '') {
|
|
61
|
-
throw new Error("Failed to fetch job status");
|
|
62
|
-
}
|
|
63
|
-
let delayIntervalMs = initialPullDelayMs;
|
|
64
|
-
for (let i = 0; i < maxPollingRetries; i++) {
|
|
65
|
-
yield new Promise(resolve => setTimeout(resolve, delayIntervalMs));
|
|
66
|
-
const scrapeResult = yield this.getScrapeResult(jobIdResponse.id);
|
|
67
|
-
if (scrapeRequest.debug) {
|
|
68
|
-
console.log(`Scrape result: ${JSON.stringify(scrapeResult)}`);
|
|
69
|
-
}
|
|
70
|
-
if (scrapeResult.status !== 'in_progress' && scrapeResult.status !== 'new') {
|
|
71
|
-
return scrapeResult;
|
|
72
|
-
}
|
|
73
|
-
if (scrapeResult.recommended_pull_delay_ms > 0) {
|
|
74
|
-
delayIntervalMs = scrapeResult.recommended_pull_delay_ms;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
throw new Error("Scraping took too long, please retry or increase the number of polling retries");
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
scrape(scrapeRequest_1) {
|
|
81
|
-
return __awaiter(this, arguments, void 0, function* (scrapeRequest, maxPollingRetries = MaxPullRetries) {
|
|
82
|
-
const scrapeResult = yield this.scrapeWithMeta(scrapeRequest, maxPollingRetries);
|
|
83
|
-
return scrapeResult.structured_data;
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
getScrapeResult(scrapeID) {
|
|
87
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
88
|
-
const url = `${this.basePath}/${this.apiVersion}/scrape/${scrapeID}`;
|
|
89
|
-
const requestOptions = {
|
|
90
|
-
'method': 'GET',
|
|
91
|
-
'headers': {
|
|
92
|
-
'Content-Type': 'application/json',
|
|
93
|
-
'Authorization': `Bearer ${this.apiKey}`,
|
|
94
|
-
"User-Agent": "WebcrawlerAPI-NodeJS-Client",
|
|
95
|
-
'Cache-Control': 'no-cache, no-store, must-revalidate',
|
|
96
|
-
'Pragma': 'no-cache',
|
|
97
|
-
'Expires': '0'
|
|
98
|
-
},
|
|
99
|
-
};
|
|
100
|
-
const response = yield fetch(url, requestOptions);
|
|
101
|
-
if (response.ok) {
|
|
102
|
-
return response.json();
|
|
103
|
-
}
|
|
104
|
-
try {
|
|
105
|
-
const data = yield response.json();
|
|
106
|
-
throw new Error(`failed to fetch job status ${response.status} ${response.statusText}: ${JSON.stringify(data)}`);
|
|
107
|
-
}
|
|
108
|
-
catch (e) {
|
|
109
|
-
throw new Error(`failed to fetch job status ${response.status} ${response.statusText}`);
|
|
110
|
-
}
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
crawl(crawlRequest) {
|
|
114
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
115
|
-
const url = `${this.basePath}/${this.apiVersion}/crawl`;
|
|
116
|
-
const requestOptions = {
|
|
117
|
-
'method': 'POST',
|
|
118
|
-
'headers': {
|
|
119
|
-
'Content-Type': 'application/json',
|
|
120
|
-
'Authorization': `Bearer ${this.apiKey}`,
|
|
121
|
-
"User-Agent": "WebcrawlerAPI-NodeJS-Client",
|
|
122
|
-
'Cache-Control': 'no-cache, no-store, must-revalidate',
|
|
123
|
-
'Pragma': 'no-cache',
|
|
124
|
-
'Expires': '0'
|
|
125
|
-
},
|
|
126
|
-
'body': JSON.stringify(crawlRequest),
|
|
127
|
-
};
|
|
128
|
-
const jobIdResponse = yield this.sendRequest(url, requestOptions);
|
|
129
|
-
if (jobIdResponse.id === '') {
|
|
130
|
-
throw new Error("Failed to fetch job status");
|
|
131
|
-
}
|
|
132
|
-
let delayIntervalMs = initialPullDelayMs;
|
|
133
|
-
for (let i = 0; i < MaxPullRetries; i++) {
|
|
134
|
-
yield new Promise(resolve => setTimeout(resolve, delayIntervalMs));
|
|
135
|
-
const timestamp = new Date().getTime();
|
|
136
|
-
const job = yield this.getJob(`${jobIdResponse.id}?t=${timestamp}`);
|
|
137
|
-
if (job.status !== 'in_progress' && job.status !== 'new') {
|
|
138
|
-
// Transform each job item to include getContent method
|
|
139
|
-
job.job_items = job.job_items.map(item => (Object.assign(Object.assign({}, item), { getContent: function () {
|
|
140
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
141
|
-
if (this.status !== 'done') {
|
|
142
|
-
return null;
|
|
143
|
-
}
|
|
144
|
-
let contentUrl;
|
|
145
|
-
switch (job.scrape_type) {
|
|
146
|
-
case 'html':
|
|
147
|
-
contentUrl = this.raw_content_url;
|
|
148
|
-
break;
|
|
149
|
-
case 'cleaned':
|
|
150
|
-
contentUrl = this.cleaned_content_url;
|
|
151
|
-
break;
|
|
152
|
-
case 'markdown':
|
|
153
|
-
contentUrl = this.markdown_content_url;
|
|
154
|
-
break;
|
|
155
|
-
}
|
|
156
|
-
if (!contentUrl) {
|
|
157
|
-
return null;
|
|
158
|
-
}
|
|
159
|
-
const response = yield fetch(contentUrl, {
|
|
160
|
-
headers: {
|
|
161
|
-
'Accept-Encoding': 'gzip, deflate, br',
|
|
162
|
-
'Accept': '*/*'
|
|
163
|
-
}
|
|
164
|
-
});
|
|
165
|
-
if (!response.ok) {
|
|
166
|
-
throw new Error(`Failed to fetch content: ${response.statusText}`);
|
|
167
|
-
}
|
|
168
|
-
return yield response.text();
|
|
169
|
-
});
|
|
170
|
-
} })));
|
|
171
|
-
return job;
|
|
172
|
-
}
|
|
173
|
-
if (job.recommended_pull_delay_ms > 0) {
|
|
174
|
-
delayIntervalMs = job.recommended_pull_delay_ms;
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
throw new Error("Crawling took too long, please retry or increase the number of polling retries");
|
|
178
|
-
});
|
|
179
|
-
}
|
|
180
|
-
crawlAsync(crawlRequest) {
|
|
181
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
182
|
-
const url = `${this.basePath}/${this.apiVersion}/crawl`;
|
|
183
|
-
const requestOptions = {
|
|
184
|
-
'method': 'POST',
|
|
185
|
-
'headers': {
|
|
186
|
-
'Content-Type': 'application/json',
|
|
187
|
-
'Authorization': `Bearer ${this.apiKey}`
|
|
188
|
-
},
|
|
189
|
-
'body': JSON.stringify(crawlRequest),
|
|
190
|
-
};
|
|
191
|
-
return yield this.sendRequest(url, requestOptions);
|
|
192
|
-
});
|
|
193
|
-
}
|
|
194
|
-
getJob(jobID) {
|
|
195
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
196
|
-
const url = `${this.basePath}/${this.apiVersion}/job/${jobID}`;
|
|
197
|
-
const requestOptions = {
|
|
198
|
-
'method': 'GET',
|
|
199
|
-
'headers': {
|
|
200
|
-
'Content-Type': 'application/json',
|
|
201
|
-
'Authorization': `Bearer ${this.apiKey}`,
|
|
202
|
-
"User-Agent": "WebcrawlerAPI-NodeJS-Client",
|
|
203
|
-
'Cache-Control': 'no-cache, no-store, must-revalidate',
|
|
204
|
-
'Pragma': 'no-cache',
|
|
205
|
-
'Expires': '0'
|
|
206
|
-
}
|
|
207
|
-
};
|
|
208
|
-
const response = yield fetch(url, requestOptions);
|
|
209
|
-
if (response.ok) {
|
|
210
|
-
return response.json();
|
|
211
|
-
}
|
|
212
|
-
try {
|
|
213
|
-
const data = yield response.json();
|
|
214
|
-
throw new Error(`failed to fetch job status ${response.status} ${response.statusText}: ${JSON.stringify(data)}`);
|
|
215
|
-
}
|
|
216
|
-
catch (e) {
|
|
217
|
-
throw new Error(`failed to fetch job status ${response.status} ${response.statusText}`);
|
|
218
|
-
}
|
|
219
|
-
});
|
|
220
|
-
}
|
|
221
|
-
sendRequest(url, requestOptions) {
|
|
222
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
223
|
-
let response;
|
|
224
|
-
try {
|
|
225
|
-
response = yield fetch(url, requestOptions);
|
|
226
|
-
}
|
|
227
|
-
catch (e) {
|
|
228
|
-
throw new Error(`Failed to send request: ${e}`);
|
|
229
|
-
}
|
|
230
|
-
if (!response.ok) {
|
|
231
|
-
const errorResponse = yield response.json();
|
|
232
|
-
throw new Error(`${JSON.stringify(errorResponse)}`);
|
|
233
|
-
}
|
|
234
|
-
return response.json();
|
|
235
|
-
});
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
exports.WebcrawlerClient = WebcrawlerClient;
|
package/dist/index.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "./api";
|
package/dist/index.js
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
-
};
|
|
16
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
__exportStar(require("./api"), exports);
|