webcrawlerapi-js 1.0.3
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 +60 -0
- package/api.ts +125 -0
- package/dist/api.d.ts +12 -0
- package/dist/api.js +124 -0
- package/dist/configuration.d.ts +16 -0
- package/dist/configuration.js +20 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +17 -0
- package/dist/model.d.ts +18 -0
- package/dist/model.js +2 -0
- package/index.ts +1 -0
- package/model.ts +20 -0
- package/package.json +26 -0
- package/tsconfig.json +17 -0
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,125 @@
|
|
|
1
|
+
import {ScrapeIDResponse, 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<ScrapeIDResponse> {
|
|
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 scrapeIDResponse: ScrapeIDResponse = await this.sendRequest(url, requestOptions);
|
|
57
|
+
|
|
58
|
+
if (scrapeIDResponse.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(scrapeIDResponse.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
|
+
private async sendRequest(url: string, requestOptions: any): Promise<any> {
|
|
110
|
+
let response: Response;
|
|
111
|
+
try {
|
|
112
|
+
response = await fetch(url, requestOptions);
|
|
113
|
+
} catch (e) {
|
|
114
|
+
throw new Error(`Failed to send request: ${e}`);
|
|
115
|
+
}
|
|
116
|
+
if (!response.ok) {
|
|
117
|
+
const errorResponse = await response.json();
|
|
118
|
+
throw new Error(`${JSON.stringify(errorResponse)}`);
|
|
119
|
+
}
|
|
120
|
+
return response.json();
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
|
package/dist/api.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ScrapeIDResponse, 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<ScrapeIDResponse>;
|
|
8
|
+
scrapeWithMeta(scrapeRequest: ScrapeRequest): Promise<ScrapeResponse>;
|
|
9
|
+
scrape(scrapeRequest: ScrapeRequest): Promise<ScrapeResponse>;
|
|
10
|
+
getScrapeResult(scrapeID: string): Promise<ScrapeResponse>;
|
|
11
|
+
private sendRequest;
|
|
12
|
+
}
|
package/dist/api.js
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
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 scrapeIDResponse = yield this.sendRequest(url, requestOptions);
|
|
59
|
+
if (scrapeIDResponse.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(scrapeIDResponse.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
|
+
sendRequest(url, requestOptions) {
|
|
108
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
109
|
+
let response;
|
|
110
|
+
try {
|
|
111
|
+
response = yield fetch(url, requestOptions);
|
|
112
|
+
}
|
|
113
|
+
catch (e) {
|
|
114
|
+
throw new Error(`Failed to send request: ${e}`);
|
|
115
|
+
}
|
|
116
|
+
if (!response.ok) {
|
|
117
|
+
const errorResponse = yield response.json();
|
|
118
|
+
throw new Error(`${JSON.stringify(errorResponse)}`);
|
|
119
|
+
}
|
|
120
|
+
return response.json();
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
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;
|
package/dist/index.d.ts
ADDED
|
@@ -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);
|
package/dist/model.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface ScrapeRequest {
|
|
2
|
+
input: any;
|
|
3
|
+
crawler_id: string;
|
|
4
|
+
max_retries?: number;
|
|
5
|
+
debug?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export interface ScrapeIDResponse {
|
|
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
|
+
}
|
package/dist/model.js
ADDED
package/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./api";
|
package/model.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface ScrapeRequest {
|
|
2
|
+
input: any;
|
|
3
|
+
crawler_id: string;
|
|
4
|
+
max_retries?: number;
|
|
5
|
+
debug?: boolean;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface ScrapeIDResponse {
|
|
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
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "webcrawlerapi-js",
|
|
3
|
+
"version": "1.0.3",
|
|
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
|
+
}
|