webcrawlerapi-js 1.0.4

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 ADDED
@@ -0,0 +1,60 @@
1
+ # JS client for WebcrawlerAPI scrapers
2
+
3
+ Official client for [WebcrawlerAPI](https://webcrawlerapi.com/) scrapers.
4
+
5
+ ## Installation
6
+ Install WebcrawlerAPI js package:
7
+
8
+ `npm i webcrawlerapi-js`
9
+
10
+ ## Preparation
11
+ 1. Register to [dashboard|https://dash.webcrawlerapi.com/].
12
+ 2. Get an [Access Key](https://dash.webcrawlerapi.com/access).
13
+
14
+ ## Request example
15
+
16
+ ```javascript
17
+ const webcrawlerapi = require('webcrawlerapi-js');
18
+
19
+ async function main() {
20
+ const client = new webcrawlerapi.WebcrawlerClient(
21
+ "YOUR API KEY HERE"
22
+ )
23
+ const response = await client.scrape({
24
+ input: {
25
+ "url": "https://www.funda.nl/detail/koop/heerhugowaard/huis-govert-flinckplantsoen-1/89968455/"
26
+ },
27
+ crawler_id: "webcrawler/funda",
28
+ })
29
+ console.log(response)
30
+ }
31
+
32
+ main().catch(console.error);
33
+ ```
34
+
35
+ ## Response example
36
+ ```json
37
+ {
38
+ city: 'Heerhugowaard',
39
+ price: 325000,
40
+ images: [ 'https://cloud.funda.nl/valentina_media/191/215/183_2160.jpg' ],
41
+ status: 'inonderhandeling',
42
+ videos: [],
43
+ address: 'Govert Flinckplantsoen 1',
44
+ country: 'Nederland',
45
+ province: 'Noord-Holland',
46
+ plot_area: '183 m²',
47
+ post_code: '1701NH',
48
+ description: 'De woning is met liefde en zorg 53 jaar bewoond door...',
49
+ living_area: 127,
50
+ house_number: 1,
51
+ energie_label: 'd',
52
+ property_type: 'woonhuis',
53
+ publication_date: '2024-05-28T00:00:00',
54
+ number_of_bedrooms: 4,
55
+ coordinates_latitude: 52.67685,
56
+ year_of_construction: 1971,
57
+ coordinates_longitude: 4.8560443,
58
+ house_number_extension: ''
59
+ }
60
+ ```
package/api.ts ADDED
@@ -0,0 +1,198 @@
1
+ import {CrawlRequest, Job, JobId, ScrapeRequest, ScrapeResponse} from "./model";
2
+
3
+ const BASE_PATH = "https://api.webcrawlerapi.com"
4
+ const initialPullDelayMs = 2000
5
+ const MaxPullRetries = 100
6
+
7
+ export class WebcrawlerClient {
8
+ protected apiVersion: string = "v1";
9
+ protected apiKey: string
10
+ protected basePath: string
11
+
12
+ constructor(apiKey: string, basePath: string = BASE_PATH, apiVersion: string = "v1") {
13
+ this.apiKey = apiKey ;
14
+ this.basePath = basePath;
15
+ this.apiVersion = apiVersion;
16
+ }
17
+
18
+ public async scrapeAsync(scrapeRequest: ScrapeRequest): Promise<JobId> {
19
+ const url = `${this.basePath}/${this.apiVersion}/scrape`;
20
+
21
+ const requestOptions = {
22
+ 'method': 'POST',
23
+ 'headers': {
24
+ 'Content-Type': 'application/json',
25
+ 'Authorization': `Bearer ${this.apiKey}`
26
+ },
27
+ 'body': JSON.stringify(scrapeRequest),
28
+ };
29
+
30
+ const response = await fetch(url, requestOptions);
31
+ if (response.ok) {
32
+ return response.json();
33
+ }
34
+ try {
35
+ const data = await response.json();
36
+ throw new Error(
37
+ `failed to scrape, response returned ${response.status} ${response.statusText}: ${data?.error}`
38
+ );
39
+ } catch (e) {
40
+ throw e;
41
+ }
42
+ }
43
+
44
+ public async scrapeWithMeta(scrapeRequest: ScrapeRequest): Promise<ScrapeResponse> {
45
+ const url = `${this.basePath}/${this.apiVersion}/scrape`;
46
+
47
+ const requestOptions = {
48
+ 'method': 'POST',
49
+ 'headers': {
50
+ 'Content-Type': 'application/json',
51
+ 'Authorization': `Bearer ${this.apiKey}`
52
+ },
53
+ 'body': JSON.stringify(scrapeRequest),
54
+ };
55
+
56
+ const jobIdResponse: JobId = await this.sendRequest(url, requestOptions);
57
+
58
+ if (jobIdResponse.id === '') {
59
+ throw new Error("Failed to fetch job status");
60
+ }
61
+
62
+ let delayIntervalMs = initialPullDelayMs;
63
+ for (let i = 0; i < MaxPullRetries; i++) {
64
+ await new Promise(resolve => setTimeout(resolve, delayIntervalMs));
65
+ const scrapeResult = await this.getScrapeResult(jobIdResponse.id);
66
+ if (scrapeRequest.debug) {
67
+ console.log(`Scrape result: ${JSON.stringify(scrapeResult)}`);
68
+ }
69
+ if (scrapeResult.status !== 'in_progress' && scrapeResult.status !== 'new') {
70
+ return scrapeResult;
71
+ }
72
+ if (scrapeResult.recommended_pull_delay_ms > 0) {
73
+ delayIntervalMs = scrapeResult.recommended_pull_delay_ms;
74
+ }
75
+ }
76
+ throw new Error("Scraping took too long, please retry");
77
+ }
78
+
79
+ public async scrape(scrapeRequest: ScrapeRequest): Promise<ScrapeResponse> {
80
+ const scrapeResult = await this.scrapeWithMeta(scrapeRequest);
81
+ return scrapeResult.structured_data;
82
+ }
83
+
84
+ public async getScrapeResult(scrapeID: string): Promise<ScrapeResponse> {
85
+ const url = `${this.basePath}/${this.apiVersion}/scrape/${scrapeID}`;
86
+ const requestOptions = {
87
+ 'method': 'GET',
88
+ 'headers': {
89
+ 'Authorization': `Bearer ${this.apiKey}`,
90
+ },
91
+ };
92
+ const response = await fetch(url, requestOptions);
93
+ if (response.ok) {
94
+ return response.json();
95
+ }
96
+
97
+ try {
98
+ const data = await response.json();
99
+ throw new Error(
100
+ `failed to fetch job status ${response.status} ${response.statusText}: ${JSON.stringify(data)}`
101
+ );
102
+ } catch (e) {
103
+ throw new Error(
104
+ `failed to fetch job status ${response.status} ${response.statusText}`
105
+ );
106
+ }
107
+ }
108
+
109
+ public async crawl(crawlRequest: CrawlRequest): Promise<Job> {
110
+ const url = `${this.basePath}/${this.apiVersion}/crawl`;
111
+
112
+ const requestOptions = {
113
+ 'method': 'POST',
114
+ 'headers': {
115
+ 'Content-Type': 'application/json',
116
+ 'Authorization': `Bearer ${this.apiKey}`
117
+ },
118
+ 'body': JSON.stringify(crawlRequest),
119
+ };
120
+
121
+ const jobIdResponse: JobId = await this.sendRequest(url, requestOptions);
122
+
123
+ if (jobIdResponse.id === '') {
124
+ throw new Error("Failed to fetch job status");
125
+ }
126
+
127
+ let delayIntervalMs = initialPullDelayMs;
128
+ for (let i = 0; i < MaxPullRetries; i++) {
129
+ await new Promise(resolve => setTimeout(resolve, delayIntervalMs));
130
+ const job = await this.getJob(jobIdResponse.id);
131
+ if (job.status !== 'in_progress' && job.status !== 'new') {
132
+ return job;
133
+ }
134
+ if (job.recommended_pull_delay_ms > 0) {
135
+ delayIntervalMs = job.recommended_pull_delay_ms;
136
+ }
137
+ }
138
+ }
139
+
140
+ public async crawlAsync(crawlRequest: CrawlRequest): Promise<JobId> {
141
+ const url = `${this.basePath}/${this.apiVersion}/crawl`;
142
+
143
+ const requestOptions = {
144
+ 'method': 'POST',
145
+ 'headers': {
146
+ 'Content-Type': 'application/json',
147
+ 'Authorization': `Bearer ${this.apiKey}`
148
+ },
149
+ 'body': JSON.stringify(crawlRequest),
150
+ };
151
+
152
+ return await this.sendRequest(url, requestOptions);
153
+ }
154
+
155
+ public async getJob(jobID: string): Promise<Job> {
156
+ const url = `${this.basePath}/${this.apiVersion}/job/${jobID}`;
157
+ const requestOptions = {
158
+ 'method': 'GET',
159
+ 'headers': {
160
+ 'Content-Type': 'application/json',
161
+ 'Authorization': `Bearer ${this.apiKey}`
162
+ }
163
+ }
164
+ const response = await fetch(url, requestOptions);
165
+ if (response.ok) {
166
+ return response.json();
167
+ }
168
+
169
+ try {
170
+ const data = await response.json();
171
+ throw new Error(
172
+ `failed to fetch job status ${response.status} ${response.statusText}: ${JSON.stringify(data)}`
173
+ );
174
+ } catch (e) {
175
+ throw new Error(
176
+ `failed to fetch job status ${response.status} ${response.statusText}`
177
+ );
178
+ }
179
+ }
180
+
181
+
182
+ private async sendRequest(url: string, requestOptions: any): Promise<any> {
183
+ let response: Response;
184
+ try {
185
+ response = await fetch(url, requestOptions);
186
+ } catch (e) {
187
+ throw new Error(`Failed to send request: ${e}`);
188
+ }
189
+ if (!response.ok) {
190
+ const errorResponse = await response.json();
191
+ throw new Error(`${JSON.stringify(errorResponse)}`);
192
+ }
193
+ return response.json();
194
+ }
195
+ }
196
+
197
+
198
+
package/dist/api.d.ts ADDED
@@ -0,0 +1,15 @@
1
+ import { CrawlRequest, Job, JobId, ScrapeRequest, ScrapeResponse } from "./model";
2
+ export declare class WebcrawlerClient {
3
+ protected apiVersion: string;
4
+ protected apiKey: string;
5
+ protected basePath: string;
6
+ constructor(apiKey: string, basePath?: string, apiVersion?: string);
7
+ scrapeAsync(scrapeRequest: ScrapeRequest): Promise<JobId>;
8
+ scrapeWithMeta(scrapeRequest: ScrapeRequest): Promise<ScrapeResponse>;
9
+ scrape(scrapeRequest: ScrapeRequest): Promise<ScrapeResponse>;
10
+ getScrapeResult(scrapeID: string): Promise<ScrapeResponse>;
11
+ crawl(crawlRequest: CrawlRequest): Promise<Job>;
12
+ crawlAsync(crawlRequest: CrawlRequest): Promise<JobId>;
13
+ getJob(jobID: string): Promise<Job>;
14
+ private sendRequest;
15
+ }
package/dist/api.js ADDED
@@ -0,0 +1,190 @@
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
+ },
32
+ 'body': JSON.stringify(scrapeRequest),
33
+ };
34
+ const response = yield fetch(url, requestOptions);
35
+ if (response.ok) {
36
+ return response.json();
37
+ }
38
+ try {
39
+ const data = yield response.json();
40
+ throw new Error(`failed to scrape, response returned ${response.status} ${response.statusText}: ${data === null || data === void 0 ? void 0 : data.error}`);
41
+ }
42
+ catch (e) {
43
+ throw e;
44
+ }
45
+ });
46
+ }
47
+ scrapeWithMeta(scrapeRequest) {
48
+ return __awaiter(this, void 0, void 0, function* () {
49
+ const url = `${this.basePath}/${this.apiVersion}/scrape`;
50
+ const requestOptions = {
51
+ 'method': 'POST',
52
+ 'headers': {
53
+ 'Content-Type': 'application/json',
54
+ 'Authorization': `Bearer ${this.apiKey}`
55
+ },
56
+ 'body': JSON.stringify(scrapeRequest),
57
+ };
58
+ const jobIdResponse = yield this.sendRequest(url, requestOptions);
59
+ if (jobIdResponse.id === '') {
60
+ throw new Error("Failed to fetch job status");
61
+ }
62
+ let delayIntervalMs = initialPullDelayMs;
63
+ for (let i = 0; i < MaxPullRetries; i++) {
64
+ yield new Promise(resolve => setTimeout(resolve, delayIntervalMs));
65
+ const scrapeResult = yield this.getScrapeResult(jobIdResponse.id);
66
+ if (scrapeRequest.debug) {
67
+ console.log(`Scrape result: ${JSON.stringify(scrapeResult)}`);
68
+ }
69
+ if (scrapeResult.status !== 'in_progress' && scrapeResult.status !== 'new') {
70
+ return scrapeResult;
71
+ }
72
+ if (scrapeResult.recommended_pull_delay_ms > 0) {
73
+ delayIntervalMs = scrapeResult.recommended_pull_delay_ms;
74
+ }
75
+ }
76
+ throw new Error("Scraping took too long, please retry");
77
+ });
78
+ }
79
+ scrape(scrapeRequest) {
80
+ return __awaiter(this, void 0, void 0, function* () {
81
+ const scrapeResult = yield this.scrapeWithMeta(scrapeRequest);
82
+ return scrapeResult.structured_data;
83
+ });
84
+ }
85
+ getScrapeResult(scrapeID) {
86
+ return __awaiter(this, void 0, void 0, function* () {
87
+ const url = `${this.basePath}/${this.apiVersion}/scrape/${scrapeID}`;
88
+ const requestOptions = {
89
+ 'method': 'GET',
90
+ 'headers': {
91
+ 'Authorization': `Bearer ${this.apiKey}`,
92
+ },
93
+ };
94
+ const response = yield fetch(url, requestOptions);
95
+ if (response.ok) {
96
+ return response.json();
97
+ }
98
+ try {
99
+ const data = yield response.json();
100
+ throw new Error(`failed to fetch job status ${response.status} ${response.statusText}: ${JSON.stringify(data)}`);
101
+ }
102
+ catch (e) {
103
+ throw new Error(`failed to fetch job status ${response.status} ${response.statusText}`);
104
+ }
105
+ });
106
+ }
107
+ crawl(crawlRequest) {
108
+ return __awaiter(this, void 0, void 0, function* () {
109
+ const url = `${this.basePath}/${this.apiVersion}/crawl`;
110
+ const requestOptions = {
111
+ 'method': 'POST',
112
+ 'headers': {
113
+ 'Content-Type': 'application/json',
114
+ 'Authorization': `Bearer ${this.apiKey}`
115
+ },
116
+ 'body': JSON.stringify(crawlRequest),
117
+ };
118
+ const jobIdResponse = yield this.sendRequest(url, requestOptions);
119
+ if (jobIdResponse.id === '') {
120
+ throw new Error("Failed to fetch job status");
121
+ }
122
+ let delayIntervalMs = initialPullDelayMs;
123
+ for (let i = 0; i < MaxPullRetries; i++) {
124
+ yield new Promise(resolve => setTimeout(resolve, delayIntervalMs));
125
+ const job = yield this.getJob(jobIdResponse.id);
126
+ if (job.status !== 'in_progress' && job.status !== 'new') {
127
+ return job;
128
+ }
129
+ if (job.recommended_pull_delay_ms > 0) {
130
+ delayIntervalMs = job.recommended_pull_delay_ms;
131
+ }
132
+ }
133
+ });
134
+ }
135
+ crawlAsync(crawlRequest) {
136
+ return __awaiter(this, void 0, void 0, function* () {
137
+ const url = `${this.basePath}/${this.apiVersion}/crawl`;
138
+ const requestOptions = {
139
+ 'method': 'POST',
140
+ 'headers': {
141
+ 'Content-Type': 'application/json',
142
+ 'Authorization': `Bearer ${this.apiKey}`
143
+ },
144
+ 'body': JSON.stringify(crawlRequest),
145
+ };
146
+ return yield this.sendRequest(url, requestOptions);
147
+ });
148
+ }
149
+ getJob(jobID) {
150
+ return __awaiter(this, void 0, void 0, function* () {
151
+ const url = `${this.basePath}/${this.apiVersion}/job/${jobID}`;
152
+ console.log(url);
153
+ const requestOptions = {
154
+ 'method': 'GET',
155
+ 'headers': {
156
+ 'Content-Type': 'application/json',
157
+ 'Authorization': `Bearer ${this.apiKey}`
158
+ }
159
+ };
160
+ const response = yield fetch(url, requestOptions);
161
+ if (response.ok) {
162
+ return response.json();
163
+ }
164
+ try {
165
+ const data = yield response.json();
166
+ throw new Error(`failed to fetch job status ${response.status} ${response.statusText}: ${JSON.stringify(data)}`);
167
+ }
168
+ catch (e) {
169
+ throw new Error(`failed to fetch job status ${response.status} ${response.statusText}`);
170
+ }
171
+ });
172
+ }
173
+ sendRequest(url, requestOptions) {
174
+ return __awaiter(this, void 0, void 0, function* () {
175
+ let response;
176
+ try {
177
+ response = yield fetch(url, requestOptions);
178
+ }
179
+ catch (e) {
180
+ throw new Error(`Failed to send request: ${e}`);
181
+ }
182
+ if (!response.ok) {
183
+ const errorResponse = yield response.json();
184
+ throw new Error(`${JSON.stringify(errorResponse)}`);
185
+ }
186
+ return response.json();
187
+ });
188
+ }
189
+ }
190
+ exports.WebcrawlerClient = WebcrawlerClient;
@@ -0,0 +1,16 @@
1
+ export interface ConfigurationParameters {
2
+ apiKey?: string;
3
+ basePath?: string;
4
+ apiVersion?: string;
5
+ }
6
+ export declare class Configuration {
7
+ /**
8
+ * Base options for http call
9
+ */
10
+ baseOptions?: any;
11
+ /**
12
+ * API version, for example: "v1"
13
+ */
14
+ apiVersion: string;
15
+ constructor(param?: ConfigurationParameters);
16
+ }
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Configuration = void 0;
4
+ const packageJson = require("../package.json");
5
+ class Configuration {
6
+ constructor(param = {}) {
7
+ /**
8
+ * API version, for example: "v1"
9
+ */
10
+ this.apiVersion = "v1";
11
+ this.apiVersion = param.apiVersion;
12
+ if (!this.baseOptions) {
13
+ this.baseOptions = {};
14
+ }
15
+ this.baseOptions = {
16
+ headers: Object.assign({ 'User-Agent': `webcrawlerapi-js/${packageJson.version}`, 'Content-Type': 'application/json' }, this.baseOptions.headers)
17
+ };
18
+ }
19
+ }
20
+ exports.Configuration = Configuration;
@@ -0,0 +1 @@
1
+ export * from "./api";
package/dist/index.js ADDED
@@ -0,0 +1,17 @@
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);
@@ -0,0 +1,58 @@
1
+ export interface ScrapeRequest {
2
+ input: any;
3
+ crawler_id: string;
4
+ max_retries?: number;
5
+ debug?: boolean;
6
+ }
7
+ export interface JobId {
8
+ id: string;
9
+ }
10
+ export interface ScrapeResponse {
11
+ id: string;
12
+ url: string;
13
+ status: any;
14
+ page_status_code: number;
15
+ created_at: string;
16
+ structured_data: any;
17
+ recommended_pull_delay_ms: number;
18
+ }
19
+ export interface CrawlRequest {
20
+ url: string;
21
+ items_limit?: number;
22
+ scrape_type?: string;
23
+ whitelist_regexp?: string;
24
+ blacklist_regexp?: string;
25
+ allow_subdomains?: boolean;
26
+ webhook_url?: string;
27
+ }
28
+ export interface Job {
29
+ id: string;
30
+ org_id: string;
31
+ url: string;
32
+ status: string;
33
+ scrape_type: string;
34
+ whitelist_regexp: string;
35
+ blacklist_regexp: string;
36
+ allow_subdomains: boolean;
37
+ items_limit: number;
38
+ created_at: string;
39
+ finished_at: string;
40
+ updated_at: string;
41
+ webhook_url: string;
42
+ recommended_pull_delay_ms: number;
43
+ job_items: JobItem[];
44
+ }
45
+ export interface JobItem {
46
+ id: string;
47
+ job_id: string;
48
+ original_url: string;
49
+ page_status_code: number;
50
+ markdown_content_url: string;
51
+ status: string;
52
+ title: string;
53
+ last_error: string;
54
+ created_at: string;
55
+ updated_at: string;
56
+ cost: number;
57
+ referred_url: string;
58
+ }
package/dist/model.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/index.ts ADDED
@@ -0,0 +1 @@
1
+ export * from "./api";
package/model.ts ADDED
@@ -0,0 +1,63 @@
1
+ export interface ScrapeRequest {
2
+ input: any;
3
+ crawler_id: string;
4
+ max_retries?: number;
5
+ debug?: boolean;
6
+ }
7
+
8
+ export interface JobId {
9
+ id: string;
10
+ }
11
+
12
+ export interface ScrapeResponse {
13
+ id: string;
14
+ url: string;
15
+ status: any;
16
+ page_status_code: number;
17
+ created_at: string;
18
+ structured_data: any;
19
+ recommended_pull_delay_ms: number;
20
+ }
21
+
22
+ export interface CrawlRequest {
23
+ url: string;
24
+ items_limit?: number;
25
+ scrape_type?: string;
26
+ whitelist_regexp?: string;
27
+ blacklist_regexp?: string;
28
+ allow_subdomains?: boolean;
29
+ webhook_url?: string;
30
+ }
31
+
32
+ export interface Job {
33
+ id: string;
34
+ org_id: string;
35
+ url: string;
36
+ status: string;
37
+ scrape_type: string;
38
+ whitelist_regexp: string;
39
+ blacklist_regexp: string;
40
+ allow_subdomains: boolean;
41
+ items_limit: number;
42
+ created_at: string;
43
+ finished_at: string;
44
+ updated_at: string;
45
+ webhook_url: string;
46
+ recommended_pull_delay_ms: number;
47
+ job_items: JobItem[];
48
+ }
49
+
50
+ export interface JobItem {
51
+ id: string;
52
+ job_id: string;
53
+ original_url: string;
54
+ page_status_code: number;
55
+ markdown_content_url: string;
56
+ status: string;
57
+ title: string;
58
+ last_error: string;
59
+ created_at: string;
60
+ updated_at: string;
61
+ cost: number;
62
+ referred_url: string;
63
+ }
package/package.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "webcrawlerapi-js",
3
+ "version": "1.0.4",
4
+ "description": "JS client for WecrawlerAPI",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "keywords": [
8
+ "scraping",
9
+ "scraper",
10
+ "crawler",
11
+ "crawling",
12
+ "webcrawler",
13
+ "webcrawling",
14
+ "ai"
15
+ ],
16
+ "devDependencies": {
17
+ "@types/node": "^22.4.0",
18
+ "typescript": "^5.5.4"
19
+ },
20
+ "author": "Andrew <support@webcrawlerapi.com>",
21
+ "license": "MIT",
22
+ "dependencies": {},
23
+ "scripts": {
24
+ "build": "tsc --outDir dist/"
25
+ }
26
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,17 @@
1
+ {
2
+ "compilerOptions": {
3
+ "declaration": true,
4
+ "target": "es6",
5
+ "module": "commonjs",
6
+ "noImplicitAny": true,
7
+ "outDir": "dist",
8
+ "rootDir": ".",
9
+ "typeRoots": [
10
+ "node_modules/@types"
11
+ ]
12
+ },
13
+ "exclude": [
14
+ "dist",
15
+ "node_modules"
16
+ ]
17
+ }