62 lines
2.0 KiB
Python
62 lines
2.0 KiB
Python
# retoor <retoor@molodetz.nl>
|
|||
|
|
import httpx
|
||
|
|
|
||
|
|
try:
|
||
|
|
from curl_cffi import CurlHttpVersion
|
||
|
|
from curl_cffi.requests import AsyncSession
|
||
|
|
|
||
|
|
CURL_AVAILABLE = True
|
||
|
|
except ImportError:
|
||
|
|
CURL_AVAILABLE = False
|
||
|
|
|
||
|
|
IMPERSONATE_PROFILE = "chrome"
|
||
|
|
|
||
|
|
|
||
|
|
class CurlImpersonationTransport(httpx.AsyncBaseTransport):
|
||
|
|
def __init__(self, proxy=None, timeout=30.0, verify=True):
|
||
|
|
self.proxy = proxy or None
|
||
|
|
self.timeout = timeout
|
||
|
|
self.verify = verify
|
||
|
|
self._session = None
|
||
|
|
|
||
|
|
def _session_for(self):
|
||
|
|
if self._session is None:
|
||
|
|
self._session = AsyncSession(impersonate=IMPERSONATE_PROFILE, verify=self.verify)
|
||
|
|
return self._session
|
||
|
|
|
||
|
|
async def handle_async_request(self, request):
|
||
|
|
url = str(request.url)
|
||
|
|
http_version = CurlHttpVersion.V1_1 if request.url.scheme == "http" else None
|
||
|
|
headers = {
|
||
|
|
key.decode("latin-1"): value.decode("latin-1")
|
||
|
|
for key, value in request.headers.raw
|
||
|
|
if key.lower() not in (b"host", b"content-length", b"user-agent", b"accept-encoding", b"connection")
|
||
|
|
}
|
||
|
|
body = await request.aread()
|
||
|
|
kwargs = {
|
||
|
|
"headers": headers,
|
||
|
|
"data": body or None,
|
||
|
|
"timeout": self.timeout,
|
||
|
|
"allow_redirects": False,
|
||
|
|
"proxy": self.proxy,
|
||
|
|
}
|
||
|
|
if http_version is not None:
|
||
|
|
kwargs["http_version"] = http_version
|
||
|
|
response = await self._session_for().request(request.method, url, **kwargs)
|
||
|
|
response_headers = [
|
||
|
|
(key, value)
|
||
|
|
for key, value in response.headers.multi_items()
|
||
|
|
if key.lower() not in ("content-encoding", "content-length", "transfer-encoding")
|
||
|
|
]
|
||
|
|
return httpx.Response(
|
||
|
|
status_code=response.status_code,
|
||
|
|
headers=response_headers,
|
||
|
|
content=response.content,
|
||
|
|
request=request,
|
||
|
|
)
|
||
|
|
|
||
|
|
async def aclose(self):
|
||
|
|
if self._session is not None:
|
||
|
|
await self._session.close()
|
||
|
|
self._session = None
|