@isdk/web-fetcher 0.2.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.
Files changed (66) hide show
  1. package/README.action.cn.md +469 -0
  2. package/README.action.md +452 -0
  3. package/README.cn.md +147 -0
  4. package/README.engine.cn.md +262 -0
  5. package/README.engine.md +262 -0
  6. package/README.md +147 -0
  7. package/dist/index.d.mts +1603 -0
  8. package/dist/index.d.ts +1603 -0
  9. package/dist/index.js +1 -0
  10. package/dist/index.mjs +1 -0
  11. package/docs/README.md +151 -0
  12. package/docs/_media/LICENSE-MIT +22 -0
  13. package/docs/_media/README.action.md +452 -0
  14. package/docs/_media/README.cn.md +147 -0
  15. package/docs/_media/README.engine.md +262 -0
  16. package/docs/classes/CheerioFetchEngine.md +1447 -0
  17. package/docs/classes/ClickAction.md +533 -0
  18. package/docs/classes/ExtractAction.md +533 -0
  19. package/docs/classes/FetchAction.md +444 -0
  20. package/docs/classes/FetchEngine.md +1230 -0
  21. package/docs/classes/FetchSession.md +111 -0
  22. package/docs/classes/FillAction.md +533 -0
  23. package/docs/classes/GetContentAction.md +533 -0
  24. package/docs/classes/GotoAction.md +537 -0
  25. package/docs/classes/PauseAction.md +533 -0
  26. package/docs/classes/PlaywrightFetchEngine.md +1437 -0
  27. package/docs/classes/SubmitAction.md +533 -0
  28. package/docs/classes/WaitForAction.md +533 -0
  29. package/docs/classes/WebFetcher.md +85 -0
  30. package/docs/enumerations/FetchActionResultStatus.md +40 -0
  31. package/docs/functions/fetchWeb.md +43 -0
  32. package/docs/globals.md +72 -0
  33. package/docs/interfaces/BaseFetchActionProperties.md +83 -0
  34. package/docs/interfaces/BaseFetchCollectorActionProperties.md +145 -0
  35. package/docs/interfaces/BaseFetcherProperties.md +206 -0
  36. package/docs/interfaces/Cookie.md +142 -0
  37. package/docs/interfaces/DispatchedEngineAction.md +60 -0
  38. package/docs/interfaces/ExtractActionProperties.md +113 -0
  39. package/docs/interfaces/FetchActionInContext.md +149 -0
  40. package/docs/interfaces/FetchActionProperties.md +125 -0
  41. package/docs/interfaces/FetchActionResult.md +55 -0
  42. package/docs/interfaces/FetchContext.md +424 -0
  43. package/docs/interfaces/FetchEngineContext.md +328 -0
  44. package/docs/interfaces/FetchMetadata.md +73 -0
  45. package/docs/interfaces/FetchResponse.md +105 -0
  46. package/docs/interfaces/FetchReturnTypeRegistry.md +57 -0
  47. package/docs/interfaces/FetchSite.md +320 -0
  48. package/docs/interfaces/FetcherOptions.md +300 -0
  49. package/docs/interfaces/GotoActionOptions.md +66 -0
  50. package/docs/interfaces/PendingEngineRequest.md +51 -0
  51. package/docs/interfaces/SubmitActionOptions.md +23 -0
  52. package/docs/interfaces/WaitForActionOptions.md +39 -0
  53. package/docs/type-aliases/BaseFetchActionOptions.md +11 -0
  54. package/docs/type-aliases/BaseFetchCollectorOptions.md +11 -0
  55. package/docs/type-aliases/BrowserEngine.md +11 -0
  56. package/docs/type-aliases/FetchActionCapabilities.md +11 -0
  57. package/docs/type-aliases/FetchActionCapabilityMode.md +11 -0
  58. package/docs/type-aliases/FetchActionOptions.md +11 -0
  59. package/docs/type-aliases/FetchEngineAction.md +18 -0
  60. package/docs/type-aliases/FetchEngineType.md +11 -0
  61. package/docs/type-aliases/FetchReturnType.md +11 -0
  62. package/docs/type-aliases/FetchReturnTypeFor.md +17 -0
  63. package/docs/type-aliases/OnFetchPauseCallback.md +23 -0
  64. package/docs/type-aliases/ResourceType.md +11 -0
  65. package/docs/variables/DefaultFetcherProperties.md +11 -0
  66. package/package.json +90 -0
