langchain-zenrows 0.1.0__tar.gz
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.
- langchain_zenrows-0.1.0/LICENSE +21 -0
- langchain_zenrows-0.1.0/MANIFEST.in +7 -0
- langchain_zenrows-0.1.0/PKG-INFO +243 -0
- langchain_zenrows-0.1.0/README.md +208 -0
- langchain_zenrows-0.1.0/langchain_zenrows/__init__.py +20 -0
- langchain_zenrows-0.1.0/langchain_zenrows/py.typed +1 -0
- langchain_zenrows-0.1.0/langchain_zenrows/zenrows_universal_scraper.py +278 -0
- langchain_zenrows-0.1.0/langchain_zenrows.egg-info/PKG-INFO +243 -0
- langchain_zenrows-0.1.0/langchain_zenrows.egg-info/SOURCES.txt +12 -0
- langchain_zenrows-0.1.0/langchain_zenrows.egg-info/dependency_links.txt +1 -0
- langchain_zenrows-0.1.0/langchain_zenrows.egg-info/requires.txt +13 -0
- langchain_zenrows-0.1.0/langchain_zenrows.egg-info/top_level.txt +1 -0
- langchain_zenrows-0.1.0/pyproject.toml +58 -0
- langchain_zenrows-0.1.0/setup.cfg +4 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 ZenRows
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: langchain-zenrows
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A LangChain integration tool that provides reliable web scraping capabilities at any scale using ZenRows' Universal Scraper API
|
|
5
|
+
Author-email: Yuvraj Chandra <support@zenrows.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/ZenRows-Hub/langchain-zenrows
|
|
8
|
+
Project-URL: Repository, https://github.com/ZenRows-Hub/langchain-zenrows
|
|
9
|
+
Project-URL: Documentation, https://github.com/ZenRows-Hub/langchain-zenrows
|
|
10
|
+
Keywords: langchain,zenrows,web scraping,llm,ai,ml,data extraction
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Requires-Python: >=3.9
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Requires-Dist: langchain-core>=0.3.0
|
|
24
|
+
Requires-Dist: requests>=2.31.0
|
|
25
|
+
Requires-Dist: pydantic>=2.0
|
|
26
|
+
Provides-Extra: test
|
|
27
|
+
Requires-Dist: pytest>=7.0; extra == "test"
|
|
28
|
+
Requires-Dist: pytest-mock>=3.10.0; extra == "test"
|
|
29
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == "test"
|
|
30
|
+
Requires-Dist: pytest-cov>=4.0; extra == "test"
|
|
31
|
+
Requires-Dist: langchain-tests>=0.3.0; extra == "test"
|
|
32
|
+
Provides-Extra: dev
|
|
33
|
+
Requires-Dist: ruff>=0.1.5; extra == "dev"
|
|
34
|
+
Dynamic: license-file
|
|
35
|
+
|
|
36
|
+
# langchain-zenrows
|
|
37
|
+
|
|
38
|
+
The langchain-zenrows integration tool enables LangChain agents to scrape and access web content at any scale using ZenRows' enterprise-grade infrastructure.
|
|
39
|
+
|
|
40
|
+
Whether you need to scrape JavaScript-heavy single-page applications, bypass anti-bot systems, access geo-restricted content, or extract structured data at scale, this integration provides the tools and reliability needed for modern AI applications.
|
|
41
|
+
|
|
42
|
+
## Table of Contents
|
|
43
|
+
|
|
44
|
+
- [Installation](#installation)
|
|
45
|
+
- [Usage](#usage)
|
|
46
|
+
- [API Reference](#api-reference)
|
|
47
|
+
- [Features](#features)
|
|
48
|
+
- [License](#license)
|
|
49
|
+
|
|
50
|
+
## Installation
|
|
51
|
+
|
|
52
|
+
```console
|
|
53
|
+
pip install langchain-zenrows
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Usage
|
|
57
|
+
|
|
58
|
+
To use the ZenRows Universal Scraper with LangChain, you'll need a ZenRows API key. You can sign up for free at [ZenRows](https://app.zenrows.com/register?prod=universal_scraper).
|
|
59
|
+
|
|
60
|
+
> For more comprehensive examples and use cases, see the `examples/` folder.
|
|
61
|
+
|
|
62
|
+
### Basic Usage
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
import os
|
|
66
|
+
from langchain_zenrows import ZenRowsUniversalScraper
|
|
67
|
+
|
|
68
|
+
# Set your ZenRows API key
|
|
69
|
+
os.environ["ZENROWS_API_KEY"] = "<YOUR_ZENROWS_API_KEY>"
|
|
70
|
+
|
|
71
|
+
# Initialize the tool
|
|
72
|
+
scraper = ZenRowsUniversalScraper()
|
|
73
|
+
|
|
74
|
+
# Scrape a simple webpage
|
|
75
|
+
result = scraper.invoke({"url": "https://httpbin.io/html"})
|
|
76
|
+
print(result)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Advanced Usage with Parameters
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
import os
|
|
83
|
+
from langchain_zenrows import ZenRowsUniversalScraper
|
|
84
|
+
|
|
85
|
+
# Set your ZenRows API key
|
|
86
|
+
os.environ["ZENROWS_API_KEY"] = "<YOUR_ZENROWS_API_KEY>"
|
|
87
|
+
|
|
88
|
+
scraper = ZenRowsUniversalScraper()
|
|
89
|
+
|
|
90
|
+
# Scrape with JavaScript rendering and premium proxies
|
|
91
|
+
result = scraper.invoke({
|
|
92
|
+
"url": "https://www.scrapingcourse.com/ecommerce/",
|
|
93
|
+
"js_render": True,
|
|
94
|
+
"premium_proxy": True,
|
|
95
|
+
"proxy_country": "us",
|
|
96
|
+
"response_type": "markdown",
|
|
97
|
+
"wait": 2000 # Wait 2 seconds after page load
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
print(result)
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
See the [API Reference](#api-reference) section below for more available parameters and customizing scraping requests.
|
|
104
|
+
|
|
105
|
+
### Using with LangChain Agents
|
|
106
|
+
|
|
107
|
+
```python
|
|
108
|
+
from langchain_zenrows import ZenRowsUniversalScraper
|
|
109
|
+
from langchain_openai import ChatOpenAI # or your preferred LLM
|
|
110
|
+
from langgraph.prebuilt import create_react_agent
|
|
111
|
+
import os
|
|
112
|
+
|
|
113
|
+
# Set your ZenRows API key
|
|
114
|
+
os.environ["ZENROWS_API_KEY"] = "<YOUR_ZENROWS_API_KEY>"
|
|
115
|
+
os.environ["OPENAI_API_KEY"] = "<YOUR_OPEN_AI_API_KEY>"
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
# Initialize components
|
|
119
|
+
llm = ChatOpenAI(model="gpt-4o-mini")
|
|
120
|
+
zenrows_tool = ZenRowsUniversalScraper()
|
|
121
|
+
|
|
122
|
+
# Create agent
|
|
123
|
+
agent = create_react_agent(llm, [zenrows_tool])
|
|
124
|
+
|
|
125
|
+
# Use the agent
|
|
126
|
+
result = agent.invoke(
|
|
127
|
+
{
|
|
128
|
+
"messages": "Scrape https://news.ycombinator.com/ and list the top 3 stories with title, points, comments, username, and time."
|
|
129
|
+
}
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
print("Agent Response:")
|
|
133
|
+
for message in result["messages"]:
|
|
134
|
+
print(f"{message.content}")
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### CSS Extraction
|
|
138
|
+
|
|
139
|
+
Extract specific data using CSS selectors:
|
|
140
|
+
|
|
141
|
+
```python
|
|
142
|
+
import json
|
|
143
|
+
import os
|
|
144
|
+
from langchain_zenrows import ZenRowsUniversalScraper
|
|
145
|
+
|
|
146
|
+
# Set your ZenRows API key
|
|
147
|
+
os.environ["ZENROWS_API_KEY"] = "<YOUR_ZENROWS_API_KEY>"
|
|
148
|
+
|
|
149
|
+
scraper = ZenRowsUniversalScraper()
|
|
150
|
+
|
|
151
|
+
# Extract specific elements
|
|
152
|
+
css_selector = json.dumps({
|
|
153
|
+
"title": "h1",
|
|
154
|
+
"paragraphs": "p"
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
result = scraper.invoke({
|
|
158
|
+
"url": "https://httpbin.io/html",
|
|
159
|
+
"css_extractor": css_selector
|
|
160
|
+
})
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Premium Proxy with Geo-targeting
|
|
164
|
+
|
|
165
|
+
Access geo-restricted content:
|
|
166
|
+
|
|
167
|
+
```python
|
|
168
|
+
import os
|
|
169
|
+
from langchain_zenrows import ZenRowsUniversalScraper
|
|
170
|
+
|
|
171
|
+
# Set your ZenRows API key
|
|
172
|
+
os.environ["ZENROWS_API_KEY"] = "<YOUR_ZENROWS_API_KEY>"
|
|
173
|
+
|
|
174
|
+
scraper = ZenRowsUniversalScraper()
|
|
175
|
+
|
|
176
|
+
# Check your IP location
|
|
177
|
+
result = scraper.invoke({
|
|
178
|
+
"url": "https://httpbin.io/ip",
|
|
179
|
+
"premium_proxy": True,
|
|
180
|
+
"proxy_country": "us"
|
|
181
|
+
})
|
|
182
|
+
print(result) # Shows the US IP being used
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## API Reference
|
|
186
|
+
|
|
187
|
+
### ZenRowsUniversalScraper
|
|
188
|
+
|
|
189
|
+
Main tool class for web scraping with ZenRows.
|
|
190
|
+
|
|
191
|
+
**Parameters:**
|
|
192
|
+
|
|
193
|
+
- `zenrows_api_key` (str, optional): Your ZenRows API key. If not provided, looks for `ZENROWS_API_KEY` environment variable.
|
|
194
|
+
|
|
195
|
+
**Input Schema:**
|
|
196
|
+
|
|
197
|
+
For complete parameter documentation and details, see the [official ZenRows API Reference](https://docs.zenrows.com/universal-scraper-api/api-reference#parameter-overview).
|
|
198
|
+
|
|
199
|
+
| Parameter | Type | Description |
|
|
200
|
+
|-----------|------|-------------|
|
|
201
|
+
| `url` | str | **Required.** The URL to scrape |
|
|
202
|
+
| `js_render` | bool | Enable JavaScript rendering with a headless browser. Essential for modern web apps, SPAs, and sites with dynamic content (default: False) |
|
|
203
|
+
| `js_instructions` | str | Execute custom JavaScript on the page to interact with elements, scroll, click buttons, or manipulate content |
|
|
204
|
+
| `premium_proxy` | bool | Use residential IPs to bypass anti-bot protection. Essential for accessing protected sites (default: False) |
|
|
205
|
+
| `proxy_country` | str | Set the country of the IP used for the request. Use for accessing geo-restricted content. Two-letter country code |
|
|
206
|
+
| `session_id` | int | Maintain the same IP for multiple requests for up to 10 minutes. Essential for multi-step processes |
|
|
207
|
+
| `custom_headers` | dict | Include custom headers in your request to mimic browser behavior |
|
|
208
|
+
| `wait_for` | str | Wait for a specific CSS Selector to appear in the DOM before returning content |
|
|
209
|
+
| `wait` | int | Wait a fixed amount of milliseconds after page load |
|
|
210
|
+
| `block_resources` | str | Block specific resources (images, fonts, etc.) from loading to speed up scraping |
|
|
211
|
+
| `response_type` | str | Convert HTML to other formats. Options: "markdown", "plaintext", "pdf" |
|
|
212
|
+
| `css_extractor` | str | Extract specific elements using CSS selectors (JSON format) |
|
|
213
|
+
| `autoparse` | bool | Automatically extract structured data from HTML (default: False) |
|
|
214
|
+
| `screenshot` | str | Capture an above-the-fold screenshot of the page (default: "false") |
|
|
215
|
+
| `screenshot_fullpage` | str | Capture a full-page screenshot (default: "false") |
|
|
216
|
+
| `screenshot_selector` | str | Capture a screenshot of a specific element using CSS Selector |
|
|
217
|
+
| `screenshot_format` | str | Choose between "png" (default) and "jpeg" formats for screenshots |
|
|
218
|
+
| `screenshot_quality` | int | For JPEG format, set quality from 1 to 100. Lower values reduce file size but decrease quality |
|
|
219
|
+
| `original_status` | bool | Return the original HTTP status code from the target page (default: False) |
|
|
220
|
+
| `allowed_status_codes` | str | Returns the content even if the target page fails with specified status codes. Useful for debugging or when you need content from error pages |
|
|
221
|
+
| `json_response` | bool | Capture network requests in JSON format, including XHR or Fetch data. Ideal for intercepting API calls made by the web page (default: False) |
|
|
222
|
+
| `outputs` | str | Specify which data types to extract from the scraped HTML. Accepted values: emails, phone_numbers, headings, images, audios, videos, links, menus, hashtags, metadata, tables, favicon |
|
|
223
|
+
|
|
224
|
+
## Features
|
|
225
|
+
|
|
226
|
+
- **JavaScript Rendering**: Scrape modern SPAs and dynamic content
|
|
227
|
+
- **Anti-Bot Bypass**: Bypass sophisticated bot detection systems
|
|
228
|
+
- **Geo-Targeting**: Access region-specific content with 190+ countries
|
|
229
|
+
- **Multiple Output Formats**: HTML, Markdown, Plaintext, PDF, Screenshots
|
|
230
|
+
- **CSS Extraction**: Target specific data with CSS selectors
|
|
231
|
+
- **Structured Data Extraction**: Automatically extract emails, phone numbers, links, and other data types
|
|
232
|
+
- **Session Management**: Maintain consistent sessions across requests
|
|
233
|
+
- **Wait Conditions**: Smart waiting for dynamic content
|
|
234
|
+
- **Premium Proxies**: 55M+ residential IPs for maximum success rates
|
|
235
|
+
|
|
236
|
+
## License
|
|
237
|
+
|
|
238
|
+
`langchain-zenrows` is distributed under the terms of the [MIT](https://spdx.org/licenses/MIT.html) license.
|
|
239
|
+
|
|
240
|
+
## Support
|
|
241
|
+
|
|
242
|
+
- [ZenRows Documentation](https://docs.zenrows.com/)
|
|
243
|
+
- [LangChain Documentation](https://python.langchain.com/)
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
# langchain-zenrows
|
|
2
|
+
|
|
3
|
+
The langchain-zenrows integration tool enables LangChain agents to scrape and access web content at any scale using ZenRows' enterprise-grade infrastructure.
|
|
4
|
+
|
|
5
|
+
Whether you need to scrape JavaScript-heavy single-page applications, bypass anti-bot systems, access geo-restricted content, or extract structured data at scale, this integration provides the tools and reliability needed for modern AI applications.
|
|
6
|
+
|
|
7
|
+
## Table of Contents
|
|
8
|
+
|
|
9
|
+
- [Installation](#installation)
|
|
10
|
+
- [Usage](#usage)
|
|
11
|
+
- [API Reference](#api-reference)
|
|
12
|
+
- [Features](#features)
|
|
13
|
+
- [License](#license)
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```console
|
|
18
|
+
pip install langchain-zenrows
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Usage
|
|
22
|
+
|
|
23
|
+
To use the ZenRows Universal Scraper with LangChain, you'll need a ZenRows API key. You can sign up for free at [ZenRows](https://app.zenrows.com/register?prod=universal_scraper).
|
|
24
|
+
|
|
25
|
+
> For more comprehensive examples and use cases, see the `examples/` folder.
|
|
26
|
+
|
|
27
|
+
### Basic Usage
|
|
28
|
+
|
|
29
|
+
```python
|
|
30
|
+
import os
|
|
31
|
+
from langchain_zenrows import ZenRowsUniversalScraper
|
|
32
|
+
|
|
33
|
+
# Set your ZenRows API key
|
|
34
|
+
os.environ["ZENROWS_API_KEY"] = "<YOUR_ZENROWS_API_KEY>"
|
|
35
|
+
|
|
36
|
+
# Initialize the tool
|
|
37
|
+
scraper = ZenRowsUniversalScraper()
|
|
38
|
+
|
|
39
|
+
# Scrape a simple webpage
|
|
40
|
+
result = scraper.invoke({"url": "https://httpbin.io/html"})
|
|
41
|
+
print(result)
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Advanced Usage with Parameters
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
import os
|
|
48
|
+
from langchain_zenrows import ZenRowsUniversalScraper
|
|
49
|
+
|
|
50
|
+
# Set your ZenRows API key
|
|
51
|
+
os.environ["ZENROWS_API_KEY"] = "<YOUR_ZENROWS_API_KEY>"
|
|
52
|
+
|
|
53
|
+
scraper = ZenRowsUniversalScraper()
|
|
54
|
+
|
|
55
|
+
# Scrape with JavaScript rendering and premium proxies
|
|
56
|
+
result = scraper.invoke({
|
|
57
|
+
"url": "https://www.scrapingcourse.com/ecommerce/",
|
|
58
|
+
"js_render": True,
|
|
59
|
+
"premium_proxy": True,
|
|
60
|
+
"proxy_country": "us",
|
|
61
|
+
"response_type": "markdown",
|
|
62
|
+
"wait": 2000 # Wait 2 seconds after page load
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
print(result)
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
See the [API Reference](#api-reference) section below for more available parameters and customizing scraping requests.
|
|
69
|
+
|
|
70
|
+
### Using with LangChain Agents
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
from langchain_zenrows import ZenRowsUniversalScraper
|
|
74
|
+
from langchain_openai import ChatOpenAI # or your preferred LLM
|
|
75
|
+
from langgraph.prebuilt import create_react_agent
|
|
76
|
+
import os
|
|
77
|
+
|
|
78
|
+
# Set your ZenRows API key
|
|
79
|
+
os.environ["ZENROWS_API_KEY"] = "<YOUR_ZENROWS_API_KEY>"
|
|
80
|
+
os.environ["OPENAI_API_KEY"] = "<YOUR_OPEN_AI_API_KEY>"
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
# Initialize components
|
|
84
|
+
llm = ChatOpenAI(model="gpt-4o-mini")
|
|
85
|
+
zenrows_tool = ZenRowsUniversalScraper()
|
|
86
|
+
|
|
87
|
+
# Create agent
|
|
88
|
+
agent = create_react_agent(llm, [zenrows_tool])
|
|
89
|
+
|
|
90
|
+
# Use the agent
|
|
91
|
+
result = agent.invoke(
|
|
92
|
+
{
|
|
93
|
+
"messages": "Scrape https://news.ycombinator.com/ and list the top 3 stories with title, points, comments, username, and time."
|
|
94
|
+
}
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
print("Agent Response:")
|
|
98
|
+
for message in result["messages"]:
|
|
99
|
+
print(f"{message.content}")
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### CSS Extraction
|
|
103
|
+
|
|
104
|
+
Extract specific data using CSS selectors:
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
import json
|
|
108
|
+
import os
|
|
109
|
+
from langchain_zenrows import ZenRowsUniversalScraper
|
|
110
|
+
|
|
111
|
+
# Set your ZenRows API key
|
|
112
|
+
os.environ["ZENROWS_API_KEY"] = "<YOUR_ZENROWS_API_KEY>"
|
|
113
|
+
|
|
114
|
+
scraper = ZenRowsUniversalScraper()
|
|
115
|
+
|
|
116
|
+
# Extract specific elements
|
|
117
|
+
css_selector = json.dumps({
|
|
118
|
+
"title": "h1",
|
|
119
|
+
"paragraphs": "p"
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
result = scraper.invoke({
|
|
123
|
+
"url": "https://httpbin.io/html",
|
|
124
|
+
"css_extractor": css_selector
|
|
125
|
+
})
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Premium Proxy with Geo-targeting
|
|
129
|
+
|
|
130
|
+
Access geo-restricted content:
|
|
131
|
+
|
|
132
|
+
```python
|
|
133
|
+
import os
|
|
134
|
+
from langchain_zenrows import ZenRowsUniversalScraper
|
|
135
|
+
|
|
136
|
+
# Set your ZenRows API key
|
|
137
|
+
os.environ["ZENROWS_API_KEY"] = "<YOUR_ZENROWS_API_KEY>"
|
|
138
|
+
|
|
139
|
+
scraper = ZenRowsUniversalScraper()
|
|
140
|
+
|
|
141
|
+
# Check your IP location
|
|
142
|
+
result = scraper.invoke({
|
|
143
|
+
"url": "https://httpbin.io/ip",
|
|
144
|
+
"premium_proxy": True,
|
|
145
|
+
"proxy_country": "us"
|
|
146
|
+
})
|
|
147
|
+
print(result) # Shows the US IP being used
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## API Reference
|
|
151
|
+
|
|
152
|
+
### ZenRowsUniversalScraper
|
|
153
|
+
|
|
154
|
+
Main tool class for web scraping with ZenRows.
|
|
155
|
+
|
|
156
|
+
**Parameters:**
|
|
157
|
+
|
|
158
|
+
- `zenrows_api_key` (str, optional): Your ZenRows API key. If not provided, looks for `ZENROWS_API_KEY` environment variable.
|
|
159
|
+
|
|
160
|
+
**Input Schema:**
|
|
161
|
+
|
|
162
|
+
For complete parameter documentation and details, see the [official ZenRows API Reference](https://docs.zenrows.com/universal-scraper-api/api-reference#parameter-overview).
|
|
163
|
+
|
|
164
|
+
| Parameter | Type | Description |
|
|
165
|
+
|-----------|------|-------------|
|
|
166
|
+
| `url` | str | **Required.** The URL to scrape |
|
|
167
|
+
| `js_render` | bool | Enable JavaScript rendering with a headless browser. Essential for modern web apps, SPAs, and sites with dynamic content (default: False) |
|
|
168
|
+
| `js_instructions` | str | Execute custom JavaScript on the page to interact with elements, scroll, click buttons, or manipulate content |
|
|
169
|
+
| `premium_proxy` | bool | Use residential IPs to bypass anti-bot protection. Essential for accessing protected sites (default: False) |
|
|
170
|
+
| `proxy_country` | str | Set the country of the IP used for the request. Use for accessing geo-restricted content. Two-letter country code |
|
|
171
|
+
| `session_id` | int | Maintain the same IP for multiple requests for up to 10 minutes. Essential for multi-step processes |
|
|
172
|
+
| `custom_headers` | dict | Include custom headers in your request to mimic browser behavior |
|
|
173
|
+
| `wait_for` | str | Wait for a specific CSS Selector to appear in the DOM before returning content |
|
|
174
|
+
| `wait` | int | Wait a fixed amount of milliseconds after page load |
|
|
175
|
+
| `block_resources` | str | Block specific resources (images, fonts, etc.) from loading to speed up scraping |
|
|
176
|
+
| `response_type` | str | Convert HTML to other formats. Options: "markdown", "plaintext", "pdf" |
|
|
177
|
+
| `css_extractor` | str | Extract specific elements using CSS selectors (JSON format) |
|
|
178
|
+
| `autoparse` | bool | Automatically extract structured data from HTML (default: False) |
|
|
179
|
+
| `screenshot` | str | Capture an above-the-fold screenshot of the page (default: "false") |
|
|
180
|
+
| `screenshot_fullpage` | str | Capture a full-page screenshot (default: "false") |
|
|
181
|
+
| `screenshot_selector` | str | Capture a screenshot of a specific element using CSS Selector |
|
|
182
|
+
| `screenshot_format` | str | Choose between "png" (default) and "jpeg" formats for screenshots |
|
|
183
|
+
| `screenshot_quality` | int | For JPEG format, set quality from 1 to 100. Lower values reduce file size but decrease quality |
|
|
184
|
+
| `original_status` | bool | Return the original HTTP status code from the target page (default: False) |
|
|
185
|
+
| `allowed_status_codes` | str | Returns the content even if the target page fails with specified status codes. Useful for debugging or when you need content from error pages |
|
|
186
|
+
| `json_response` | bool | Capture network requests in JSON format, including XHR or Fetch data. Ideal for intercepting API calls made by the web page (default: False) |
|
|
187
|
+
| `outputs` | str | Specify which data types to extract from the scraped HTML. Accepted values: emails, phone_numbers, headings, images, audios, videos, links, menus, hashtags, metadata, tables, favicon |
|
|
188
|
+
|
|
189
|
+
## Features
|
|
190
|
+
|
|
191
|
+
- **JavaScript Rendering**: Scrape modern SPAs and dynamic content
|
|
192
|
+
- **Anti-Bot Bypass**: Bypass sophisticated bot detection systems
|
|
193
|
+
- **Geo-Targeting**: Access region-specific content with 190+ countries
|
|
194
|
+
- **Multiple Output Formats**: HTML, Markdown, Plaintext, PDF, Screenshots
|
|
195
|
+
- **CSS Extraction**: Target specific data with CSS selectors
|
|
196
|
+
- **Structured Data Extraction**: Automatically extract emails, phone numbers, links, and other data types
|
|
197
|
+
- **Session Management**: Maintain consistent sessions across requests
|
|
198
|
+
- **Wait Conditions**: Smart waiting for dynamic content
|
|
199
|
+
- **Premium Proxies**: 55M+ residential IPs for maximum success rates
|
|
200
|
+
|
|
201
|
+
## License
|
|
202
|
+
|
|
203
|
+
`langchain-zenrows` is distributed under the terms of the [MIT](https://spdx.org/licenses/MIT.html) license.
|
|
204
|
+
|
|
205
|
+
## Support
|
|
206
|
+
|
|
207
|
+
- [ZenRows Documentation](https://docs.zenrows.com/)
|
|
208
|
+
- [LangChain Documentation](https://python.langchain.com/)
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"""LangChain ZenRows integration package.
|
|
2
|
+
|
|
3
|
+
This package provides integration between LangChain and ZenRows Universal Scraper API,
|
|
4
|
+
enabling powerful web scraping capabilities with anti-bot bypass, JavaScript
|
|
5
|
+
rendering, and geo-targeting features.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from langchain_zenrows.zenrows_universal_scraper import (
|
|
9
|
+
ZenRowsUniversalScraper,
|
|
10
|
+
ZenRowsUniversalScraperAPIWrapper,
|
|
11
|
+
ZenRowsUniversalScraperInput,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
__version__ = "0.1.0"
|
|
15
|
+
|
|
16
|
+
__all__ = [
|
|
17
|
+
"ZenRowsUniversalScraper",
|
|
18
|
+
"ZenRowsUniversalScraperAPIWrapper",
|
|
19
|
+
"ZenRowsUniversalScraperInput",
|
|
20
|
+
]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# This file indicates that the package supports type hints
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
"""ZenRows Universal Scraper API integration for LangChain."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import os
|
|
5
|
+
from typing import Any, Dict, Literal, Optional, Type, Union
|
|
6
|
+
|
|
7
|
+
import requests
|
|
8
|
+
from langchain_core.tools import BaseTool
|
|
9
|
+
from pydantic import BaseModel, Field, field_validator
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class ZenRowsUniversalScraperInput(BaseModel):
|
|
13
|
+
"""Input schema for ZenRows Universal Scraper API."""
|
|
14
|
+
|
|
15
|
+
url: str = Field(description="The URL of the page you want to scrape")
|
|
16
|
+
js_render: Optional[bool] = Field(
|
|
17
|
+
default=False,
|
|
18
|
+
description="Enable JavaScript rendering with a headless browser. Essential for modern web apps, SPAs, and sites with dynamic content.",
|
|
19
|
+
)
|
|
20
|
+
js_instructions: Optional[str] = Field(
|
|
21
|
+
default=None,
|
|
22
|
+
description="Execute custom JavaScript on the page to interact with elements, scroll, click buttons, or manipulate content.",
|
|
23
|
+
)
|
|
24
|
+
premium_proxy: Optional[bool] = Field(
|
|
25
|
+
default=False,
|
|
26
|
+
description="Use residential IPs to bypass anti-bot protection. Essential for accessing protected sites.",
|
|
27
|
+
)
|
|
28
|
+
proxy_country: Optional[str] = Field(
|
|
29
|
+
default=None,
|
|
30
|
+
description="Set the country of the IP used for the request (requires Premium Proxies). Use for accessing geo-restricted content.",
|
|
31
|
+
)
|
|
32
|
+
session_id: Optional[int] = Field(
|
|
33
|
+
default=None,
|
|
34
|
+
description="Maintain the same IP for multiple requests for up to 10 minutes. Essential for multi-step processes.",
|
|
35
|
+
)
|
|
36
|
+
custom_headers: Optional[Dict[str, str]] = Field(
|
|
37
|
+
default=None,
|
|
38
|
+
description="Include custom headers in your request to mimic browser behavior.",
|
|
39
|
+
)
|
|
40
|
+
wait_for: Optional[str] = Field(
|
|
41
|
+
default=None,
|
|
42
|
+
description="Wait for a specific CSS Selector to appear in the DOM before returning content.",
|
|
43
|
+
)
|
|
44
|
+
wait: Optional[int] = Field(
|
|
45
|
+
default=None, description="Wait a fixed amount of milliseconds after page load."
|
|
46
|
+
)
|
|
47
|
+
block_resources: Optional[str] = Field(
|
|
48
|
+
default=None,
|
|
49
|
+
description="Block specific resources (images, fonts, etc.) from loading to speed up scraping.",
|
|
50
|
+
)
|
|
51
|
+
response_type: Optional[Literal["markdown", "plaintext", "pdf"]] = Field(
|
|
52
|
+
default=None,
|
|
53
|
+
description="Convert HTML to other formats. Options: markdown, plaintext, pdf.",
|
|
54
|
+
)
|
|
55
|
+
css_extractor: Optional[str] = Field(
|
|
56
|
+
default=None,
|
|
57
|
+
description="Extract specific elements using CSS selectors (JSON format).",
|
|
58
|
+
)
|
|
59
|
+
autoparse: Optional[bool] = Field(
|
|
60
|
+
default=False, description="Automatically extract structured data from HTML."
|
|
61
|
+
)
|
|
62
|
+
screenshot: Optional[str] = Field(
|
|
63
|
+
default=None, description="Capture an above-the-fold screenshot of the page."
|
|
64
|
+
)
|
|
65
|
+
screenshot_fullpage: Optional[str] = Field(
|
|
66
|
+
default=None, description="Capture a full-page screenshot."
|
|
67
|
+
)
|
|
68
|
+
screenshot_selector: Optional[str] = Field(
|
|
69
|
+
default=None,
|
|
70
|
+
description="Capture a screenshot of a specific element using CSS Selector.",
|
|
71
|
+
)
|
|
72
|
+
original_status: Optional[bool] = Field(
|
|
73
|
+
default=False,
|
|
74
|
+
description="Return the original HTTP status code from the target page.",
|
|
75
|
+
)
|
|
76
|
+
allowed_status_codes: Optional[str] = Field(
|
|
77
|
+
default=None,
|
|
78
|
+
description="Returns the content even if the target page fails with specified status codes. Useful for debugging or when you need content from error pages.",
|
|
79
|
+
)
|
|
80
|
+
json_response: Optional[bool] = Field(
|
|
81
|
+
default=False,
|
|
82
|
+
description="Capture network requests in JSON format, including XHR or Fetch data. Ideal for intercepting API calls made by the web page.",
|
|
83
|
+
)
|
|
84
|
+
screenshot_format: Optional[Literal["png", "jpeg"]] = Field(
|
|
85
|
+
default=None,
|
|
86
|
+
description="Choose between png (default) and jpeg formats for screenshots.",
|
|
87
|
+
)
|
|
88
|
+
screenshot_quality: Optional[int] = Field(
|
|
89
|
+
default=None,
|
|
90
|
+
description="For JPEG format, set quality from 1 to 100. Lower values reduce file size but decrease quality.",
|
|
91
|
+
)
|
|
92
|
+
outputs: Optional[str] = Field(
|
|
93
|
+
default=None,
|
|
94
|
+
description="Specify which data types to extract from the scraped HTML. Accepted values: emails, phone_numbers, headings, images, audios, videos, links, menus, hashtags, metadata, tables, favicon.",
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
@field_validator("css_extractor")
|
|
98
|
+
@classmethod
|
|
99
|
+
def validate_css_extractor(cls, v):
|
|
100
|
+
"""Validate that css_extractor is valid JSON if provided."""
|
|
101
|
+
if v is not None:
|
|
102
|
+
try:
|
|
103
|
+
json.loads(v)
|
|
104
|
+
except json.JSONDecodeError:
|
|
105
|
+
raise ValueError("css_extractor must be valid JSON")
|
|
106
|
+
return v
|
|
107
|
+
|
|
108
|
+
@field_validator("proxy_country")
|
|
109
|
+
@classmethod
|
|
110
|
+
def validate_proxy_country(cls, v):
|
|
111
|
+
"""Validate that proxy_country is a two-letter country code."""
|
|
112
|
+
if v is not None and len(v) != 2:
|
|
113
|
+
raise ValueError("proxy_country must be a two-letter country code")
|
|
114
|
+
return v
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
class ZenRowsUniversalScraper(BaseTool):
|
|
118
|
+
"""ZenRows Universal Scraper API tool for LangChain.
|
|
119
|
+
|
|
120
|
+
This tool provides access to ZenRows' Universal Scraper API, enabling reliable
|
|
121
|
+
web scraping with advanced features like JavaScript rendering, premium proxies,
|
|
122
|
+
and anti-bot bypass.
|
|
123
|
+
|
|
124
|
+
To use this tool, you must sign up for a ZenRows account and obtain an API key.
|
|
125
|
+
Visit https://www.zenrows.com/ to get started.
|
|
126
|
+
"""
|
|
127
|
+
|
|
128
|
+
name: str = "zenrows_universal_scraper"
|
|
129
|
+
description: str = (
|
|
130
|
+
"A powerful web scraping tool that can extract data from websites with "
|
|
131
|
+
"anti-bot protection, JavaScript rendering, and geo-targeting capabilities. "
|
|
132
|
+
"Use this when you need to scrape modern websites, bypass bot detection, "
|
|
133
|
+
"or access geo-restricted content. Supports multiple output formats including "
|
|
134
|
+
"HTML, Markdown, and screenshots."
|
|
135
|
+
)
|
|
136
|
+
args_schema: Type[BaseModel] = ZenRowsUniversalScraperInput
|
|
137
|
+
|
|
138
|
+
zenrows_api_key: Optional[str] = None
|
|
139
|
+
base_url: str = "https://api.zenrows.com/v1/"
|
|
140
|
+
|
|
141
|
+
def __init__(self, zenrows_api_key: Optional[str] = None, **kwargs):
|
|
142
|
+
"""Initialize the ZenRows Universal Scraper tool.
|
|
143
|
+
|
|
144
|
+
Args:
|
|
145
|
+
zenrows_api_key: Your ZenRows API key. If not provided, will look for
|
|
146
|
+
ZENROWS_API_KEY environment variable.
|
|
147
|
+
**kwargs: Additional arguments passed to BaseTool.
|
|
148
|
+
"""
|
|
149
|
+
super().__init__(**kwargs)
|
|
150
|
+
self.zenrows_api_key = zenrows_api_key or os.environ.get("ZENROWS_API_KEY")
|
|
151
|
+
|
|
152
|
+
if not self.zenrows_api_key:
|
|
153
|
+
raise ValueError(
|
|
154
|
+
"ZenRows API key is required. Set ZENROWS_API_KEY environment "
|
|
155
|
+
"variable or pass zenrows_api_key parameter."
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
def _prepare_request_params(
|
|
159
|
+
self, tool_input: Union[str, Dict[str, Any]]
|
|
160
|
+
) -> Dict[str, Any]:
|
|
161
|
+
"""Prepare request parameters for the ZenRows API."""
|
|
162
|
+
# Handle string input (just URL)
|
|
163
|
+
if isinstance(tool_input, str):
|
|
164
|
+
params = {"url": tool_input}
|
|
165
|
+
else:
|
|
166
|
+
params = tool_input.copy()
|
|
167
|
+
|
|
168
|
+
# Auto-enable js_render for parameters that require JavaScript rendering
|
|
169
|
+
js_required_params = [
|
|
170
|
+
"screenshot",
|
|
171
|
+
"screenshot_fullpage",
|
|
172
|
+
"screenshot_selector",
|
|
173
|
+
"js_instructions",
|
|
174
|
+
"json_response",
|
|
175
|
+
"wait",
|
|
176
|
+
"wait_for",
|
|
177
|
+
]
|
|
178
|
+
js_required = any(params.get(param) for param in js_required_params)
|
|
179
|
+
|
|
180
|
+
if js_required:
|
|
181
|
+
# If any parameter requiring JS is provided, enable js_render
|
|
182
|
+
params["js_render"] = True
|
|
183
|
+
|
|
184
|
+
# Special handling for screenshot variants
|
|
185
|
+
screenshot_variants = ["screenshot_fullpage", "screenshot_selector"]
|
|
186
|
+
if any(params.get(param) for param in screenshot_variants):
|
|
187
|
+
# If screenshot_fullpage or screenshot_selector is provided,
|
|
188
|
+
# also enable the base screenshot parameter
|
|
189
|
+
params["screenshot"] = "true"
|
|
190
|
+
|
|
191
|
+
# Auto-enable premium_proxy when proxy_country is specified
|
|
192
|
+
if params.get("proxy_country"):
|
|
193
|
+
params["premium_proxy"] = True
|
|
194
|
+
|
|
195
|
+
# Add required API key
|
|
196
|
+
params["apikey"] = self.zenrows_api_key
|
|
197
|
+
|
|
198
|
+
# Handle custom headers according to ZenRows API documentation
|
|
199
|
+
request_headers = None
|
|
200
|
+
if "custom_headers" in params and params["custom_headers"]:
|
|
201
|
+
# Store the headers dictionary for the request
|
|
202
|
+
request_headers = params["custom_headers"]
|
|
203
|
+
# Set custom_headers to "true" to enable custom header support in the API
|
|
204
|
+
params["custom_headers"] = "true"
|
|
205
|
+
else:
|
|
206
|
+
# Remove custom_headers if not provided or empty
|
|
207
|
+
params.pop("custom_headers", None)
|
|
208
|
+
|
|
209
|
+
# Remove None values to avoid sending unnecessary parameters
|
|
210
|
+
params = {k: v for k, v in params.items() if v is not None}
|
|
211
|
+
|
|
212
|
+
return params, request_headers
|
|
213
|
+
|
|
214
|
+
def _run(self, **kwargs) -> str:
|
|
215
|
+
"""Execute the ZenRows Universal Scraper API request.
|
|
216
|
+
|
|
217
|
+
Returns:
|
|
218
|
+
The scraped content as a string, format depends on response_type parameter.
|
|
219
|
+
"""
|
|
220
|
+
try:
|
|
221
|
+
params, request_headers = self._prepare_request_params(kwargs)
|
|
222
|
+
|
|
223
|
+
# Make the API request
|
|
224
|
+
# Note: ZenRows automatically handles User-Agent and other headers
|
|
225
|
+
response = requests.get(
|
|
226
|
+
self.base_url,
|
|
227
|
+
params=params,
|
|
228
|
+
headers=request_headers, # Pass custom headers if provided
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
# Check for successful response
|
|
232
|
+
response.raise_for_status()
|
|
233
|
+
|
|
234
|
+
# Handle different response types
|
|
235
|
+
screenshot_params = [
|
|
236
|
+
"screenshot",
|
|
237
|
+
"screenshot_fullpage",
|
|
238
|
+
"screenshot_selector",
|
|
239
|
+
]
|
|
240
|
+
if any(param in kwargs and kwargs[param] for param in screenshot_params):
|
|
241
|
+
# For screenshots, return base64 encoded content with metadata
|
|
242
|
+
return response.content
|
|
243
|
+
|
|
244
|
+
# For text content, return the response text
|
|
245
|
+
return response.text
|
|
246
|
+
|
|
247
|
+
except requests.exceptions.HTTPError as e:
|
|
248
|
+
if e.response.status_code == 401:
|
|
249
|
+
raise ValueError("Invalid ZenRows API key")
|
|
250
|
+
elif e.response.status_code == 429:
|
|
251
|
+
raise ValueError("Rate limit exceeded. Check your ZenRows plan limits.")
|
|
252
|
+
elif e.response.status_code == 413:
|
|
253
|
+
raise ValueError(
|
|
254
|
+
"Response size too large. Consider using CSS selectors to reduce content."
|
|
255
|
+
)
|
|
256
|
+
else:
|
|
257
|
+
raise ValueError(
|
|
258
|
+
f"HTTP error occurred: {e.response.status_code} - {e.response.text}"
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
except requests.exceptions.Timeout:
|
|
262
|
+
raise ValueError(
|
|
263
|
+
"Request timed out. The website might be slow or unresponsive."
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
except requests.exceptions.RequestException as e:
|
|
267
|
+
raise ValueError(f"Request failed: {str(e)}")
|
|
268
|
+
|
|
269
|
+
except Exception as e:
|
|
270
|
+
raise ValueError(f"Unexpected error: {str(e)}")
|
|
271
|
+
|
|
272
|
+
async def _arun(self, **kwargs) -> str:
|
|
273
|
+
"""Async version of _run method."""
|
|
274
|
+
return self._run(**kwargs)
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
# For backward compatibility and easier imports
|
|
278
|
+
ZenRowsUniversalScraperAPIWrapper = ZenRowsUniversalScraper
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: langchain-zenrows
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A LangChain integration tool that provides reliable web scraping capabilities at any scale using ZenRows' Universal Scraper API
|
|
5
|
+
Author-email: Yuvraj Chandra <support@zenrows.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/ZenRows-Hub/langchain-zenrows
|
|
8
|
+
Project-URL: Repository, https://github.com/ZenRows-Hub/langchain-zenrows
|
|
9
|
+
Project-URL: Documentation, https://github.com/ZenRows-Hub/langchain-zenrows
|
|
10
|
+
Keywords: langchain,zenrows,web scraping,llm,ai,ml,data extraction
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Requires-Python: >=3.9
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Requires-Dist: langchain-core>=0.3.0
|
|
24
|
+
Requires-Dist: requests>=2.31.0
|
|
25
|
+
Requires-Dist: pydantic>=2.0
|
|
26
|
+
Provides-Extra: test
|
|
27
|
+
Requires-Dist: pytest>=7.0; extra == "test"
|
|
28
|
+
Requires-Dist: pytest-mock>=3.10.0; extra == "test"
|
|
29
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == "test"
|
|
30
|
+
Requires-Dist: pytest-cov>=4.0; extra == "test"
|
|
31
|
+
Requires-Dist: langchain-tests>=0.3.0; extra == "test"
|
|
32
|
+
Provides-Extra: dev
|
|
33
|
+
Requires-Dist: ruff>=0.1.5; extra == "dev"
|
|
34
|
+
Dynamic: license-file
|
|
35
|
+
|
|
36
|
+
# langchain-zenrows
|
|
37
|
+
|
|
38
|
+
The langchain-zenrows integration tool enables LangChain agents to scrape and access web content at any scale using ZenRows' enterprise-grade infrastructure.
|
|
39
|
+
|
|
40
|
+
Whether you need to scrape JavaScript-heavy single-page applications, bypass anti-bot systems, access geo-restricted content, or extract structured data at scale, this integration provides the tools and reliability needed for modern AI applications.
|
|
41
|
+
|
|
42
|
+
## Table of Contents
|
|
43
|
+
|
|
44
|
+
- [Installation](#installation)
|
|
45
|
+
- [Usage](#usage)
|
|
46
|
+
- [API Reference](#api-reference)
|
|
47
|
+
- [Features](#features)
|
|
48
|
+
- [License](#license)
|
|
49
|
+
|
|
50
|
+
## Installation
|
|
51
|
+
|
|
52
|
+
```console
|
|
53
|
+
pip install langchain-zenrows
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Usage
|
|
57
|
+
|
|
58
|
+
To use the ZenRows Universal Scraper with LangChain, you'll need a ZenRows API key. You can sign up for free at [ZenRows](https://app.zenrows.com/register?prod=universal_scraper).
|
|
59
|
+
|
|
60
|
+
> For more comprehensive examples and use cases, see the `examples/` folder.
|
|
61
|
+
|
|
62
|
+
### Basic Usage
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
import os
|
|
66
|
+
from langchain_zenrows import ZenRowsUniversalScraper
|
|
67
|
+
|
|
68
|
+
# Set your ZenRows API key
|
|
69
|
+
os.environ["ZENROWS_API_KEY"] = "<YOUR_ZENROWS_API_KEY>"
|
|
70
|
+
|
|
71
|
+
# Initialize the tool
|
|
72
|
+
scraper = ZenRowsUniversalScraper()
|
|
73
|
+
|
|
74
|
+
# Scrape a simple webpage
|
|
75
|
+
result = scraper.invoke({"url": "https://httpbin.io/html"})
|
|
76
|
+
print(result)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Advanced Usage with Parameters
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
import os
|
|
83
|
+
from langchain_zenrows import ZenRowsUniversalScraper
|
|
84
|
+
|
|
85
|
+
# Set your ZenRows API key
|
|
86
|
+
os.environ["ZENROWS_API_KEY"] = "<YOUR_ZENROWS_API_KEY>"
|
|
87
|
+
|
|
88
|
+
scraper = ZenRowsUniversalScraper()
|
|
89
|
+
|
|
90
|
+
# Scrape with JavaScript rendering and premium proxies
|
|
91
|
+
result = scraper.invoke({
|
|
92
|
+
"url": "https://www.scrapingcourse.com/ecommerce/",
|
|
93
|
+
"js_render": True,
|
|
94
|
+
"premium_proxy": True,
|
|
95
|
+
"proxy_country": "us",
|
|
96
|
+
"response_type": "markdown",
|
|
97
|
+
"wait": 2000 # Wait 2 seconds after page load
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
print(result)
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
See the [API Reference](#api-reference) section below for more available parameters and customizing scraping requests.
|
|
104
|
+
|
|
105
|
+
### Using with LangChain Agents
|
|
106
|
+
|
|
107
|
+
```python
|
|
108
|
+
from langchain_zenrows import ZenRowsUniversalScraper
|
|
109
|
+
from langchain_openai import ChatOpenAI # or your preferred LLM
|
|
110
|
+
from langgraph.prebuilt import create_react_agent
|
|
111
|
+
import os
|
|
112
|
+
|
|
113
|
+
# Set your ZenRows API key
|
|
114
|
+
os.environ["ZENROWS_API_KEY"] = "<YOUR_ZENROWS_API_KEY>"
|
|
115
|
+
os.environ["OPENAI_API_KEY"] = "<YOUR_OPEN_AI_API_KEY>"
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
# Initialize components
|
|
119
|
+
llm = ChatOpenAI(model="gpt-4o-mini")
|
|
120
|
+
zenrows_tool = ZenRowsUniversalScraper()
|
|
121
|
+
|
|
122
|
+
# Create agent
|
|
123
|
+
agent = create_react_agent(llm, [zenrows_tool])
|
|
124
|
+
|
|
125
|
+
# Use the agent
|
|
126
|
+
result = agent.invoke(
|
|
127
|
+
{
|
|
128
|
+
"messages": "Scrape https://news.ycombinator.com/ and list the top 3 stories with title, points, comments, username, and time."
|
|
129
|
+
}
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
print("Agent Response:")
|
|
133
|
+
for message in result["messages"]:
|
|
134
|
+
print(f"{message.content}")
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### CSS Extraction
|
|
138
|
+
|
|
139
|
+
Extract specific data using CSS selectors:
|
|
140
|
+
|
|
141
|
+
```python
|
|
142
|
+
import json
|
|
143
|
+
import os
|
|
144
|
+
from langchain_zenrows import ZenRowsUniversalScraper
|
|
145
|
+
|
|
146
|
+
# Set your ZenRows API key
|
|
147
|
+
os.environ["ZENROWS_API_KEY"] = "<YOUR_ZENROWS_API_KEY>"
|
|
148
|
+
|
|
149
|
+
scraper = ZenRowsUniversalScraper()
|
|
150
|
+
|
|
151
|
+
# Extract specific elements
|
|
152
|
+
css_selector = json.dumps({
|
|
153
|
+
"title": "h1",
|
|
154
|
+
"paragraphs": "p"
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
result = scraper.invoke({
|
|
158
|
+
"url": "https://httpbin.io/html",
|
|
159
|
+
"css_extractor": css_selector
|
|
160
|
+
})
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Premium Proxy with Geo-targeting
|
|
164
|
+
|
|
165
|
+
Access geo-restricted content:
|
|
166
|
+
|
|
167
|
+
```python
|
|
168
|
+
import os
|
|
169
|
+
from langchain_zenrows import ZenRowsUniversalScraper
|
|
170
|
+
|
|
171
|
+
# Set your ZenRows API key
|
|
172
|
+
os.environ["ZENROWS_API_KEY"] = "<YOUR_ZENROWS_API_KEY>"
|
|
173
|
+
|
|
174
|
+
scraper = ZenRowsUniversalScraper()
|
|
175
|
+
|
|
176
|
+
# Check your IP location
|
|
177
|
+
result = scraper.invoke({
|
|
178
|
+
"url": "https://httpbin.io/ip",
|
|
179
|
+
"premium_proxy": True,
|
|
180
|
+
"proxy_country": "us"
|
|
181
|
+
})
|
|
182
|
+
print(result) # Shows the US IP being used
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## API Reference
|
|
186
|
+
|
|
187
|
+
### ZenRowsUniversalScraper
|
|
188
|
+
|
|
189
|
+
Main tool class for web scraping with ZenRows.
|
|
190
|
+
|
|
191
|
+
**Parameters:**
|
|
192
|
+
|
|
193
|
+
- `zenrows_api_key` (str, optional): Your ZenRows API key. If not provided, looks for `ZENROWS_API_KEY` environment variable.
|
|
194
|
+
|
|
195
|
+
**Input Schema:**
|
|
196
|
+
|
|
197
|
+
For complete parameter documentation and details, see the [official ZenRows API Reference](https://docs.zenrows.com/universal-scraper-api/api-reference#parameter-overview).
|
|
198
|
+
|
|
199
|
+
| Parameter | Type | Description |
|
|
200
|
+
|-----------|------|-------------|
|
|
201
|
+
| `url` | str | **Required.** The URL to scrape |
|
|
202
|
+
| `js_render` | bool | Enable JavaScript rendering with a headless browser. Essential for modern web apps, SPAs, and sites with dynamic content (default: False) |
|
|
203
|
+
| `js_instructions` | str | Execute custom JavaScript on the page to interact with elements, scroll, click buttons, or manipulate content |
|
|
204
|
+
| `premium_proxy` | bool | Use residential IPs to bypass anti-bot protection. Essential for accessing protected sites (default: False) |
|
|
205
|
+
| `proxy_country` | str | Set the country of the IP used for the request. Use for accessing geo-restricted content. Two-letter country code |
|
|
206
|
+
| `session_id` | int | Maintain the same IP for multiple requests for up to 10 minutes. Essential for multi-step processes |
|
|
207
|
+
| `custom_headers` | dict | Include custom headers in your request to mimic browser behavior |
|
|
208
|
+
| `wait_for` | str | Wait for a specific CSS Selector to appear in the DOM before returning content |
|
|
209
|
+
| `wait` | int | Wait a fixed amount of milliseconds after page load |
|
|
210
|
+
| `block_resources` | str | Block specific resources (images, fonts, etc.) from loading to speed up scraping |
|
|
211
|
+
| `response_type` | str | Convert HTML to other formats. Options: "markdown", "plaintext", "pdf" |
|
|
212
|
+
| `css_extractor` | str | Extract specific elements using CSS selectors (JSON format) |
|
|
213
|
+
| `autoparse` | bool | Automatically extract structured data from HTML (default: False) |
|
|
214
|
+
| `screenshot` | str | Capture an above-the-fold screenshot of the page (default: "false") |
|
|
215
|
+
| `screenshot_fullpage` | str | Capture a full-page screenshot (default: "false") |
|
|
216
|
+
| `screenshot_selector` | str | Capture a screenshot of a specific element using CSS Selector |
|
|
217
|
+
| `screenshot_format` | str | Choose between "png" (default) and "jpeg" formats for screenshots |
|
|
218
|
+
| `screenshot_quality` | int | For JPEG format, set quality from 1 to 100. Lower values reduce file size but decrease quality |
|
|
219
|
+
| `original_status` | bool | Return the original HTTP status code from the target page (default: False) |
|
|
220
|
+
| `allowed_status_codes` | str | Returns the content even if the target page fails with specified status codes. Useful for debugging or when you need content from error pages |
|
|
221
|
+
| `json_response` | bool | Capture network requests in JSON format, including XHR or Fetch data. Ideal for intercepting API calls made by the web page (default: False) |
|
|
222
|
+
| `outputs` | str | Specify which data types to extract from the scraped HTML. Accepted values: emails, phone_numbers, headings, images, audios, videos, links, menus, hashtags, metadata, tables, favicon |
|
|
223
|
+
|
|
224
|
+
## Features
|
|
225
|
+
|
|
226
|
+
- **JavaScript Rendering**: Scrape modern SPAs and dynamic content
|
|
227
|
+
- **Anti-Bot Bypass**: Bypass sophisticated bot detection systems
|
|
228
|
+
- **Geo-Targeting**: Access region-specific content with 190+ countries
|
|
229
|
+
- **Multiple Output Formats**: HTML, Markdown, Plaintext, PDF, Screenshots
|
|
230
|
+
- **CSS Extraction**: Target specific data with CSS selectors
|
|
231
|
+
- **Structured Data Extraction**: Automatically extract emails, phone numbers, links, and other data types
|
|
232
|
+
- **Session Management**: Maintain consistent sessions across requests
|
|
233
|
+
- **Wait Conditions**: Smart waiting for dynamic content
|
|
234
|
+
- **Premium Proxies**: 55M+ residential IPs for maximum success rates
|
|
235
|
+
|
|
236
|
+
## License
|
|
237
|
+
|
|
238
|
+
`langchain-zenrows` is distributed under the terms of the [MIT](https://spdx.org/licenses/MIT.html) license.
|
|
239
|
+
|
|
240
|
+
## Support
|
|
241
|
+
|
|
242
|
+
- [ZenRows Documentation](https://docs.zenrows.com/)
|
|
243
|
+
- [LangChain Documentation](https://python.langchain.com/)
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
MANIFEST.in
|
|
3
|
+
README.md
|
|
4
|
+
pyproject.toml
|
|
5
|
+
langchain_zenrows/__init__.py
|
|
6
|
+
langchain_zenrows/py.typed
|
|
7
|
+
langchain_zenrows/zenrows_universal_scraper.py
|
|
8
|
+
langchain_zenrows.egg-info/PKG-INFO
|
|
9
|
+
langchain_zenrows.egg-info/SOURCES.txt
|
|
10
|
+
langchain_zenrows.egg-info/dependency_links.txt
|
|
11
|
+
langchain_zenrows.egg-info/requires.txt
|
|
12
|
+
langchain_zenrows.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
langchain_zenrows
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "langchain-zenrows"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "A LangChain integration tool that provides reliable web scraping capabilities at any scale using ZenRows' Universal Scraper API"
|
|
9
|
+
authors = [{name = "Yuvraj Chandra", email = "support@zenrows.com"}]
|
|
10
|
+
readme = "README.md"
|
|
11
|
+
license = {text = "MIT"}
|
|
12
|
+
keywords = [
|
|
13
|
+
"langchain",
|
|
14
|
+
"zenrows",
|
|
15
|
+
"web scraping",
|
|
16
|
+
"llm",
|
|
17
|
+
"ai",
|
|
18
|
+
"ml",
|
|
19
|
+
"data extraction"
|
|
20
|
+
]
|
|
21
|
+
classifiers = [
|
|
22
|
+
"Development Status :: 4 - Beta",
|
|
23
|
+
"Intended Audience :: Developers",
|
|
24
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
25
|
+
"License :: OSI Approved :: MIT License",
|
|
26
|
+
"Programming Language :: Python :: 3",
|
|
27
|
+
"Programming Language :: Python :: 3.9",
|
|
28
|
+
"Programming Language :: Python :: 3.10",
|
|
29
|
+
"Programming Language :: Python :: 3.11",
|
|
30
|
+
"Programming Language :: Python :: 3.12",
|
|
31
|
+
]
|
|
32
|
+
requires-python = ">=3.9"
|
|
33
|
+
dependencies = [
|
|
34
|
+
"langchain-core>=0.3.0",
|
|
35
|
+
"requests>=2.31.0",
|
|
36
|
+
"pydantic>=2.0",
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
[project.optional-dependencies]
|
|
40
|
+
test = [
|
|
41
|
+
"pytest>=7.0",
|
|
42
|
+
"pytest-mock>=3.10.0",
|
|
43
|
+
"pytest-asyncio>=0.21.0",
|
|
44
|
+
"pytest-cov>=4.0",
|
|
45
|
+
"langchain-tests>=0.3.0",
|
|
46
|
+
]
|
|
47
|
+
dev = [
|
|
48
|
+
"ruff>=0.1.5",
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
[project.urls]
|
|
52
|
+
Homepage = "https://github.com/ZenRows-Hub/langchain-zenrows"
|
|
53
|
+
Repository = "https://github.com/ZenRows-Hub/langchain-zenrows"
|
|
54
|
+
Documentation = "https://github.com/ZenRows-Hub/langchain-zenrows"
|
|
55
|
+
|
|
56
|
+
[tool.setuptools.packages.find]
|
|
57
|
+
where = ["."]
|
|
58
|
+
include = ["langchain_zenrows*"]
|