webcrawlerapi-js 1.1.7 → 2.0.0

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,9 @@ 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`;
74
+ console.log(request);
73
75
  const requestOptions = {
74
76
  'method': 'POST',
75
77
  'headers': {
@@ -77,46 +79,13 @@ class WebcrawlerClient {
77
79
  'Authorization': `Bearer ${this.apiKey}`,
78
80
  "User-Agent": "WebcrawlerAPI-NodeJS-Client"
79
81
  },
80
- 'body': JSON.stringify(scrapeRequest),
82
+ 'body': JSON.stringify(request),
81
83
  };
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;
84
+ const response = await this.sendRequest(apiUrl, requestOptions);
85
+ return { id: response.id };
117
86
  }
118
- async getScrapeResult(scrapeID) {
119
- const url = `${this.basePath}/${this.apiVersion}/scrape/${scrapeID}`;
87
+ async getScrape(scrapeId) {
88
+ const url = `${this.basePath}/${SCRAPE_VERSION}/scrape/${scrapeId}`;
120
89
  const requestOptions = {
121
90
  'method': 'GET',
122
91
  'headers': {
@@ -128,7 +97,46 @@ class WebcrawlerClient {
128
97
  'Expires': '0'
129
98
  },
130
99
  };
131
- return await this.sendRequest(url, requestOptions);
100
+ const responseData = await this.sendRequest(url, requestOptions);
101
+ const status = responseData.status;
102
+ if (status === "done") {
103
+ return responseData;
104
+ }
105
+ else if (status === "error") {
106
+ return responseData;
107
+ }
108
+ else {
109
+ // in_progress or any other status
110
+ return {
111
+ success: false,
112
+ status: status,
113
+ page_status_code: 0
114
+ };
115
+ }
116
+ }
117
+ async scrape(request, maxPolls = 100) {
118
+ // Start the scraping job
119
+ const scrapeIdResponse = await this.scrapeAsync(request);
120
+ const scrapeId = scrapeIdResponse.id;
121
+ let polls = 0;
122
+ let result;
123
+ while (polls < maxPolls) {
124
+ result = await this.getScrape(scrapeId);
125
+ // Return immediately if scrape is done
126
+ if ('status' in result && result.status === "done") {
127
+ return result;
128
+ }
129
+ // Return immediately if there's an error
130
+ if ('error_code' in result) {
131
+ return result;
132
+ }
133
+ // Continue polling if status is in_progress or any other non-terminal status
134
+ // Wait before next poll
135
+ await new Promise(resolve => setTimeout(resolve, DEFAULT_POLL_DELAY_SECONDS * 1000));
136
+ polls++;
137
+ }
138
+ // Return the last known state if maxPolls is reached
139
+ return result;
132
140
  }
133
141
  async crawl(crawlRequest, actions) {
134
142
  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.0",
4
4
 
5
5
  "description": "JS client for WebcrawlerAPI",
6
6
  "main": "./dist/api.js",