webcrawlerapi-js 1.0.7 → 1.0.9
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 +8 -2
- package/api.ts +58 -6
- package/constants.ts +14 -0
- package/dist/api.js +52 -6
- package/dist/constants.d.ts +13 -0
- package/dist/constants.js +16 -0
- package/dist/model.d.ts +3 -0
- package/model.ts +3 -0
- package/package.json +7 -6
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
|
|
@@ -29,6 +29,11 @@ async function main() {
|
|
|
29
29
|
"scrape_type": "markdown"
|
|
30
30
|
}
|
|
31
31
|
)
|
|
32
|
+
for (const item of syncJob.job_items) {
|
|
33
|
+
item.getContent().then((content) => {
|
|
34
|
+
console.log(content.slice(0, 100));
|
|
35
|
+
})
|
|
36
|
+
}
|
|
32
37
|
console.log(syncJob);
|
|
33
38
|
|
|
34
39
|
// or async - get the job id and then poll the job status and get the data
|
|
@@ -74,6 +79,7 @@ main().catch(console.error);
|
|
|
74
79
|
status: 'new',
|
|
75
80
|
title: '',
|
|
76
81
|
last_error: '',
|
|
82
|
+
error_code: '',
|
|
77
83
|
created_at: '2024-12-28T21:36:04.468Z',
|
|
78
84
|
updated_at: '2024-12-28T21:36:04.435Z',
|
|
79
85
|
cost: 0,
|
package/api.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {CrawlRequest, Job, JobId, ScrapeRequest, ScrapeResponse} from "./model";
|
|
2
|
+
import { JobStatus } from "./constants";
|
|
2
3
|
|
|
3
4
|
const BASE_PATH = "https://api.webcrawlerapi.com"
|
|
4
5
|
const initialPullDelayMs = 2000
|
|
@@ -67,7 +68,7 @@ export class WebcrawlerClient {
|
|
|
67
68
|
if (scrapeRequest.debug) {
|
|
68
69
|
console.log(`Scrape result: ${JSON.stringify(scrapeResult)}`);
|
|
69
70
|
}
|
|
70
|
-
if (scrapeResult.status !==
|
|
71
|
+
if (scrapeResult.status !== JobStatus.IN_PROGRESS && scrapeResult.status !== JobStatus.NEW) {
|
|
71
72
|
return scrapeResult;
|
|
72
73
|
}
|
|
73
74
|
if (scrapeResult.recommended_pull_delay_ms > 0) {
|
|
@@ -87,8 +88,12 @@ export class WebcrawlerClient {
|
|
|
87
88
|
const requestOptions = {
|
|
88
89
|
'method': 'GET',
|
|
89
90
|
'headers': {
|
|
91
|
+
'Content-Type': 'application/json',
|
|
90
92
|
'Authorization': `Bearer ${this.apiKey}`,
|
|
91
|
-
"User-Agent": "WebcrawlerAPI-NodeJS-Client"
|
|
93
|
+
"User-Agent": "WebcrawlerAPI-NodeJS-Client",
|
|
94
|
+
'Cache-Control': 'no-cache, no-store, must-revalidate',
|
|
95
|
+
'Pragma': 'no-cache',
|
|
96
|
+
'Expires': '0'
|
|
92
97
|
},
|
|
93
98
|
};
|
|
94
99
|
const response = await fetch(url, requestOptions);
|
|
@@ -116,7 +121,10 @@ export class WebcrawlerClient {
|
|
|
116
121
|
'headers': {
|
|
117
122
|
'Content-Type': 'application/json',
|
|
118
123
|
'Authorization': `Bearer ${this.apiKey}`,
|
|
119
|
-
"User-Agent": "WebcrawlerAPI-NodeJS-Client"
|
|
124
|
+
"User-Agent": "WebcrawlerAPI-NodeJS-Client",
|
|
125
|
+
'Cache-Control': 'no-cache, no-store, must-revalidate',
|
|
126
|
+
'Pragma': 'no-cache',
|
|
127
|
+
'Expires': '0'
|
|
120
128
|
},
|
|
121
129
|
'body': JSON.stringify(crawlRequest),
|
|
122
130
|
};
|
|
@@ -130,14 +138,55 @@ export class WebcrawlerClient {
|
|
|
130
138
|
let delayIntervalMs = initialPullDelayMs;
|
|
131
139
|
for (let i = 0; i < MaxPullRetries; i++) {
|
|
132
140
|
await new Promise(resolve => setTimeout(resolve, delayIntervalMs));
|
|
133
|
-
const
|
|
134
|
-
|
|
141
|
+
const timestamp = new Date().getTime();
|
|
142
|
+
const job = await this.getJob(`${jobIdResponse.id}?t=${timestamp}`);
|
|
143
|
+
if (job.status !== JobStatus.IN_PROGRESS && job.status !== JobStatus.NEW) {
|
|
144
|
+
// Transform each job item to include getContent method
|
|
145
|
+
job.job_items = job.job_items.map(item => ({
|
|
146
|
+
...item,
|
|
147
|
+
getContent: async function(): Promise<string | null> {
|
|
148
|
+
if (job.status !== JobStatus.DONE || this.status !== JobStatus.DONE) {
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
let contentUrl: string | undefined;
|
|
153
|
+
switch (job.scrape_type) {
|
|
154
|
+
case 'html':
|
|
155
|
+
contentUrl = this.raw_content_url;
|
|
156
|
+
break;
|
|
157
|
+
case 'cleaned':
|
|
158
|
+
contentUrl = this.cleaned_content_url;
|
|
159
|
+
break;
|
|
160
|
+
case 'markdown':
|
|
161
|
+
contentUrl = this.markdown_content_url;
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (!contentUrl) {
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const response = await fetch(contentUrl, {
|
|
170
|
+
headers: {
|
|
171
|
+
'Accept-Encoding': 'gzip, deflate, br',
|
|
172
|
+
'Accept': '*/*'
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
if (!response.ok) {
|
|
177
|
+
throw new Error(`Failed to fetch content: ${response.statusText}`);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return await response.text();
|
|
181
|
+
}
|
|
182
|
+
}));
|
|
135
183
|
return job;
|
|
136
184
|
}
|
|
137
185
|
if (job.recommended_pull_delay_ms > 0) {
|
|
138
186
|
delayIntervalMs = job.recommended_pull_delay_ms;
|
|
139
187
|
}
|
|
140
188
|
}
|
|
189
|
+
throw new Error("Crawling took too long, please retry or increase the number of polling retries");
|
|
141
190
|
}
|
|
142
191
|
|
|
143
192
|
public async crawlAsync(crawlRequest: CrawlRequest): Promise<JobId> {
|
|
@@ -162,7 +211,10 @@ export class WebcrawlerClient {
|
|
|
162
211
|
'headers': {
|
|
163
212
|
'Content-Type': 'application/json',
|
|
164
213
|
'Authorization': `Bearer ${this.apiKey}`,
|
|
165
|
-
"User-Agent": "WebcrawlerAPI-NodeJS-Client"
|
|
214
|
+
"User-Agent": "WebcrawlerAPI-NodeJS-Client",
|
|
215
|
+
'Cache-Control': 'no-cache, no-store, must-revalidate',
|
|
216
|
+
'Pragma': 'no-cache',
|
|
217
|
+
'Expires': '0'
|
|
166
218
|
}
|
|
167
219
|
}
|
|
168
220
|
const response = await fetch(url, requestOptions);
|
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;
|
package/dist/api.js
CHANGED
|
@@ -10,6 +10,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.WebcrawlerClient = void 0;
|
|
13
|
+
const constants_1 = require("./constants");
|
|
13
14
|
const BASE_PATH = "https://api.webcrawlerapi.com";
|
|
14
15
|
const initialPullDelayMs = 2000;
|
|
15
16
|
const MaxPullRetries = 100;
|
|
@@ -67,7 +68,7 @@ class WebcrawlerClient {
|
|
|
67
68
|
if (scrapeRequest.debug) {
|
|
68
69
|
console.log(`Scrape result: ${JSON.stringify(scrapeResult)}`);
|
|
69
70
|
}
|
|
70
|
-
if (scrapeResult.status !==
|
|
71
|
+
if (scrapeResult.status !== constants_1.JobStatus.IN_PROGRESS && scrapeResult.status !== constants_1.JobStatus.NEW) {
|
|
71
72
|
return scrapeResult;
|
|
72
73
|
}
|
|
73
74
|
if (scrapeResult.recommended_pull_delay_ms > 0) {
|
|
@@ -89,8 +90,12 @@ class WebcrawlerClient {
|
|
|
89
90
|
const requestOptions = {
|
|
90
91
|
'method': 'GET',
|
|
91
92
|
'headers': {
|
|
93
|
+
'Content-Type': 'application/json',
|
|
92
94
|
'Authorization': `Bearer ${this.apiKey}`,
|
|
93
|
-
"User-Agent": "WebcrawlerAPI-NodeJS-Client"
|
|
95
|
+
"User-Agent": "WebcrawlerAPI-NodeJS-Client",
|
|
96
|
+
'Cache-Control': 'no-cache, no-store, must-revalidate',
|
|
97
|
+
'Pragma': 'no-cache',
|
|
98
|
+
'Expires': '0'
|
|
94
99
|
},
|
|
95
100
|
};
|
|
96
101
|
const response = yield fetch(url, requestOptions);
|
|
@@ -114,7 +119,10 @@ class WebcrawlerClient {
|
|
|
114
119
|
'headers': {
|
|
115
120
|
'Content-Type': 'application/json',
|
|
116
121
|
'Authorization': `Bearer ${this.apiKey}`,
|
|
117
|
-
"User-Agent": "WebcrawlerAPI-NodeJS-Client"
|
|
122
|
+
"User-Agent": "WebcrawlerAPI-NodeJS-Client",
|
|
123
|
+
'Cache-Control': 'no-cache, no-store, must-revalidate',
|
|
124
|
+
'Pragma': 'no-cache',
|
|
125
|
+
'Expires': '0'
|
|
118
126
|
},
|
|
119
127
|
'body': JSON.stringify(crawlRequest),
|
|
120
128
|
};
|
|
@@ -125,14 +133,49 @@ class WebcrawlerClient {
|
|
|
125
133
|
let delayIntervalMs = initialPullDelayMs;
|
|
126
134
|
for (let i = 0; i < MaxPullRetries; i++) {
|
|
127
135
|
yield new Promise(resolve => setTimeout(resolve, delayIntervalMs));
|
|
128
|
-
const
|
|
129
|
-
|
|
136
|
+
const timestamp = new Date().getTime();
|
|
137
|
+
const job = yield this.getJob(`${jobIdResponse.id}?t=${timestamp}`);
|
|
138
|
+
if (job.status !== constants_1.JobStatus.IN_PROGRESS && job.status !== constants_1.JobStatus.NEW) {
|
|
139
|
+
// Transform each job item to include getContent method
|
|
140
|
+
job.job_items = job.job_items.map(item => (Object.assign(Object.assign({}, item), { getContent: function () {
|
|
141
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
142
|
+
if (job.status !== constants_1.JobStatus.DONE || this.status !== constants_1.JobStatus.DONE) {
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
let contentUrl;
|
|
146
|
+
switch (job.scrape_type) {
|
|
147
|
+
case 'html':
|
|
148
|
+
contentUrl = this.raw_content_url;
|
|
149
|
+
break;
|
|
150
|
+
case 'cleaned':
|
|
151
|
+
contentUrl = this.cleaned_content_url;
|
|
152
|
+
break;
|
|
153
|
+
case 'markdown':
|
|
154
|
+
contentUrl = this.markdown_content_url;
|
|
155
|
+
break;
|
|
156
|
+
}
|
|
157
|
+
if (!contentUrl) {
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
const response = yield fetch(contentUrl, {
|
|
161
|
+
headers: {
|
|
162
|
+
'Accept-Encoding': 'gzip, deflate, br',
|
|
163
|
+
'Accept': '*/*'
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
if (!response.ok) {
|
|
167
|
+
throw new Error(`Failed to fetch content: ${response.statusText}`);
|
|
168
|
+
}
|
|
169
|
+
return yield response.text();
|
|
170
|
+
});
|
|
171
|
+
} })));
|
|
130
172
|
return job;
|
|
131
173
|
}
|
|
132
174
|
if (job.recommended_pull_delay_ms > 0) {
|
|
133
175
|
delayIntervalMs = job.recommended_pull_delay_ms;
|
|
134
176
|
}
|
|
135
177
|
}
|
|
178
|
+
throw new Error("Crawling took too long, please retry or increase the number of polling retries");
|
|
136
179
|
});
|
|
137
180
|
}
|
|
138
181
|
crawlAsync(crawlRequest) {
|
|
@@ -157,7 +200,10 @@ class WebcrawlerClient {
|
|
|
157
200
|
'headers': {
|
|
158
201
|
'Content-Type': 'application/json',
|
|
159
202
|
'Authorization': `Bearer ${this.apiKey}`,
|
|
160
|
-
"User-Agent": "WebcrawlerAPI-NodeJS-Client"
|
|
203
|
+
"User-Agent": "WebcrawlerAPI-NodeJS-Client",
|
|
204
|
+
'Cache-Control': 'no-cache, no-store, must-revalidate',
|
|
205
|
+
'Pragma': 'no-cache',
|
|
206
|
+
'Expires': '0'
|
|
161
207
|
}
|
|
162
208
|
};
|
|
163
209
|
const response = yield fetch(url, requestOptions);
|
|
@@ -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/model.d.ts
CHANGED
package/model.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "webcrawlerapi-js",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.9",
|
|
4
|
+
|
|
4
5
|
"description": "JS client for WecrawlerAPI",
|
|
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
|
+
}
|