Playwright wrapper обеспечивающий необходимый функционал для человеко-подобного парсинга сайтов
Project description
Human Requests
Asynchronous Playwright wrappers for browser-like HTTP scenarios, controlled render flow, and API autotest integration.
Features
- Typed wrappers over Playwright primitives:
HumanBrowserHumanContextHumanPage
HumanPage.fetch(...): execute HTTP requests from page context and get structuredFetchResponse.HumanPage.goto_render(...): render already available response payloads without duplicate upstream request.- Storage helpers:
HumanContext.local_storage()for full context snapshotHumanPage.local_storage()for current page originHumanPage.cookies()convenience alias
- Fingerprint snapshot collection:
HumanContext.fingerprint(...). - Built-in pytest autotest plugin for API clients (
@autotest, hooks, params, dependencies).
Installation
Base package:
pip install human-requests
playwright install chromium
Optional autotest addon dependencies:
pip install human-requests[autotest] pytest pytest-anyio pytest-jsonschema-snapshot pytest-subtests
If you run with Camoufox, install it separately:
pip install camoufox
camoufox fetch
Quick Start
Wrap a Playwright browser
import asyncio
from playwright.async_api import async_playwright
from human_requests import HumanBrowser
async def main() -> None:
async with async_playwright() as p:
pw_browser = await p.chromium.launch(headless=True)
browser = HumanBrowser.replace(pw_browser)
ctx = await browser.new_context()
page = await ctx.new_page()
await page.goto("https://httpbin.org/html", wait_until="domcontentloaded")
print(page.url)
await browser.close()
asyncio.run(main())
Direct request in page context (fetch)
resp = await page.fetch("https://httpbin.org/json")
print(resp.status_code)
print(resp.json())
Render previously fetched response (goto_render)
challenge = await page.fetch("https://example.com/challenge")
await page.goto_render(challenge, wait_until="networkidle")
State helpers
cookies = await page.cookies()
context_storage = await ctx.local_storage()
page_storage = await page.local_storage()
print(len(cookies), context_storage.keys(), page_storage.keys())
Fingerprint snapshot
fingerprint = await ctx.fingerprint(origin="https://example.com")
print(fingerprint.user_agent)
print(fingerprint.browser_name, fingerprint.browser_version)
API Tree Boilerplate Helper
To avoid repetitive _parent and __post_init__ wiring in SDK-style clients
(like fixprice_api / perekrestok_api), use:
ApiChild[ParentType]ApiParentapi_child_field(...)
from dataclasses import dataclass
from human_requests import ApiChild, ApiParent, api_child_field
class ClassCatalog(ApiChild["ShopApi"]):
async def tree(self):
...
class ClassGeolocation(ApiChild["ShopApi"]):
async def cities_list(self):
...
@dataclass
class ShopApi(ApiParent):
Catalog: ClassCatalog = api_child_field(ClassCatalog)
Geolocation: ClassGeolocation = api_child_field(ClassGeolocation)
ApiParent initializes all api_child_field(...) values in __post_init__
automatically, so manual assignments are no longer needed.
Nested chains are supported as well (Root -> Child -> Child):
@dataclass
class BranchApi(ApiChild["RootApi"], ApiParent):
Catalog: ClassCatalog = api_child_field(ClassCatalog)
@dataclass
class RootApi(ApiParent):
Branch: BranchApi = api_child_field(BranchApi)
API Autotest Addon (pytest)
human-requests ships with a pytest plugin that can auto-run API methods marked with @autotest and validate payloads via schemashot from pytest-jsonschema-snapshot.
With pytest-subtests, each discovered @autotest method and @autotest_data
provider is shown as a separate subtest inside test_autotest_api_methods.
Minimal pytest.ini:
[pytest]
anyio_mode = auto
autotest_start_class = your_package.StartClass
autotest_typecheck = warn
autotest_typecheck modes:
off(default): no runtime type checks for params provider argumentswarn: emitRuntimeWarningon annotation mismatchstrict: fail test case withTypeErroron mismatch
Minimal fixtures:
import pytest
from your_package import StartClass
@pytest.fixture(scope="session")
def anyio_backend() -> str:
return "asyncio"
@pytest.fixture(scope="session")
async def api() -> StartClass:
async with StartClass() as client:
yield client
Business code only marks methods:
from human_requests import autotest
class Catalog:
@autotest
async def tree(self):
...
Test layer adds hooks and params:
from human_requests import autotest_depends_on, autotest_hook, autotest_params
from human_requests.autotest import AutotestCallContext, AutotestContext
@autotest_hook(target=Catalog.tree)
def _capture_category(_resp, data, ctx: AutotestContext) -> None:
ctx.state["category_id"] = data["items"][0]["id"]
@autotest_depends_on(Catalog.tree)
@autotest_params(target=Catalog.feed)
def _feed_params(ctx: AutotestCallContext) -> dict[str, int]:
return {"category_id": ctx.state["category_id"]}
Parent-specific registration is supported:
@autotest_hook(target=Child.method, parent=ParentA)
def _only_for_parent_a(_resp, data, ctx):
...
For a complete guide, see docs/source/autotest.rst.
Development
Setup:
git clone https://github.com/Miskler/human-requests.git
cd human-requests
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txt
pip install -e .
Commands:
pytest
make lint
make type-check
make format
make docs
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file human_requests-0.1.7.tar.gz.
File metadata
- Download URL: human_requests-0.1.7.tar.gz
- Upload date:
- Size: 50.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4a1532d76a03fcf0f2acadb237a12b9be3566566ba58b94425dd49af78ff4123
|
|
| MD5 |
d3259c30b8d535fadd324d9037b3dd44
|
|
| BLAKE2b-256 |
024b3567c17ee40fc6273a7e1eb2cc4cfec0c6890fe988d646d56fb48c4cdfba
|
Provenance
The following attestation bundles were made for human_requests-0.1.7.tar.gz:
Publisher:
release.yml on Miskler/human-requests
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
human_requests-0.1.7.tar.gz -
Subject digest:
4a1532d76a03fcf0f2acadb237a12b9be3566566ba58b94425dd49af78ff4123 - Sigstore transparency entry: 988392090
- Sigstore integration time:
-
Permalink:
Miskler/human-requests@e6483acdde2cf8d6ed64c8c6a2afa8c11165b508 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/Miskler
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@e6483acdde2cf8d6ed64c8c6a2afa8c11165b508 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file human_requests-0.1.7-py3-none-any.whl.
File metadata
- Download URL: human_requests-0.1.7-py3-none-any.whl
- Upload date:
- Size: 43.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e9189b555bf3655dc260fae2caf34192de7bd2a5718f906fd36703e7a89c9997
|
|
| MD5 |
6658518aa2302d3f6213c8d4d51d1bcd
|
|
| BLAKE2b-256 |
8485a38d8005a94be3c0fdf5c8520c24e3c84a6b34bb15c50ff4feaaad6abbc7
|
Provenance
The following attestation bundles were made for human_requests-0.1.7-py3-none-any.whl:
Publisher:
release.yml on Miskler/human-requests
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
human_requests-0.1.7-py3-none-any.whl -
Subject digest:
e9189b555bf3655dc260fae2caf34192de7bd2a5718f906fd36703e7a89c9997 - Sigstore transparency entry: 988392146
- Sigstore integration time:
-
Permalink:
Miskler/human-requests@e6483acdde2cf8d6ed64c8c6a2afa8c11165b508 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/Miskler
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@e6483acdde2cf8d6ed64c8c6a2afa8c11165b508 -
Trigger Event:
workflow_dispatch
-
Statement type: