parse-everything 1.0.0__py3-none-any.whl
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.
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Parse Everything — Python Client Library
|
|
3
|
+
Official SDK for parse-everything.com Anti-Bot Bypass & Web Extraction API.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from .client import ParseEverything, ParseEverythingError
|
|
7
|
+
|
|
8
|
+
__version__ = "1.0.0"
|
|
9
|
+
__all__ = ["ParseEverything", "ParseEverythingError"]
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import urllib.request
|
|
2
|
+
import urllib.parse
|
|
3
|
+
import json
|
|
4
|
+
import time
|
|
5
|
+
from typing import Optional, Dict, Any, List
|
|
6
|
+
|
|
7
|
+
class ParseEverythingError(Exception):
|
|
8
|
+
"""Base exception for Parse Everything API errors."""
|
|
9
|
+
def __init__(self, message: str, status_code: Optional[int] = None, response_body: Optional[str] = None):
|
|
10
|
+
super().__init__(message)
|
|
11
|
+
self.status_code = status_code
|
|
12
|
+
self.response_body = response_body
|
|
13
|
+
|
|
14
|
+
class ParseEverything:
|
|
15
|
+
"""
|
|
16
|
+
Client for Parse Everything Web Scraping & Anti-Bot Bypass API.
|
|
17
|
+
|
|
18
|
+
Usage:
|
|
19
|
+
from parse_everything import ParseEverything
|
|
20
|
+
client = ParseEverything(api_key="pe_live_...")
|
|
21
|
+
res = client.scrape("https://nowsecure.nl")
|
|
22
|
+
print(res['data']['page_title'])
|
|
23
|
+
"""
|
|
24
|
+
def __init__(self, api_key: str, base_url: str = "https://api.parse-everything.com"):
|
|
25
|
+
if not api_key:
|
|
26
|
+
raise ValueError("api_key is required. Get 1,000 free credits at https://parse-everything.com")
|
|
27
|
+
self.api_key = api_key.strip()
|
|
28
|
+
self.base_url = base_url.rstrip("/")
|
|
29
|
+
|
|
30
|
+
def scrape(
|
|
31
|
+
self,
|
|
32
|
+
target_url: str,
|
|
33
|
+
render_js: bool = False,
|
|
34
|
+
bypass_cloudflare: bool = True,
|
|
35
|
+
country_code: str = "US",
|
|
36
|
+
extract_text: bool = False,
|
|
37
|
+
selectors: Optional[Dict[str, str]] = None,
|
|
38
|
+
custom_headers: Optional[Dict[str, str]] = None,
|
|
39
|
+
cookies: Optional[Dict[str, str]] = None,
|
|
40
|
+
timeout: int = 40
|
|
41
|
+
) -> Dict[str, Any]:
|
|
42
|
+
"""
|
|
43
|
+
Extract web data from any protected target URL.
|
|
44
|
+
"""
|
|
45
|
+
payload = {
|
|
46
|
+
"target_url": target_url,
|
|
47
|
+
"render_js": render_js,
|
|
48
|
+
"bypass_cloudflare": bypass_cloudflare,
|
|
49
|
+
"country_code": country_code,
|
|
50
|
+
"extract_text": extract_text,
|
|
51
|
+
"timeout": timeout
|
|
52
|
+
}
|
|
53
|
+
if selectors:
|
|
54
|
+
payload["selectors"] = selectors
|
|
55
|
+
if custom_headers:
|
|
56
|
+
payload["custom_headers"] = custom_headers
|
|
57
|
+
if cookies:
|
|
58
|
+
payload["cookies"] = cookies
|
|
59
|
+
|
|
60
|
+
url = f"{self.base_url}/api/v1/extract"
|
|
61
|
+
req = urllib.request.Request(
|
|
62
|
+
url,
|
|
63
|
+
data=json.dumps(payload).encode("utf-8"),
|
|
64
|
+
headers={
|
|
65
|
+
"Content-Type": "application/json",
|
|
66
|
+
"Authorization": f"Bearer {self.api_key}",
|
|
67
|
+
"User-Agent": "ParseEverything-PythonSDK/1.0"
|
|
68
|
+
},
|
|
69
|
+
method="POST"
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
try:
|
|
73
|
+
with urllib.request.urlopen(req, timeout=timeout + 5) as resp:
|
|
74
|
+
return json.loads(resp.read().decode("utf-8"))
|
|
75
|
+
except urllib.error.HTTPError as e:
|
|
76
|
+
body = e.read().decode("utf-8", errors="replace")
|
|
77
|
+
try:
|
|
78
|
+
err_json = json.loads(body)
|
|
79
|
+
msg = err_json.get("detail") or err_json.get("message") or str(e)
|
|
80
|
+
except Exception:
|
|
81
|
+
msg = body or str(e)
|
|
82
|
+
raise ParseEverythingError(f"API Error ({e.code}): {msg}", status_code=e.code, response_body=body)
|
|
83
|
+
except Exception as e:
|
|
84
|
+
raise ParseEverythingError(f"Request failed: {str(e)}")
|
|
85
|
+
|
|
86
|
+
def batch(
|
|
87
|
+
self,
|
|
88
|
+
target_urls: List[str],
|
|
89
|
+
render_js: bool = False,
|
|
90
|
+
country_code: str = "US",
|
|
91
|
+
webhook_url: Optional[str] = None
|
|
92
|
+
) -> Dict[str, Any]:
|
|
93
|
+
"""
|
|
94
|
+
Submit a batch of up to 100 URLs for background extraction.
|
|
95
|
+
"""
|
|
96
|
+
payload = {
|
|
97
|
+
"target_urls": target_urls,
|
|
98
|
+
"render_js": render_js,
|
|
99
|
+
"country_code": country_code
|
|
100
|
+
}
|
|
101
|
+
if webhook_url:
|
|
102
|
+
payload["webhook_url"] = webhook_url
|
|
103
|
+
|
|
104
|
+
url = f"{self.base_url}/api/v1/batch"
|
|
105
|
+
req = urllib.request.Request(
|
|
106
|
+
url,
|
|
107
|
+
data=json.dumps(payload).encode("utf-8"),
|
|
108
|
+
headers={
|
|
109
|
+
"Content-Type": "application/json",
|
|
110
|
+
"Authorization": f"Bearer {self.api_key}",
|
|
111
|
+
"User-Agent": "ParseEverything-PythonSDK/1.0"
|
|
112
|
+
},
|
|
113
|
+
method="POST"
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
try:
|
|
117
|
+
with urllib.request.urlopen(req, timeout=30) as resp:
|
|
118
|
+
return json.loads(resp.read().decode("utf-8"))
|
|
119
|
+
except urllib.error.HTTPError as e:
|
|
120
|
+
body = e.read().decode("utf-8", errors="replace")
|
|
121
|
+
raise ParseEverythingError(f"Batch Error ({e.code}): {body}", status_code=e.code, response_body=body)
|
|
122
|
+
|
|
123
|
+
def get_batch(self, batch_id: str) -> Dict[str, Any]:
|
|
124
|
+
"""
|
|
125
|
+
Poll progress and results for a batch job.
|
|
126
|
+
"""
|
|
127
|
+
url = f"{self.base_url}/api/v1/batch/{batch_id}"
|
|
128
|
+
req = urllib.request.Request(
|
|
129
|
+
url,
|
|
130
|
+
headers={
|
|
131
|
+
"Authorization": f"Bearer {self.api_key}",
|
|
132
|
+
"User-Agent": "ParseEverything-PythonSDK/1.0"
|
|
133
|
+
}
|
|
134
|
+
)
|
|
135
|
+
try:
|
|
136
|
+
with urllib.request.urlopen(req, timeout=20) as resp:
|
|
137
|
+
return json.loads(resp.read().decode("utf-8"))
|
|
138
|
+
except urllib.error.HTTPError as e:
|
|
139
|
+
body = e.read().decode("utf-8", errors="replace")
|
|
140
|
+
raise ParseEverythingError(f"Batch poll failed ({e.code}): {body}", status_code=e.code, response_body=body)
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: parse-everything
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Official Python SDK for Parse Everything — Bypass Cloudflare Turnstile, Akamai & DataDome with TLS JA3/JA4 impersonation.
|
|
5
|
+
Home-page: https://parse-everything.com
|
|
6
|
+
Author: Parse Everything
|
|
7
|
+
Author-email: support@rawmind.app
|
|
8
|
+
License: MIT
|
|
9
|
+
Project-URL: Documentation, https://parse-everything.com/docs.php
|
|
10
|
+
Project-URL: Source Code, https://github.com/parse-everything/parse-everything-python
|
|
11
|
+
Keywords: cloudflare-bypass,turnstile-solver,akamai-bypass,datadome,web-scraping-api,ja3-spoofing,ja4-fingerprinting,anti-bot,flaresolverr-alternative,zenrows-alternative,scrapingbee-alternative,crawler,web-extraction
|
|
12
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
|
|
15
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Operating System :: OS Independent
|
|
23
|
+
Requires-Python: >=3.8
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
Dynamic: author
|
|
26
|
+
Dynamic: author-email
|
|
27
|
+
Dynamic: classifier
|
|
28
|
+
Dynamic: description
|
|
29
|
+
Dynamic: description-content-type
|
|
30
|
+
Dynamic: home-page
|
|
31
|
+
Dynamic: keywords
|
|
32
|
+
Dynamic: license
|
|
33
|
+
Dynamic: project-url
|
|
34
|
+
Dynamic: requires-python
|
|
35
|
+
Dynamic: summary
|
|
36
|
+
|
|
37
|
+
# Parse Everything — Python SDK
|
|
38
|
+
|
|
39
|
+
[](https://pypi.org/project/parse-everything/)
|
|
40
|
+
[](https://parse-everything.com)
|
|
41
|
+
[](https://pypi.org/project/parse-everything/)
|
|
42
|
+
|
|
43
|
+
Official lightweight Python client for [Parse Everything](https://parse-everything.com) — Enterprise Web Scraping & Anti-Bot Bypass API.
|
|
44
|
+
|
|
45
|
+
Effortlessly bypass **Cloudflare Turnstile**, **Cloudflare WAF (403 Forbidden)**, **Akamai Bot Manager**, **DataDome**, and **DDoS-Guard** with authentic TLS JA3/JA4 fingerprint impersonation.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## 🚀 Quick Install
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
pip install parse-everything
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
*(Zero heavy browser or binary dependencies required. Uses built-in standard library).*
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## 🔑 Get Your API Key
|
|
60
|
+
|
|
61
|
+
Sign up at [parse-everything.com](https://parse-everything.com) to receive **1,000 free API credits** instantly.
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## 💡 Usage Examples
|
|
66
|
+
|
|
67
|
+
### 1. Simple Scrape (Bypass Cloudflare Turnstile & WAF)
|
|
68
|
+
```python
|
|
69
|
+
from parse_everything import ParseEverything
|
|
70
|
+
|
|
71
|
+
client = ParseEverything(api_key="pe_live_YOUR_API_KEY")
|
|
72
|
+
|
|
73
|
+
result = client.scrape(
|
|
74
|
+
target_url="https://nowsecure.nl",
|
|
75
|
+
bypass_cloudflare=True,
|
|
76
|
+
render_js=False # Handled via ultra-fast TLS impersonation in ~300ms
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
print("HTTP Status:", result["data"]["http_status"])
|
|
80
|
+
print("Page Title:", result["data"]["page_title"])
|
|
81
|
+
print("Protection Bypassed:", result["data"]["protection_bypassed"])
|
|
82
|
+
print("HTML:", result["data"]["full_html"][:200])
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### 2. Extract Structured Data with CSS Selectors (LLM / RAG Ready)
|
|
86
|
+
```python
|
|
87
|
+
result = client.scrape(
|
|
88
|
+
target_url="https://example.com/products",
|
|
89
|
+
selectors={
|
|
90
|
+
"titles": "h2.product-title",
|
|
91
|
+
"prices": ".price",
|
|
92
|
+
"links": "a.buy-btn"
|
|
93
|
+
}
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
print(result["data"]["selectors_data"])
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### 3. Extract Clean Text Only (Save 85% LLM Tokens)
|
|
100
|
+
```python
|
|
101
|
+
result = client.scrape(
|
|
102
|
+
target_url="https://news-site.com/article",
|
|
103
|
+
extract_text=True
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
print(result["data"]["clean_text"])
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### 4. Asynchronous Batch Scraping (Up to 100 URLs)
|
|
110
|
+
```python
|
|
111
|
+
batch_job = client.batch(
|
|
112
|
+
target_urls=[
|
|
113
|
+
"https://example.com/page1",
|
|
114
|
+
"https://example.com/page2",
|
|
115
|
+
"https://example.com/page3"
|
|
116
|
+
]
|
|
117
|
+
)
|
|
118
|
+
print("Batch ID:", batch_job["batch_id"])
|
|
119
|
+
|
|
120
|
+
# Poll progress
|
|
121
|
+
status = client.get_batch(batch_job["batch_id"])
|
|
122
|
+
print(f"Status: {status['job_status']} ({status['completed_urls']}/{status['total_urls']})")
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## 📦 How to Publish to PyPI
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
cd AD/04_sdks_and_packages/python_pypi
|
|
131
|
+
pip install build twine
|
|
132
|
+
python -m build
|
|
133
|
+
python -m twine upload dist/*
|
|
134
|
+
```
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
parse_everything/__init__.py,sha256=E1dt6ECbkTmT3z0UQ51sTNkboE43kL2tC-rc2Dpkss4,263
|
|
2
|
+
parse_everything/client.py,sha256=9kGhQrMT8fBChLRpqv7Ei_GTVeJpWtlogyUSZPO3gUE,5173
|
|
3
|
+
parse_everything-1.0.0.dist-info/METADATA,sha256=H3RvsJzzdqPNHekVoXFqfNWfzx6XutikxUglm-mQOmk,4408
|
|
4
|
+
parse_everything-1.0.0.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
|
|
5
|
+
parse_everything-1.0.0.dist-info/top_level.txt,sha256=52mc273gfsXNfESvTcFJOwU1_rE-mnb2JCuzNTeLO2g,17
|
|
6
|
+
parse_everything-1.0.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
parse_everything
|