@@ -0,0 +1,452 @@
1
+ # 📜 Action Script Architecture
2
+
3
+ English | [简体中文](./README.action.cn.md)
4
+
5
+ > This document details the architecture, design philosophy, and usage of the Action Script system within `@isdk/web-fetcher`. It is intended to help developers maintain and extend the system, and to help users efficiently build automation tasks.
6
+
7
+ ## 🎯 1. Overview
8
+
9
+ The core goal of the Action Script system is to provide a **declarative, engine-agnostic** way to define and execute a series of web interactions.
10
+
11
+ The system is built on two fundamental concepts:
12
+
13
+ * **⚛️ Atomic Actions:** Built into the library, these represent a single, indivisible operation and are the basic "atoms" that make up all complex processes. Examples: `goto`, `click`, `fill`.
14
+ * **🧩 Composite Actions:** Created by the library user, these represent a complex operation with business semantics, composed of multiple atomic actions. This is the essence of the architecture, encouraging users to encapsulate low-level operations into higher-level "molecules" that are easier to understand and reuse. Examples: `login`, `search`, `addToCart`.
15
+
16
+ This approach allows users to describe a complete business process with intuitive semantics, while hiding the specific, engine-related implementation details in the underlying layers.
17
+
18
+ ---
19
+
20
+ ## 🛠️ 2. Core Concepts
21
+
22
+ ### `FetchAction` (Base Class)
23
+
24
+ `FetchAction` is the abstract base class for all Actions. It defines the core elements of an Action:
25
+
26
+ * `static id`: The unique identifier for the Action, e.g., `'click'`.
27
+ * `static returnType`: The type of the result returned after the Action executes, e.g., `'none'`, `'response'`.
28
+ * `static capabilities`: Declares the capability level of this Action in different engines (`http`, `browser`), such as `native`, `simulate`, or `noop`.
29
+ * `static register()`: A static method to register the Action class in a global registry, allowing it to be dynamically created by its `id`.
30
+
31
+ ### `onExecute` (Core Logic)
32
+
33
+ Every `FetchAction` subclass must implement the `onExecute` method. This is where an Action defines its behavior.
34
+
35
+ ### `delegateToEngine` (Delegation Helper)
36
+
37
+ To simplify the creation of **atomic actions**, the `FetchAction` base class provides a protected helper method, `delegateToEngine`. It forwards the call to the corresponding method on the active engine, passing along any arguments. This allows actions to be a thin wrapper around engine capabilities.
38
+
39
+ **Example: The `fill` Action using `delegateToEngine`**
40
+
41
+ ```typescript
42
+ // src/action/definitions/fill.ts
43
+ export class FillAction extends FetchAction {
44
+ // ...
45
+ async onExecute(context: FetchContext, options?: BaseFetchActionProperties): Promise<void> {
46
+ const { selector, value, ...restOptions } = options?.params || {};
47
+ if (!selector) throw new Error('Selector is required for fill action');
48
+ if (value === undefined) throw new Error('Value is required for fill action');
49
+ // selector, value, and restOptions are passed as arguments to engine.fill()
50
+ await this.delegateToEngine(context, 'fill', selector, value, restOptions);
51
+ }
52
+ }
53
+ ```
54
+
55
+ ---
56
+
57
+ ## 🚀 3. How to Use (For Users)
58
+
59
+ Users define a complete automation workflow via a JSON-formatted `actions` array.
60
+
61
+ ### Using Atomic Actions
62
+
63
+ For simple, linear workflows, you can use a list of the library's built-in atomic actions directly.
64
+
65
+ **Example: Searching for "gemini" on Google**
66
+
67
+ ```json
68
+ {
69
+ "actions": [
70
+ { "id": "goto", "params": { "url": "https://www.google.com" } },
71
+ { "id": "fill", "params": { "selector": "textarea[name=q]", "value": "gemini" } },
72
+ { "id": "submit", "params": { "selector": "form" } }
73
+ ]
74
+ }
75
+ ```
76
+
77
+ ### Built-in Atomic Actions
78
+
79
+ The library provides a set of essential atomic actions to perform common web interactions.
80
+
81
+ #### `goto`
82
+
83
+ Navigates the browser to a new URL.
84
+
85
+ * **`id`**: `goto`
86
+ * **`params`**:
87
+ * `url` (string): The URL to navigate to.
88
+ * ...other navigation options like `waitUntil`, `timeout` which are passed to the engine.
89
+ * **`returns`**: `response`
90
+
91
+ #### `click`
92
+
93
+ Clicks on an element specified by a selector.
94
+
95
+ * **`id`**: `click`
96
+ * **`params`**:
97
+ * `selector` (string): A CSS selector or XPath to identify the element to click.
98
+ * **`returns`**: `none`
99
+
100
+ #### `fill`
101
+
102
+ Fills an input field with a specified value.
103
+
104
+ * **`id`**: `fill`
105
+ * **`params`**:
106
+ * `selector` (string): A selector for the input element.
107
+ * `value` (string): The text to fill into the element.
108
+ * **`returns`**: `none`
109
+
110
+ #### `submit`
111
+
112
+ Submits a form.
113
+
114
+ * **`id`**: `submit`
115
+ * **`params`**:
116
+ * `selector` (string, optional): A selector for the form element.
117
+ * **`returns`**: `none`
118
+
119
+ #### `waitFor`
120
+
121
+ Pauses execution to wait for a specific condition to be met.
122
+
123
+ * **`id`**: `waitFor`
124
+ * **`params`**: An object specifying the wait condition (e.g., `ms`, `selector`, `networkIdle`).
125
+ * **`returns`**: `none`
126
+
127
+ #### `pause`
128
+
129
+ Pauses the execution of the Action Script to allow for manual user intervention (e.g., solving a CAPTCHA).
130
+
131
+ This action **requires** an `onPause` callback handler to be provided in the `fetchWeb` options. When triggered, this action calls the `onPause` handler and waits for it to complete.
132
+
133
+ * **`id`**: `pause`
134
+ * **`params`**:
135
+ * `selector` (string, optional): If provided, the action will only pause if an element matching this selector exists.
136
+ * `attribute` (string, optional): Used in conjunction with `selector`. If provided, the action will only pause if the element exists AND has the specified attribute.
137
+ * `message` (string, optional): A message that will be passed to the `onPause` handler, which can be used to display prompts to the user.
138
+ * **`returns`**: `none`
139
+
140
+ **Example: Handling a CAPTCHA in Google Search**
141
+
142
+ ```json
143
+ {
144
+ "actions": [
145
+ { "id": "goto", "params": { "url": "https://www.google.com/search?q=gemini" } },
146
+ {
147
+ "id": "pause",
148
+ "params": {
149
+ "selector": "#recaptcha",
150
+ "message": "Google CAPTCHA detected. Please solve it in the browser and press Enter to continue."
151
+ }
152
+ },
153
+ { "id": "waitFor", "params": { "selector": "#search" } }
154
+ ]
155
+ }
156
+ ```
157
+
158
+ **`onPause` Handler Example:**
159
+
160
+ ```typescript
161
+ // In your code that calls fetchWeb
162
+ import { fetchWeb } from '@isdk/web-fetcher';
163
+ import readline from 'readline';
164
+
165
+ const handlePause = async ({ message }) => {
166
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
167
+ await new Promise(resolve => {
168
+ rl.question(message || 'Execution paused. Press Enter to continue...', () => {
169
+ rl.close();
170
+ resolve();
171
+ });
172
+ });
173
+ };
174
+
175
+ await fetchWeb({
176
+ // ...,
177
+ engine: 'browser',
178
+ engineOptions: { headless: false },
179
+ onPause: handlePause,
180
+ actions: [
181
+ // ... your actions
182
+ ]
183
+ });
184
+ ```
185
+
186
+ #### `getContent`
187
+
188
+ Retrieves the full content of the current page state.
189
+
190
+ * **`id`**: `getContent`
191
+ * **`params`**: (none)
192
+ * **`returns`**: `response`
193
+
194
+ #### `extract`
195
+
196
+ Extracts structured data from the page using a powerful and declarative Schema. This is the core Action for data collection.
197
+
198
+ * **`id`**: `extract`
199
+ * **`params`**: An `ExtractSchema` object that defines the extraction rules.
200
+ * **`returns`**: `any` (the extracted data)
201
+
202
+ ##### Detailed Explanation of Extraction Schema
203
+
204
+ The `params` object itself is a Schema that describes the data structure you want to extract.
205
+
206
+ ###### 1. Extracting a Single Value
207
+
208
+ The most basic extraction. You can specify a `selector` (CSS selector), an `attribute` (the name of the attribute to extract), and a `type` (string, number, boolean, html).
209
+
210
+ ```json
211
+ {
212
+ "id": "extract",
213
+ "params": {
214
+ "selector": "h1.main-title",
215
+ "type": "string"
216
+ }
217
+ }
218
+ ```
219
+
220
+ > The example above will extract the text content of the `<h1>` tag with the class `main-title`.
221
+
222
+ ###### 2. Extracting an Object
223
+
224
+ Define a structured object using `type: 'object'` and the `properties` field.
225
+
226
+ ```json
227
+ {
228
+ "id": "extract",
229
+ "params": {
230
+ "type": "object",
231
+ "selector": ".author-bio",
232
+ "properties": {
233
+ "name": { "selector": ".author-name" },
234
+ "email": { "selector": "a.email", "attribute": "href" }
235
+ }
236
+ }
237
+ }
238
+ ```
239
+
240
+ ###### 3. Extracting an Array (Convenient Usage)
241
+
242
+ Extract a list using `type: 'array'`. To make the most common operations simpler, we provide some convenient usages.
243
+
244
+ * **Extracting an Array of Texts (Default Behavior)**: When you want to extract a list of text, just provide the selector and omit `items`. This is the most common usage.
245
+
246
+ ```json
247
+ {
248
+ "id": "extract",
249
+ "params": {
250
+ "type": "array",
251
+ "selector": ".tags li"
252
+ }
253
+ }
254
+ ```
255
+
256
+ > The example above will return an array of the text from all `<li>` tags, e.g., `["tech", "news"]`.
257
+
258
+ * **Extracting an Array of Attributes (Shortcut)**: When you only want to extract a list of attributes (e.g., all `href`s from links), there's no need to nest `items` either. Just declare `attribute` directly in the `array` definition.
259
+
260
+ ```json
261
+ {
262
+ "id": "extract",
263
+ "params": {
264
+ "type": "array",
265
+ "selector": ".gallery img",
266
+ "attribute": "src"
267
+ }
268
+ }
269
+ ```
270
+
271
+ > The example above will return an array of the `src` attributes from all `<img>` tags.
272
+
273
+ ###### 4. Precise Filtering: `has` and `exclude`
274
+
275
+ You can use the `has` and `exclude` fields in any schema that includes a `selector` to precisely control element selection.
276
+
277
+ * `has`: A CSS selector to ensure the selected element **must contain** a descendant matching this selector.
278
+ * `exclude`: A CSS selector to **exclude** elements matching this selector from the results.
279
+
280
+ **Complete Example: Extracting links of articles that have an image and are not marked as "draft"**
281
+
282
+ ```json
283
+ {
284
+ "actions": [
285
+ { "id": "goto", "params": { "url": "https://example.com/articles" } },
286
+ {
287
+ "id": "extract",
288
+ "params": {
289
+ "type": "array",
290
+ "selector": "div.article-card",
291
+ "has": "img.cover-image",
292
+ "exclude": ".draft",
293
+ "items": {
294
+ "selector": "a.title-link",
295
+ "attribute": "href"
296
+ }
297
+ }
298
+ }
299
+ ]
300
+ }
301
+ ```
302
+
303
+ > The `extract` action above will:
304
+ >
305
+ > 1. Find all `div.article-card` elements.
306
+ > 2. Filter them to only include those that contain an `<img class="cover-image">`.
307
+ > 3. Further filter the results to exclude any that also have the `.draft` class.
308
+ > 4. For each of the remaining `div.article-card` elements, find its descendant `a.title-link` and extract the `href` attribute.
309
+
310
+ ### Building High-Level Semantic Actions via "Composition"
311
+
312
+ This is the recommended best practice for **users** to encapsulate and reuse business logic.
313
+
314
+ **Scenario: Creating a reusable `LoginAction`**
315
+
316
+ 1. **Define `LoginAction.ts` in your project:**
317
+
318
+ ```typescript
319
+ import { FetchContext, FetchAction, BaseFetchActionOptions } from '@isdk/web-fetcher';
320
+
321
+ export class LoginAction extends FetchAction {
322
+ static override id = 'login';
323
+ static override capabilities = { http: 'simulate' as const, browser: 'native' as const };
324
+
325
+ async onExecute(context: FetchContext, options?: BaseFetchActionOptions): Promise<void> {
326
+ const { username, password, userSelector, passSelector, submitSelector } = options?.params || {};
327
+ if (!username || !password || !userSelector || !passSelector || !submitSelector) {
328
+ throw new Error('Username, password, and all selectors are required for login action');
329
+ }
330
+
331
+ const engine = context.internal.engine;
332
+ if (!engine) throw new Error('No engine available');
333
+
334
+ // Orchestrate atomic capabilities to form a complete business process
335
+ await engine.fill({ selector: userSelector, value: username });
336
+ await engine.fill({ selector: passSelector, value: password });
337
+ await engine.click({ selector: submitSelector });
338
+ await engine.waitFor({ networkIdle: true });
339
+ }
340
+ }
341
+ ```
342
+
343
+ 2. **Register this custom Action when your application starts:**
344
+
345
+ ```typescript
346
+ import { FetchAction } from '@isdk/web-fetcher';
347
+ import { LoginAction } from './path/to/LoginAction';
348
+
349
+ FetchAction.register(LoginAction);
350
+ ```
351
+
352
+ 3. **Use your `LoginAction` in scripts:**
353
+
354
+ Now, your action script becomes much cleaner and more semantic:
355
+
356
+ ```json
357
+ {
358
+ "actions": [
359
+ {
360
+ "id": "login",
361
+ "params": {
362
+ "username": "testuser",
363
+ "password": "password123",
364
+ "userSelector": "#username",
365
+ "passSelector": "#password",
366
+ "submitSelector": "button[type=submit]"
367
+ }
368
+ }
369
+ ]
370
+ }
371
+ ```
372
+
373
+ ---
374
+
375
+ ## 🧲 4. Advanced Feature: Collectors
376
+
377
+ A Collector is a powerful mechanism that allows a **main Action** to run one or more **child Actions** during its execution to collect data in a parallel, event-driven manner.
378
+
379
+ ### Core Concepts
380
+
381
+ Collectors are defined in the `collectors` array of a main Action. Their execution is event-driven:
382
+
383
+ * `activateOn`: Event(s) to activate the collector.
384
+ * `collectOn`: Event(s) that trigger the collector's `onExecute` logic.
385
+ * `deactivateOn`: Event(s) to deactivate the collector.
386
+ * `storeAs`: A key to store the collected results in `context.outputs`.
387
+
388
+ > **ℹ️ Special Rule**: If a collector has no `On` events configured, it will execute its `onExecute` logic once when the main Action's `end` event is triggered.
389
+
390
+ ### Applicable Scenarios for Collectors
391
+
392
+ > **⚠️ Important**: While any Action can technically be used as a collector, it is only meaningful for **Actions whose purpose is to return data** (e.g., `getContent`, `extract`). Using an action like `click` or `fill` as a collector is pointless as it doesn't "collect" anything.
393
+
394
+ ### Usage Example
395
+
396
+ **Scenario**: Visit a blog page and collect all hyperlinks (`href` from `<a>` tags) after the page has loaded.
397
+
398
+ ```json
399
+ {
400
+ "actions": [
401
+ {
402
+ "id": "goto",
403
+ "params": { "url": "https://example.com/blog/my-post" },
404
+ "collectors": [
405
+ {
406
+ "id": "extract",
407
+ "name": "linkCollector",
408
+ "params": {
409
+ "type": "array",
410
+ "selector": "a",
411
+ "attribute": "href"
412
+ },
413
+ "storeAs": "allLinks"
414
+ }
415
+ ]
416
+ }
417
+ ]
418
+ }
419
+ ```
420
+
421
+ **Execution Flow**:
422
+
423
+ 1. The main `goto` Action begins.
424
+ 2. The `linkCollector` is initialized.
425
+ 3. Since it has no triggers, it waits for the `goto` action to complete.
426
+ 4. `goto` loads the page and fires its `action:goto.end` event.
427
+ 5. `linkCollector` hears this event and executes, extracting the `href` from all `<a>` tags.
428
+ 6. The results are pushed into the `context.outputs.allLinks` array.
429
+
430
+ ---
431
+
432
+ ## 🧑‍💻 5. How to Extend (For Developers)
433
+
434
+ As a library developer, your primary responsibility is to enrich the **atomic Action** ecosystem.
435
+
436
+ ### Adding a New Atomic Action
437
+
438
+ 1. **Define the Capability in the Engine:** Add a new abstract method to `FetchEngine` in `src/engine/base.ts` and implement it in the concrete engines (`Cheerio`, `Playwright`).
439
+ 2. **Create the Action Class:** Create a new file like `src/action/definitions/MyNewAction.ts`.
440
+ 3. **Implement `onExecute`:** Use the `delegateToEngine` helper for simple cases.
441
+ 4. **Register the Action:** Call `FetchAction.register(MyNewAction)` in your new file.
442
+
443
+ ---
444
+
445
+ ## 🔄 6. Action Lifecycle
446
+
447
+ The `FetchAction` base class provides lifecycle hooks that allow injecting custom behavior before and after the core logic of an Action executes.
448
+
449
+ * `protected onBeforeExec?()`: Called before `onExecute`.
450
+ * `protected onAfterExec?()`: Called after `onExecute`.
451
+
452
+ For Actions that need to manage complex state or resources, you can implement these hooks. Generally, for composite actions, writing the logic directly in `onExecute` is sufficient.
@@ -0,0 +1,147 @@
1
+ # 🕸️ @isdk/web-fetcher
2
+
3
+ [English](./README.md) | 简体中文
4
+
5
+ > 一个功能强大且灵活的 Web 抓取与浏览器自动化库。
6
+ > 它采用双引擎架构(HTTP 和浏览器)和声明式动作系统,是 AI 代理和复杂数据抓取任务的理想选择。
7
+
8
+ ---
9
+
10
+ ## ✨ 核心特性
11
+
12
+ * **⚙️ 双引擎架构**: 可在 **`http`** 模式(由 Cheerio 驱动,适用于静态站点,速度快)和 **`browser`** 模式(由 Playwright 驱动,适用于动态站点,可执行完整的 JavaScript 交互)之间选择。
13
+ * **📜 声明式动作脚本**: 以简单、可读的 JSON 格式定义多步骤工作流(如登录、填写表单、点击按钮等)。
14
+ * **📊 强大而灵活的数据提取**: 通过直观、强大的声明式 Schema,轻松提取从简单文本到复杂嵌套的各类结构化数据。
15
+ * **🧠 智能引擎选择**: 可自动检测动态站点,并在需要时将引擎从 `http` 动态升级到 `browser`。
16
+ * **🧩 可扩展性**: 轻松创建自定义的、高级别的“组合动作”,以封装可复用的业务逻辑(例如,一个 `login` 动作)。
17
+ * **🧲 高级收集器 (Collectors)**: 在主动作执行期间,由事件触发,在后台异步收集数据。
18
+ * **🛡️ 反爬虫/反屏蔽**: 在 `browser` 模式下,一个可选的 `antibot` 标志有助于绕过常见的反机器人措施,如 Cloudflare 挑战。
19
+
20
+ ---
21
+
22
+ ## 📦 安装
23
+
24
+ 1. **安装依赖包:**
25
+
26
+ ```bash
27
+ npm install @isdk/web-fetcher
28
+ ```
29
+
30
+ 2. **安装浏览器 (用于 `browser` 模式):**
31
+
32
+ `browser` 引擎由 Playwright 驱动,它需要下载独立的浏览器二进制文件。如果您计划使用 `browser` 引擎与动态网站进行交互,请运行以下命令:
33
+
34
+ ```bash
35
+ npx playwright install
36
+ ```
37
+
38
+ > ℹ️ **提示:** 仅当您需要使用 `browser` 模式时,此步骤才是必需的。轻量级的 `http` 模式无需安装浏览器即可工作。
39
+
40
+ ---
41
+
42
+ ## 🚀 快速入门
43
+
44
+ 以下示例抓取一个网页并提取其标题。
45
+
46
+ ```typescript
47
+ import { fetchWeb } from '@isdk/web-fetcher';
48
+
49
+ async function getTitle(url: string) {
50
+ const { outputs } = await fetchWeb({
51
+ url,
52
+ actions: [
53
+ {
54
+ id: 'extract',
55
+ params: {
56
+ // 提取 <title> 标签的文本内容
57
+ selector: 'title',
58
+ },
59
+ // 将结果存储在 `outputs` 对象的 'pageTitle' 键下
60
+ storeAs: 'pageTitle',
61
+ },
62
+ ],
63
+ });
64
+
65
+ console.log('页面标题:', outputs.pageTitle);
66
+ }
67
+
68
+ getTitle('https://www.google.com');
69
+ ```
70
+
71
+ ---
72
+
73
+ ## 🤖 高级用法:多步表单提交
74
+
75
+ 此示例演示如何使用 `browser` 引擎在 Google 上执行搜索。
76
+
77
+ ```typescript
78
+ import { fetchWeb } from '@isdk/web-fetcher';
79
+
80
+ async function searchGoogle(query: string) {
81
+ // 在 Google 上搜索指定查询
82
+ const { result, outputs } = await fetchWeb({
83
+ url: 'https://www.google.com',
84
+ engine: 'browser', // 使用完整的浏览器引擎进行交互
85
+ actions: [
86
+ // 对 google.com 的初始导航由 `url` 选项处理
87
+ { id: 'fill', params: { selector: 'textarea[name=q]', value: query } },
88
+ { id: 'submit', params: { selector: 'form' } },
89
+ { id: 'waitFor', params: { selector: '#search' } }, // 等待搜索结果容器出现
90
+ { id: 'getContent', storeAs: 'searchResultsPage' },
91
+ ]
92
+ });
93
+
94
+ console.log('搜索结果 URL:', result?.finalUrl);
95
+ console.log('Outputs 中包含了完整的页面内容:', outputs.searchResultsPage.html.substring(0, 100));
96
+ }
97
+
98
+ searchGoogle('gemini');
99
+ ```
100
+
101
+ ---
102
+
103
+ ## 🏗️ 架构
104
+
105
+ 该库构建于两个核心概念之上:**引擎 (Engines)** 和 **动作 (Actions)**。
106
+
107
+ * ### 引擎架构
108
+
109
+ 该库的核心是其双引擎设计。它将 Web 交互的复杂性抽象在一个统一的 API 之后。有关 `http` (Cheerio) 和 `browser` (Playwright) 引擎的详细信息、它们如何管理状态以及如何扩展它们,请参阅 [**抓取引擎架构**](./README.engine.cn.md) 文档。
110
+
111
+ * ### 动作架构
112
+
113
+ 所有工作流都定义为一系列“动作”。该库提供了一套内置的原子动作和一个强大的组合模型,用于创建您自己的语义动作。有关创建和使用动作的深入探讨,请参阅 [**动作脚本架构**](./README.action.cn.md) 文档。
114
+
115
+ ---
116
+
117
+ ## 📚 API 参考
118
+
119
+ ### `fetchWeb(options)` 或 `fetchWeb(url, options)`
120
+
121
+ 这是库的主入口点。
122
+
123
+ **关键 `FetcherOptions`**:
124
+
125
+ * `url` (string): 要导航的初始 URL。
126
+ * `engine` ('http' | 'browser' | 'auto'): 要使用的引擎。默认为 `auto`。
127
+ * `actions` (FetchActionOptions[]): 要执行的动作对象数组。
128
+ * `headers` (Record<string, string>): 用于所有请求的头信息。
129
+ * ...以及许多其他用于代理、Cookie、重试等的选项。
130
+
131
+ ### 内置动作
132
+
133
+ 以下是核心的内置动作:
134
+
135
+ * `goto`: 导航到一个新的 URL。
136
+ * `click`: 点击一个由选择器指定的元素。
137
+ * `fill`: 用指定的值填充一个输入字段。
138
+ * `submit`: 提交一个表单。
139
+ * `waitFor`: 暂停执行以等待特定条件(例如,超时、选择器出现或网络空闲)。
140
+ * `getContent`: 获取当前页面状态的完整内容(HTML、文本等)。
141
+ * `extract`: 使用富有表现力的声明式 Schema,可轻松提取页面中的任意结构化数据。
142
+
143
+ ---
144
+
145
+ ## 📜 许可证
146
+
147
+ [MIT](./LICENSE-MIT)