You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/guides/extending_crawlee.mdx
+48-32Lines changed: 48 additions & 32 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -6,13 +6,13 @@ description: The extension points Crawlee exposes, the contract each one defines
6
6
7
7
importApiLinkfrom'@site/src/components/ApiLink';
8
8
9
-
Crawlee covers the common cases out of the box, but sooner or later you'll hit something it doesn't do: a parser for a format no built-in crawler understands, an HTTP backend your company mandates, a database you want your data in, or a browser that isn't launched the standard Playwright way. Rather than forking, you can plug your own implementation into the layer that differs and keep everything else.
9
+
Crawlee covers the common cases out of the box, but sooner or later you'll hit something it doesn't do: a parser for a format no built-in crawler understands, an HTTP backend your company mandates, a database you want your data in, or a browser that isn't launched through the standard Playwright path. Rather than forking, you can plug your own implementation into the layer that differs and keep everything else.
10
10
11
11
This guide is the map. It covers the extension points, the contract each one defines, and links to the guide that goes deeper on it. If you maintain a third-party integration, you can build it against these contracts and host your own guide for it.
12
12
13
13
## Extension points
14
14
15
-
The four extension points below are the main ones, and they're where most integrations plug in. They aren't the only abstract classes you can subclass - <ApiLinkto="class/RequestLoader">`RequestLoader`</ApiLink>, <ApiLinkto="class/FingerprintGenerator">`FingerprintGenerator`</ApiLink>, and <ApiLinkto="class/RenderingTypePredictor">`RenderingTypePredictor`</ApiLink> are extensible too.
15
+
The four component families below contain the main extension points, and they're where most integrations plug in. This isn't a complete list of Crawlee's extensible classes. Other examples include <ApiLinkto="class/RequestLoader">`RequestLoader`</ApiLink>, <ApiLinkto="class/FingerprintGenerator">`FingerprintGenerator`</ApiLink>, and <ApiLinkto="class/RenderingTypePredictor">`RenderingTypePredictor`</ApiLink>. The diagram marks the classes in these four families that you can extend or implement as an `extension point`.
16
16
17
17
```mermaid
18
18
---
@@ -24,72 +24,85 @@ config:
24
24
classDiagram
25
25
26
26
class BasicCrawler {
27
-
<<abstract>>
27
+
<<extension point>>
28
28
}
29
29
30
30
class AbstractHttpCrawler {
31
-
<<abstract>>
31
+
<<extension point>>
32
32
}
33
33
34
-
class PlaywrightCrawler
34
+
class AbstractHttpParser {
35
+
<<extension point>>
36
+
}
37
+
38
+
class PlaywrightCrawler {
39
+
<<extension point>>
40
+
}
41
+
42
+
class StagehandCrawler
35
43
36
44
class HttpClient {
37
-
<<abstract>>
45
+
<<extension point>>
38
46
}
39
47
40
48
class StorageClient {
41
-
<<abstract>>
42
-
create_dataset_client()
43
-
create_kvs_client()
44
-
create_rq_client()
49
+
<<extension point>>
45
50
}
46
51
47
52
class DatasetClient {
48
-
<<abstract>>
53
+
<<extension point>>
49
54
}
50
55
51
56
class KeyValueStoreClient {
52
-
<<abstract>>
57
+
<<extension point>>
53
58
}
54
59
55
60
class RequestQueueClient {
56
-
<<abstract>>
61
+
<<extension point>>
57
62
}
58
63
59
64
class BrowserPool
60
65
61
66
class BrowserPlugin {
62
-
<<abstract>>
63
-
new_browser()
67
+
<<extension point>>
64
68
}
65
69
66
70
class BrowserController {
67
-
<<abstract>>
71
+
<<extension point>>
72
+
}
73
+
74
+
class PlaywrightBrowserPlugin {
75
+
<<extension point>>
68
76
}
69
77
70
78
BasicCrawler --|> AbstractHttpCrawler
71
79
BasicCrawler --|> PlaywrightCrawler
72
-
AbstractHttpCrawler --> HttpClient : uses
80
+
AbstractHttpCrawler --> AbstractHttpParser : parses with
A crawler drives the whole run: it takes requests from the queue, fetches each one, builds the context object your handler receives, and manages retries, concurrency, sessions, and storage along the way. <ApiLinkto="class/BasicCrawler">`BasicCrawler`</ApiLink> implements all of that and stays agnostic about how a page is fetched or parsed, which is what makes it the base every other crawler builds on.
95
+
A crawler drives the whole run. It takes requests from the queue, fetches each one, builds the context object your handler receives, and manages retries, concurrency, sessions, and storage along the way. <ApiLinkto="class/BasicCrawler">`BasicCrawler`</ApiLink> implements that orchestration and stays agnostic about how a page is fetched or parsed, which is what makes it the base every other crawler builds on.
85
96
86
-
For HTTP-based crawling, <ApiLinkto="class/AbstractHttpCrawler">`AbstractHttpCrawler`</ApiLink> adds the fetch-and-parse layer on top. Extending it means supplying a parser that implements <ApiLinkto="class/AbstractHttpParser">`AbstractHttpParser`</ApiLink>: `parse` turns an <ApiLinkto="class/HttpResponse">`HttpResponse`</ApiLink> into your parsed type, `parse_text` does the same for a string, `select` and `is_matching_selector` apply selectors to it, and `find_links` extracts the URLs used for link enqueuing. You then pair that parser with a context type that exposes the parsed data to handlers, and a crawler class that ties the two together.
97
+
For HTTP-based crawling, <ApiLinkto="class/AbstractHttpCrawler">`AbstractHttpCrawler`</ApiLink> adds the fetch-and-parse layer. Its contract pairs a parser, a crawling context type, and a crawler class. The parser implements <ApiLinkto="class/AbstractHttpParser">`AbstractHttpParser`</ApiLink>. Its `parse`method turns an <ApiLinkto="class/HttpResponse">`HttpResponse`</ApiLink> into your parsed type, `parse_text` does the same for a string, `select` and `is_matching_selector` apply selectors, and `find_links` extracts URLs for link enqueuing. The context exposes the parsed data to handlers, and the crawler ties the parser and context together.
87
98
88
-
See the [HTTP crawlers guide](./http-crawlers) for a worked example built on `selectolax`, and the [Architecture overview](./architecture-overview) for how crawlers relate to the other components.
99
+
Browser crawlers use the same orchestration with a browser-backed context. Extend <ApiLinkto="class/PlaywrightCrawler">`PlaywrightCrawler`</ApiLink> when an integration needs crawler-level browser behavior or a different handler context. <ApiLinkto="class/StagehandCrawler">`StagehandCrawler`</ApiLink> is an example. It extends `PlaywrightCrawler` with a Stagehand-specific context and browser behavior. If only browser launch or lifecycle differs, a browser plugin is the narrower extension point.
100
+
101
+
See the [HTTP crawlers guide](./http-crawlers) for a worked example built on `selectolax`. The [Architecture overview](./architecture-overview) explains how HTTP and browser crawlers relate to the other components.
89
102
90
103
### HTTP clients
91
104
92
-
An HTTP client is what actually performs the network calls for HTTP-based crawlers. Swapping it changes the transport - the TLS stack, connection pooling, proxy handling, and browser impersonation - without touching how pages are parsed or how the crawl is orchestrated.
105
+
An HTTP client performs network calls for crawlers. Swapping it changes the transport, including the TLS stack, connection pooling, proxy handling, and browser impersonation. It doesn't change how pages are parsed or how the crawl is orchestrated.
93
106
94
107
The contract is <ApiLinkto="class/HttpClient">`HttpClient`</ApiLink>. `crawl` performs a request inside the crawler's pipeline and returns the result the crawler consumes, `send_request` covers standalone calls made from a handler, `stream` yields a response you read incrementally, and `cleanup` releases whatever the client holds open. Crawlee ships <ApiLinkto="class/ImpitHttpClient">`ImpitHttpClient`</ApiLink>, <ApiLinkto="class/HttpxHttpClient">`HttpxHttpClient`</ApiLink>, and <ApiLinkto="class/CurlImpersonateHttpClient">`CurlImpersonateHttpClient`</ApiLink>.
95
108
@@ -99,31 +112,34 @@ See the [HTTP clients guide](./http-clients) for the full contract and the trade
99
112
100
113
A storage client is the backend behind Crawlee's three storages. <ApiLinkto="class/Dataset">`Dataset`</ApiLink>, <ApiLinkto="class/KeyValueStore">`KeyValueStore`</ApiLink>, and <ApiLinkto="class/RequestQueue">`RequestQueue`</ApiLink> are the API you write against, and the storage client decides where that data actually lives. That separation is what lets you move a crawler from the local file system to a database or a cloud service without changing crawl code.
101
114
102
-
<ApiLinkto="class/StorageClient">`StorageClient`</ApiLink> itself is only three factory methods - `create_dataset_client`, `create_kvs_client`, and `create_rq_client`. The real work sits in what they return: <ApiLinkto="class/DatasetClient">`DatasetClient`</ApiLink> handles appending and reading items, <ApiLinkto="class/KeyValueStoreClient">`KeyValueStoreClient`</ApiLink> handles record get, set, delete, and iteration, and <ApiLinkto="class/RequestQueueClient">`RequestQueueClient`</ApiLink> handles adding, fetching, and marking requests as handled. A custom backend implements all four.
115
+
The <ApiLinkto="class/StorageClient">`StorageClient`</ApiLink> contract defines three factory methods: `create_dataset_client`, `create_kvs_client`, and `create_rq_client`. The returned clients define the rest of the contract. <ApiLinkto="class/DatasetClient">`DatasetClient`</ApiLink> handles appending and reading items, <ApiLinkto="class/KeyValueStoreClient">`KeyValueStoreClient`</ApiLink> handles record access and iteration, and <ApiLinkto="class/RequestQueueClient">`RequestQueueClient`</ApiLink> handles adding, fetching, and marking requests as handled. A custom backend implements all four classes.
103
116
104
117
See the [Storage clients guide](./storage-clients) for the built-in implementations and a custom client example.
105
118
106
119
### Browser plugins
107
120
108
-
A browser plugin is what launches browsers for <ApiLinkto="class/PlaywrightCrawler">`PlaywrightCrawler`</ApiLink>. The crawler never launches one itself: it goes through <ApiLinkto="class/BrowserPool">`BrowserPool`</ApiLink>, which initializes the plugins it's given, forwards browser context options when creating pages, and manages each browser's lifecycle.
121
+
A browser plugin launches browsers for <ApiLinkto="class/PlaywrightCrawler">`PlaywrightCrawler`</ApiLink>. The crawler delegates that work to <ApiLinkto="class/BrowserPool">`BrowserPool`</ApiLink>. The pool initializes its plugins, forwards browser context options when creating pages, and manages each browser's lifecycle.
122
+
123
+
The abstract contract is <ApiLinkto="class/BrowserPlugin">`BrowserPlugin`</ApiLink>. Its `new_browser` method launches a browser and returns a <ApiLinkto="class/BrowserController">`BrowserController`</ApiLink>. The pool uses that controller to open pages and tear down the browser. Implement this base contract directly when the launch and lifecycle are too specific for Crawlee's Playwright integration.
109
124
110
-
The contract is <ApiLinkto="class/BrowserPlugin">`BrowserPlugin`</ApiLink>. Its `new_browser` launches a browser and returns a <ApiLinkto="class/BrowserController">`BrowserController`</ApiLink>, which is what the pool then drives to open pages and tear things down. Reach for a subclass when the launch path itself differs from the standard Playwright one, since <ApiLinkto="class/PlaywrightBrowserPlugin">`PlaywrightBrowserPlugin`</ApiLink>'s configuration options already cover the cases where it doesn't.
125
+
Most integrations should start with <ApiLinkto="class/PlaywrightBrowserPlugin">`PlaywrightBrowserPlugin`</ApiLink>. Configure it when its launch and context options cover the required browser. Extend it when you need a custom Playwright-compatible launch path while preserving its standard lifecycle and context handling.
111
126
112
127
See the [Playwright crawler guide](./playwright-crawler) for the responsibilities a subclass has to preserve, and the [Camoufox example](../examples/playwright-crawler-with-camoufox) for a complete integration.
113
128
114
129
## Choosing an extension point
115
130
116
-
Match the layer to what actually differs in your integration.
131
+
Start with configuration before writing a subclass. You can parse a response with a third-party library inside an <ApiLinkto="class/HttpCrawler">`HttpCrawler`</ApiLink> handler, pass an existing `http_client` to any crawler, or configure <ApiLinkto="class/PlaywrightBrowserPlugin">`PlaywrightBrowserPlugin`</ApiLink>. Use an extension contract only when the maintained options don't cover the required behavior.
117
132
118
-
- The response format is one no built-in crawler parses - subclass <ApiLinkto="class/AbstractHttpCrawler">`AbstractHttpCrawler`</ApiLink> with your own parser.
119
-
- The transport differs, but parsing doesn't - implement <ApiLinkto="class/HttpClient">`HttpClient`</ApiLink> and pass it to any HTTP crawler.
120
-
- Data needs to live somewhere Crawlee doesn't support yet - implement <ApiLinkto="class/StorageClient">`StorageClient`</ApiLink> and its three per-storage clients.
121
-
- Browsers need to be launched through a different API - implement <ApiLinkto="class/BrowserPlugin">`BrowserPlugin`</ApiLink> and hand it to <ApiLinkto="class/BrowserPool">`BrowserPool`</ApiLink>.
133
+
- If reusable HTTP parsing and the handler context both need to change, extend <ApiLinkto="class/AbstractHttpCrawler">`AbstractHttpCrawler`</ApiLink> and implement <ApiLinkto="class/AbstractHttpParser">`AbstractHttpParser`</ApiLink>.
134
+
- If browser-level orchestration or the handler context needs to change, extend <ApiLinkto="class/PlaywrightCrawler">`PlaywrightCrawler`</ApiLink>.
135
+
- If the network transport needs to change while crawler behavior stays the same, implement <ApiLinkto="class/HttpClient">`HttpClient`</ApiLink> and pass it to the crawler.
136
+
- If the storage backend needs to change while the storage API stays the same, implement <ApiLinkto="class/StorageClient">`StorageClient`</ApiLink> and its three per-storage clients.
137
+
- If browser launch needs to change while the Playwright lifecycle stays the same, extend <ApiLinkto="class/PlaywrightBrowserPlugin">`PlaywrightBrowserPlugin`</ApiLink>. Implement <ApiLinkto="class/BrowserPlugin">`BrowserPlugin`</ApiLink> directly only when its launch and lifecycle contract needs a different implementation.
122
138
123
139
When more than one fits, pick the narrowest. A custom HTTP client works with every HTTP crawler, so it's easier to maintain than a crawler subclass that hard-codes the same transport.
124
140
125
141
## Conclusion
126
142
127
-
Each extension point is a small abstract class with a documented contract, and everything above it keeps working once you implement one. If you're building a third-party integration, these contracts are also the stable surface to write your own documentation against.
143
+
Each extension point has a documented class contract, and everything above it keeps working once you implement that contract. These public abstract class contracts only change with a major release. That versioning policy makes them the stable surface for a third-party integration and its documentation.
128
144
129
-
If anything here is unclear or you hit a case the contracts don't cover, open an issue on [GitHub](https://github.com/apify/crawlee-python) or join our [Discord](https://discord.com/invite/jyEM2PRvMU).
145
+
If you have questions or need assistance, feel free to reach out on our [GitHub](https://github.com/apify/crawlee-python) or join our [Discord community](https://discord.com/invite/jyEM2PRvMU). Happy scraping!
0 commit comments