Addon for Playwright for intercepting and modifying HTTP requests and responses.
Project description
Playwright Interceptor
Addon for Playwright for intercepting and modifying HTTP requests and responses.
Features
- Request modification before sending to the server
- Server response modification before passing to the browser
- Request filtering by URL, method, and content type
- Support for synchronous and asynchronous modification functions
- Processing requests with multiple handlers
- Obtaining information about intercepted requests
- Type safety with beartype
- Direct access to request and response properties
Installation
pip install playwright_interceptor
Usage
from playwright.async_api import async_playwright
from playwright_interceptor import NetworkInterceptor, Handler, Execute, Request, Response
import asyncio
async def main():
async with async_playwright() as pw:
browser = await pw.firefox.launch()
page = await browser.new_page()
interceptor = NetworkInterceptor(page)
# Intercepting and modifying requests and responses
handler = Handler.ALL(execute=Execute.ALL(
request_modify=modify_request,
response_modify=modify_response,
max_modifications=5,
max_responses=2
))
# Starting interception
results, _ = await asyncio.gather(
interceptor.execute([handler]),
page.goto("https://httpbin.org/get")
)
print(f"Results: {results}")
await browser.close()
def modify_request(request: Request) -> Request:
"""Modifies request before sending"""
request.headers["X-Custom-Header"] = "ModifiedByInterceptor"
request.params["intercepted"] = "true"
return request
def modify_response(response: Response) -> Response:
"""Modifies response after receiving"""
response.response_headers["X-Response-Modified"] = "true"
# Parsing and modifying JSON
parsed_content = response.content_parse()
if isinstance(parsed_content, dict):
parsed_content["_intercepted"] = True
# Updating content
import json
response.content = json.dumps(parsed_content).encode('utf-8')
return response
if __name__ == "__main__":
asyncio.run(main())
Components
NetworkInterceptor
Class for intercepting HTTP traffic:
from playwright_interceptor import NetworkInterceptor
interceptor = NetworkInterceptor(page, logger=custom_logger)
results = await interceptor.execute(handlers, timeout=10.0)
Parameters:
page- Playwright pagelogger- Optional logger
Methods:
execute(handlers, timeout=10.0)- Start interception with specified handlers
Handler
Rules for capturing and processing requests:
from playwright_interceptor import Handler, Execute, ExpectedContentType, HttpMethod
handler_all = Handler.ALL(
expected_content=ExpectedContentType.JSON,
startswith_url="https://api.example.com",
method=HttpMethod.GET,
execute=Execute.RETURN(max_responses=3)
)
handler_modify = Handler.ALL(
expected_content=ExpectedContentType.ANY,
execute=Execute.MODIFY(
request_modify=my_request_modifier,
response_modify=my_response_modifier,
max_modifications=5
)
)
handler_combined = Handler.ALL(
slug="my_handler",
expected_content=ExpectedContentType.JSON,
startswith_url="https://api.example.com",
method=HttpMethod.POST,
execute=Execute.ALL(
request_modify=my_request_modifier,
response_modify=my_response_modifier,
max_modifications=3,
max_responses=2
)
)
Parameters:
expected_content- Expected content typestartswith_url- Filter by URL beginningmethod- HTTP method for filteringexecute- Execution configurationslug- Handler identifier
Factory methods:
Handler.ALL()- Universal handler for all types of requestsHandler.MAIN()- Handler for main page requestsHandler.SIDE()- Handler for side resource requestsHandler.NONE()- Empty handler
Execute
Handler behavior configuration:
from playwright_interceptor import Execute
execute_return = Execute.RETURN(max_responses=5)
execute_modify = Execute.MODIFY(
request_modify=modify_request,
max_modifications=3
)
execute_all = Execute.ALL(
request_modify=modify_request,
response_modify=modify_response,
max_modifications=5,
max_responses=3
)
Modes:
RETURN- Request interceptionMODIFY- Request/response modificationALL- Combination of interception and modification
Parameters:
request_modify- Request modification functionresponse_modify- Response modification functionmax_modifications- Maximum number of modificationsmax_responses- Maximum number of intercepted responses
Request
HTTP request representation:
from playwright_interceptor import Request, HttpMethod
request = Request(
url="https://api.example.com/users",
headers={"Authorization": "Bearer token"},
params={"page": "1", "limit": "10"},
body={"name": "John"},
method=HttpMethod.POST
)
# Modification (direct field access)
request.headers["X-Custom"] = "value"
request.params["filter"] = "active"
request.method = HttpMethod.PUT
request.body = {"updated": "data"}
# URL with parameters
final_url = request.real_url
Properties:
url- Base URLreal_url- URL with parameters (read-only property)base_url- URL without parameters (read-only property)headers- Headers dictionaryparams- Request parameters dictionarybody- Request bodymethod- HTTP method
Response
HTTP response representation:
from playwright_interceptor import Response
def modify_response(response: Response) -> Response:
response.response_headers["X-Modified"] = "true"
parsed_content = response.content_parse()
if isinstance(parsed_content, dict):
parsed_content["_intercepted"] = True
import json
response.content = json.dumps(parsed_content).encode('utf-8')
return response
Properties:
status- HTTP status codeurl- Request URLrequest_headers- Request headersresponse_headers- Response headerscontent- Response content (bytes)duration- Request execution time
Methods:
content_parse()- Parse content into objects
Enum Classes
from playwright_interceptor import ExpectedContentType, HttpMethod
# Content types
ExpectedContentType.JSON # application/json
ExpectedContentType.JS # application/javascript
ExpectedContentType.CSS # text/css
ExpectedContentType.IMAGE # image/*
ExpectedContentType.VIDEO # video/*
ExpectedContentType.AUDIO # audio/*
ExpectedContentType.FONT # font/*
ExpectedContentType.APPLICATION # application/*
ExpectedContentType.ARCHIVE # archive formats
ExpectedContentType.TEXT # text/*
ExpectedContentType.ANY # any type
# HTTP methods
HttpMethod.GET
HttpMethod.POST
HttpMethod.PUT
HttpMethod.DELETE
HttpMethod.PATCH
HttpMethod.HEAD
HttpMethod.OPTIONS
HttpMethod.ANY
Examples
Adding Authentication
def add_auth(request: Request) -> Request:
if "/api/" in request.url:
request.headers["Authorization"] = "Bearer your-token"
return request
handler = Handler.ALL(
startswith_url="https://api.example.com",
execute=Execute.MODIFY(request_modify=add_auth, max_modifications=10)
)
Adding Analytics
from datetime import datetime
async def add_analytics(response: Response) -> Response:
parsed_content = response.content_parse()
if isinstance(parsed_content, dict):
parsed_content["_analytics"] = {
"intercepted_at": datetime.now().isoformat(),
"response_time_ms": response.duration * 1000,
"status_code": response.status
}
import json
response.content = json.dumps(parsed_content).encode('utf-8')
return response
handler = Handler.ALL(
expected_content=ExpectedContentType.JSON,
execute=Execute.ALL(
response_modify=add_analytics,
max_modifications=5,
max_responses=3
)
)
Multiple Handlers
async def run_multiple_handlers():
request_handler = Handler.ALL(
slug="request_modifier",
execute=Execute.MODIFY(
request_modify=add_tracking,
max_modifications=10
)
)
response_handler = Handler.ALL(
slug="response_modifier",
expected_content=ExpectedContentType.JSON,
execute=Execute.MODIFY(
response_modify=add_metadata,
max_modifications=10
)
)
collector_handler = Handler.ALL(
slug="data_collector",
startswith_url="https://api.example.com",
execute=Execute.ALL(
response_modify=collect_data,
max_modifications=5,
max_responses=5
)
)
results = await interceptor.execute([
request_handler,
response_handler,
collector_handler
])
Asynchronous Modifiers
async def async_request_modifier(request: Request) -> Request:
await asyncio.sleep(0.01)
request.headers["X-Async-Modified"] = "true"
return request
async def async_response_modifier(response: Response) -> Response:
parsed_content = response.content_parse()
if isinstance(parsed_content, dict):
parsed_content["_processed_async"] = True
import json
response.content = json.dumps(parsed_content).encode('utf-8')
return response
Error Handling
def safe_modifier(response: Response) -> Response:
try:
parsed_content = response.content_parse()
if isinstance(parsed_content, dict):
parsed_content["_modified"] = True
import json
response.content = json.dumps(parsed_content).encode('utf-8')
return response
except Exception as e:
print(f"Modification error: {e}")
return response
Important Notes
- When using multiple handlers, modifications are applied sequentially
- For
MODIFYandALLmodes, at least one of the modifiers is required - With multiple handlers, unique
slugvalues are required - Avoid heavy operations in modifiers
License
MIT License
Support
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 playwright_interceptor-0.1.1.tar.gz.
File metadata
- Download URL: playwright_interceptor-0.1.1.tar.gz
- Upload date:
- Size: 22.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
290786fff44f6fc9002a7c498b2cfeb847774d0e17f7848c5a7df9ffeba78be5
|
|
| MD5 |
a0d293e876b8992508f2ec32d1b61200
|
|
| BLAKE2b-256 |
9235b1dd953ea31fdb3a89fe7af91d18ef70cd48acc209fb244e92226a691213
|
Provenance
The following attestation bundles were made for playwright_interceptor-0.1.1.tar.gz:
Publisher:
python-publish.yml on Open-Inflation/playwright_interceptor
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
playwright_interceptor-0.1.1.tar.gz -
Subject digest:
290786fff44f6fc9002a7c498b2cfeb847774d0e17f7848c5a7df9ffeba78be5 - Sigstore transparency entry: 238544043
- Sigstore integration time:
-
Permalink:
Open-Inflation/playwright_interceptor@93639b58119fab444fed856159f64d648a28a69a -
Branch / Tag:
refs/heads/main - Owner: https://github.com/Open-Inflation
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@93639b58119fab444fed856159f64d648a28a69a -
Trigger Event:
push
-
Statement type:
File details
Details for the file playwright_interceptor-0.1.1-py3-none-any.whl.
File metadata
- Download URL: playwright_interceptor-0.1.1-py3-none-any.whl
- Upload date:
- Size: 21.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
92db51e748013d3d4e9355e951c25ea94e3dc64b5b8d83475f2fa5f5f71a0dec
|
|
| MD5 |
750a8fc961c82f32439eef255e203dc9
|
|
| BLAKE2b-256 |
44f37b64d6d18582d0d0311385a8139115b22df1bf3b1709e9d8911845a66a07
|
Provenance
The following attestation bundles were made for playwright_interceptor-0.1.1-py3-none-any.whl:
Publisher:
python-publish.yml on Open-Inflation/playwright_interceptor
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
playwright_interceptor-0.1.1-py3-none-any.whl -
Subject digest:
92db51e748013d3d4e9355e951c25ea94e3dc64b5b8d83475f2fa5f5f71a0dec - Sigstore transparency entry: 238544048
- Sigstore integration time:
-
Permalink:
Open-Inflation/playwright_interceptor@93639b58119fab444fed856159f64d648a28a69a -
Branch / Tag:
refs/heads/main - Owner: https://github.com/Open-Inflation
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@93639b58119fab444fed856159f64d648a28a69a -
Trigger Event:
push
-
Statement type: