webcrawlerapi-js 1.1.7 → 2.0.1

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.
@@ -1,4 +1,4 @@
1
- import { CrawlRequest, Job, JobId, ScrapeRequest, ScrapeResponse, Action } from "./model";
1
+ import { CrawlRequest, Job, JobId, ScrapeRequest, ScrapeResponse, ScrapeResponseError, ScrapeId, Action } from "./model";
2
2
  import { JobStatus } from "./constants";
3
3
  import { WebcrawlerApiError } from "./errors";
4
4
  export { WebcrawlerApiError, JobStatus };
@@ -8,10 +8,9 @@ export declare class WebcrawlerClient {
8
8
  protected apiKey: string;
9
9
  protected basePath: string;
10
10
  constructor(apiKey: string, basePath?: string, apiVersion?: string);
11
- scrapeAsync(scrapeRequest: ScrapeRequest): Promise<JobId>;
12
- scrapeWithMeta(scrapeRequest: ScrapeRequest, maxPollingRetries?: number): Promise<ScrapeResponse>;
13
- scrape(scrapeRequest: ScrapeRequest, maxPollingRetries?: number): Promise<any>;
14
- getScrapeResult(scrapeID: string): Promise<ScrapeResponse>;
11
+ scrapeAsync(request: ScrapeRequest): Promise<ScrapeId>;
12
+ getScrape(scrapeId: string): Promise<ScrapeResponse | ScrapeResponseError>;
13
+ scrape(request: ScrapeRequest, maxPolls?: number): Promise<ScrapeResponse | ScrapeResponseError>;
15
14
  crawl(crawlRequest: CrawlRequest, actions?: Action | Action[]): Promise<Job>;
16
15
  crawlAsync(crawlRequest: CrawlRequest, actions?: Action | Action[]): Promise<JobId>;
17
16
  getJob(jobID: string): Promise<Job>;
@@ -1,21 +1,32 @@
1
1
  export interface ScrapeRequest {
2
- input: any;
3
- crawler_id: string;
4
- max_retries?: number;
5
- debug?: boolean;
6
- omit_cache?: boolean;
2
+ url: string;
3
+ output_format: string;
4
+ webhook_url?: string;
5
+ clean_selectors?: string;
6
+ actions?: Action[];
7
+ prompt?: string;
7
8
  }
8
- export interface JobId {
9
+ export interface ScrapeId {
9
10
  id: string;
10
11
  }
11
12
  export interface ScrapeResponse {
12
- id: string;
13
- url: string;
14
- status: any;
13
+ success: boolean;
14
+ status?: string;
15
+ markdown?: string;
16
+ cleaned_content?: string;
17
+ raw_content?: string;
15
18
  page_status_code: number;
16
- created_at: string;
17
- structured_data: any;
18
- recommended_pull_delay_ms: number;
19
+ page_title?: string;
20
+ structured_data?: any;
21
+ }
22
+ export interface ScrapeResponseError {
23
+ success: boolean;
24
+ error_code: string;
25
+ error_message: string;
26
+ status?: string;
27
+ }
28
+ export interface JobId {
29
+ id: string;
19
30
  }
20
31
  export interface CrawlRequest {
21
32
  url?: string;
package/dist/api.js CHANGED
@@ -22,8 +22,9 @@ Object.defineProperty(exports, "WebcrawlerApiError", { enumerable: true, get: fu
22
22
  const BASE_PATH = "https://api.webcrawlerapi.com";
23
23
  const initialPullDelayMs = 2000;
24
24
  const MaxPullRetries = 100;
25
+ const DEFAULT_POLL_DELAY_SECONDS = 2;
25
26
  __exportStar(require("./model"), exports);
26
- // Helper function to add getContent method to job items
27
+ const SCRAPE_VERSION = "v2";
27
28
  function addGetContentMethod(job) {
28
29
  // Transform each job item to include getContent method
29
30
  job.job_items = job.job_items.map(item => ({
@@ -68,8 +69,8 @@ class WebcrawlerClient {
68
69
  this.basePath = basePath;
69
70
  this.apiVersion = apiVersion;
70
71
  }
71
- async scrapeAsync(scrapeRequest) {
72
- const url = `${this.basePath}/${this.apiVersion}/scrape`;
72
+ async scrapeAsync(request) {
73
+ const apiUrl = `${this.basePath}/${SCRAPE_VERSION}/scrape?async=true`;
73
74
  const requestOptions = {
74
75
  'method': 'POST',
75
76
  'headers': {
@@ -77,46 +78,13 @@ class WebcrawlerClient {
77
78
  'Authorization': `Bearer ${this.apiKey}`,
78
79
  "User-Agent": "WebcrawlerAPI-NodeJS-Client"
79
80
  },
80
- 'body': JSON.stringify(scrapeRequest),
81
+ 'body': JSON.stringify(request),
81
82
  };
82
- return await this.sendRequest(url, requestOptions);
83
- }
84
- async scrapeWithMeta(scrapeRequest, maxPollingRetries = MaxPullRetries) {
85
- const url = `${this.basePath}/${this.apiVersion}/scrape`;
86
- const requestOptions = {
87
- 'method': 'POST',
88
- 'headers': {
89
- 'Content-Type': 'application/json',
90
- 'Authorization': `Bearer ${this.apiKey}`
91
- },
92
- 'body': JSON.stringify(scrapeRequest),
93
- };
94
- const jobIdResponse = await this.sendRequest(url, requestOptions);
95
- if (jobIdResponse.id === '') {
96
- throw new errors_1.WebcrawlerApiError('invalid_response', 'Failed to fetch job status', 0);
97
- }
98
- let delayIntervalMs = initialPullDelayMs;
99
- for (let i = 0; i < maxPollingRetries; i++) {
100
- await new Promise(resolve => setTimeout(resolve, delayIntervalMs));
101
- const scrapeResult = await this.getScrapeResult(jobIdResponse.id);
102
- if (scrapeRequest.debug) {
103
- console.log(`Scrape result: ${JSON.stringify(scrapeResult)}`);
104
- }
105
- if (scrapeResult.status !== constants_1.JobStatus.IN_PROGRESS && scrapeResult.status !== constants_1.JobStatus.NEW) {
106
- return scrapeResult;
107
- }
108
- if (scrapeResult.recommended_pull_delay_ms > 0) {
109
- delayIntervalMs = scrapeResult.recommended_pull_delay_ms;
110
- }
111
- }
112
- throw new errors_1.WebcrawlerApiError('timeout', 'Scraping took too long, please retry or increase the number of polling retries', 0);
113
- }
114
- async scrape(scrapeRequest, maxPollingRetries = MaxPullRetries) {
115
- const scrapeResult = await this.scrapeWithMeta(scrapeRequest, maxPollingRetries);
116
- return scrapeResult.structured_data;
83
+ const response = await this.sendRequest(apiUrl, requestOptions);
84
+ return { id: response.id };
117
85
  }
118
- async getScrapeResult(scrapeID) {
119
- const url = `${this.basePath}/${this.apiVersion}/scrape/${scrapeID}`;
86
+ async getScrape(scrapeId) {
87
+ const url = `${this.basePath}/${SCRAPE_VERSION}/scrape/${scrapeId}`;
120
88
  const requestOptions = {
121
89
  'method': 'GET',
122
90
  'headers': {
@@ -128,7 +96,46 @@ class WebcrawlerClient {
128
96
  'Expires': '0'
129
97
  },
130
98
  };
131
- return await this.sendRequest(url, requestOptions);
99
+ const responseData = await this.sendRequest(url, requestOptions);
100
+ const status = responseData.status;
101
+ if (status === "done") {
102
+ return responseData;
103
+ }
104
+ else if (status === "error") {
105
+ return responseData;
106
+ }
107
+ else {
108
+ // in_progress or any other status
109
+ return {
110
+ success: false,
111
+ status: status,
112
+ page_status_code: 0
113
+ };
114
+ }
115
+ }
116
+ async scrape(request, maxPolls = 100) {
117
+ // Start the scraping job
118
+ const scrapeIdResponse = await this.scrapeAsync(request);
119
+ const scrapeId = scrapeIdResponse.id;
120
+ let polls = 0;
121
+ let result;
122
+ while (polls < maxPolls) {
123
+ result = await this.getScrape(scrapeId);
124
+ // Return immediately if scrape is done
125
+ if ('status' in result && result.status === "done") {
126
+ return result;
127
+ }
128
+ // Return immediately if there's an error
129
+ if ('error_code' in result) {
130
+ return result;
131
+ }
132
+ // Continue polling if status is in_progress or any other non-terminal status
133
+ // Wait before next poll
134
+ await new Promise(resolve => setTimeout(resolve, DEFAULT_POLL_DELAY_SECONDS * 1000));
135
+ polls++;
136
+ }
137
+ // Return the last known state if maxPolls is reached
138
+ return result;
132
139
  }
133
140
  async crawl(crawlRequest, actions) {
134
141
  const url = `${this.basePath}/${this.apiVersion}/crawl`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "webcrawlerapi-js",
3
- "version": "1.1.7",
3
+ "version": "2.0.1",
4
4
 
5
5
  "description": "JS client for WebcrawlerAPI",
6
6
  "main": "./dist/api.js",