iploop-sdk
Advanced tools
| Metadata-Version: 2.4 | ||
| Name: iploop-sdk | ||
| Version: 1.6.0 | ||
| Version: 1.7.0 | ||
| Summary: Residential proxy SDK with full scraping capabilities — render JS, bypass protection, extract data | ||
@@ -5,0 +5,0 @@ Home-page: https://iploop.io |
+49
-9
@@ -20,3 +20,3 @@ """Main IPLoop client.""" | ||
| def __init__(self, client, session_id, country=None, city=None): | ||
| def __init__(self, client, session_id, country=None, city=None, lifetime=None): | ||
| self._client = client | ||
@@ -26,2 +26,3 @@ self.session_id = session_id | ||
| self.city = city or client._city | ||
| self.lifetime = lifetime | ||
@@ -32,2 +33,5 @@ def fetch(self, url, **kwargs): | ||
| kwargs["session"] = self.session_id | ||
| kwargs["sesstype"] = "sticky" | ||
| if self.lifetime: | ||
| kwargs["lifetime"] = self.lifetime | ||
| kwargs["_no_rotate"] = True | ||
@@ -44,3 +48,12 @@ return self._client.fetch(url, **kwargs) | ||
| def put(self, url, data=None, json=None, **kwargs): | ||
| kwargs["method"] = "PUT" | ||
| kwargs["data"] = data or json | ||
| return self.fetch(url, **kwargs) | ||
| def delete(self, url, **kwargs): | ||
| kwargs["method"] = "DELETE" | ||
| return self.fetch(url, **kwargs) | ||
| class IPLoop: | ||
@@ -78,3 +91,4 @@ """Residential proxy SDK — one-liner web fetching through millions of real IPs.""" | ||
| def _build_proxy_auth(self, country=None, city=None, session=None, render=False): | ||
| def _build_proxy_auth(self, country=None, city=None, session=None, render=False, | ||
| sesstype=None, lifetime=None): | ||
| parts = [self.api_key] | ||
@@ -87,4 +101,8 @@ c = country or self._country | ||
| parts.append(f"city-{ci.lower()}") | ||
| if sesstype: | ||
| parts.append(f"sesstype-{sesstype}") | ||
| if session: | ||
| parts.append(f"session-{session}") | ||
| if lifetime: | ||
| parts.append(f"lifetime-{lifetime}") | ||
| if render: | ||
@@ -94,4 +112,6 @@ parts.append("render-1") | ||
| def _proxy_url(self, **kwargs): | ||
| auth = self._build_proxy_auth(**kwargs) | ||
| def _proxy_url(self, country=None, city=None, session=None, render=False, | ||
| sesstype=None, lifetime=None): | ||
| auth = self._build_proxy_auth(country=country, city=city, session=session, | ||
| render=render, sesstype=sesstype, lifetime=lifetime) | ||
| return { | ||
@@ -104,3 +124,3 @@ "http": f"http://user:{auth}@{self.base_proxy}", | ||
| headers=None, method="GET", data=None, timeout=15, retries=3, | ||
| _no_rotate=False): | ||
| _no_rotate=False, sesstype=None, lifetime=None): | ||
| """Fetch a URL through residential proxy with auto-retry and smart headers.""" | ||
@@ -115,3 +135,4 @@ c = country or self._country or "US" | ||
| sid = session if _no_rotate else (session or new_session_id()) | ||
| proxies = self._proxy_url(country=country, city=city, session=sid, render=render) | ||
| proxies = self._proxy_url(country=country, city=city, session=sid, render=render, | ||
| sesstype=sesstype, lifetime=lifetime) | ||
| req_start = time.time() | ||
@@ -160,6 +181,25 @@ # Use TLS fingerprint engine if available (curl_cffi/tls_client) | ||
| def session(self, session_id=None, country=None, city=None): | ||
| """Create a sticky session that reuses the same proxy IP.""" | ||
| return StickySession(self, session_id or new_session_id(), country, city) | ||
| def put(self, url, data=None, json=None, **kwargs): | ||
| """PUT request through proxy.""" | ||
| import json as json_mod | ||
| if json is not None: | ||
| kwargs.setdefault("headers", {})["Content-Type"] = "application/json" | ||
| data = json_mod.dumps(json) | ||
| return self.fetch(url, method="PUT", data=data, **kwargs) | ||
| def delete(self, url, **kwargs): | ||
| """DELETE request through proxy.""" | ||
| return self.fetch(url, method="DELETE", **kwargs) | ||
| def session(self, session_id=None, country=None, city=None, lifetime=None): | ||
| """Create a sticky session that reuses the same proxy IP. | ||
| Args: | ||
| session_id: Custom session ID (auto-generated if not provided) | ||
| country: Target country code (e.g. "US", "DE") | ||
| city: Target city (e.g. "miami", "london") | ||
| lifetime: Session lifetime in minutes (e.g. 30) | ||
| """ | ||
| return StickySession(self, session_id or new_session_id(), country, city, lifetime=lifetime) | ||
| def batch(self, max_workers=10): | ||
@@ -166,0 +206,0 @@ """Create a batch fetcher for concurrent requests. Safe up to 25 workers.""" |
+10
-0
@@ -12,2 +12,3 @@ """Support API client.""" | ||
| self.api_base = api_base.rstrip("/") | ||
| self.customer_api = "https://api.iploop.io/api/v1" | ||
| self._headers = {"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"} | ||
@@ -41,2 +42,11 @@ | ||
| def countries(self): | ||
| """List available proxy countries via customer API (not through proxy).""" | ||
| try: | ||
| resp = requests.get(f"{self.customer_api}/proxy/countries", | ||
| headers=self._headers, timeout=15, verify=True) | ||
| if resp.status_code == 200: | ||
| return resp.json() | ||
| except Exception: | ||
| pass | ||
| # Fallback to gateway support endpoint (direct, not proxied) | ||
| return self._get("/api/support/countries") | ||
@@ -43,0 +53,0 @@ |
+1
-1
| Metadata-Version: 2.4 | ||
| Name: iploop-sdk | ||
| Version: 1.6.0 | ||
| Version: 1.7.0 | ||
| Summary: Residential proxy SDK with full scraping capabilities — render JS, bypass protection, extract data | ||
@@ -5,0 +5,0 @@ Home-page: https://iploop.io |
+1
-1
@@ -7,3 +7,3 @@ [build-system] | ||
| name = "iploop-sdk" | ||
| version = "1.6.0" | ||
| version = "1.7.0" | ||
| description = "Residential proxy SDK with full scraping capabilities — render JS, bypass protection, extract data" | ||
@@ -10,0 +10,0 @@ readme = "README.md" |
+1
-1
@@ -5,3 +5,3 @@ from setuptools import setup, find_packages | ||
| name="iploop-sdk", | ||
| version="1.6.0", | ||
| version="1.7.0", | ||
| packages=find_packages(exclude=['dist-obf', 'dist-obf.*']), | ||
@@ -8,0 +8,0 @@ install_requires=["requests>=2.28"], |
Alert delta unavailable
Currently unable to show alert delta for PyPI packages.
236531
0.96%4618
0.98%