diff --git a/CHANGELOG.md b/CHANGELOG.md index 53d3eb5..5028ea6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.2.2] - 2025-12-26 + +### Changed +- **Better HAR Recording**: Improved HAR file recording and capture functionality + ## [0.2.1] - 2025-12-26 ### Added diff --git a/pyproject.toml b/pyproject.toml index 757cb15..dd5f25c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "reverse-api-engineer" -version = "0.2.1" +version = "0.2.2" description = "A tool to capture browser traffic for API reverse engineering" readme = "README.md" requires-python = ">=3.11" diff --git a/src/reverse_api/__init__.py b/src/reverse_api/__init__.py index b849b3d..aba7ec4 100644 --- a/src/reverse_api/__init__.py +++ b/src/reverse_api/__init__.py @@ -1,3 +1,3 @@ """Reverse API - Browser traffic capture for API reverse engineering.""" -__version__ = "0.2.1" +__version__ = "0.2.2" diff --git a/src/reverse_api/browser.py b/src/reverse_api/browser.py index f614b74..8ac7cf4 100644 --- a/src/reverse_api/browser.py +++ b/src/reverse_api/browser.py @@ -241,8 +241,6 @@ def _inject_stealth(self, page: Page) -> None: def _start_with_real_chrome(self, start_url: Optional[str] = None) -> Path: """Start using the real Chrome browser with user's profile.""" - # We need to use a COPY of the profile to avoid locking issues - # Chrome locks its profile when running, so we can't use it directly import shutil import tempfile @@ -257,12 +255,12 @@ def _start_with_real_chrome(self, start_url: Optional[str] = None) -> Path: temp_profile_dir = Path(tempfile.mkdtemp(prefix="chrome_profile_")) console.print(f" [dim]using real chrome (profile copy)[/dim]") - console.print(f" [dim]note: close chrome if you have it open[/dim]") + console.print(f" [yellow]⚠️ please browse in the FIRST tab only[/yellow]") + console.print(f" [yellow] (new tabs may not be recorded)[/yellow]") console.print() try: # Use launch_persistent_context with channel="chrome" to use real Chrome binary - # This gives us the real Chrome with a fresh profile that has all extensions/settings self._context = self._playwright.chromium.launch_persistent_context( user_data_dir=str(temp_profile_dir), channel="chrome", # Use real Chrome binary @@ -278,19 +276,24 @@ def _start_with_real_chrome(self, start_url: Optional[str] = None) -> Path: ) self._using_persistent = True - # Get or create page - if self._context.pages: - page = self._context.pages[0] - else: - page = self._context.new_page() + for existing_page in self._context.pages: + try: + existing_page.close() + except Exception: + pass + + # For HAR recording & context + page = self._context.new_page() if start_url: page.goto(start_url, wait_until="domcontentloaded") + else: + page.goto("https://www.google.com", wait_until="domcontentloaded") # Wait for browser to close try: while self._context.pages: - self._context.pages[0].wait_for_timeout(100) # Faster polling + self._context.pages[0].wait_for_timeout(100) except Exception: pass @@ -376,11 +379,14 @@ def _start_with_stealth_chromium(self, start_url: Optional[str] = None) -> Path: if start_url: page.goto(start_url, wait_until="domcontentloaded") + else: + # For HAR recording & context + page.goto("about:blank") # Wait for browser to close try: while self._context.pages: - self._context.pages[0].wait_for_timeout(100) # Faster polling + self._context.pages[0].wait_for_timeout(100) except Exception: pass @@ -423,10 +429,26 @@ def close(self) -> Path: spinner="dots", ) as status: try: + status.update(" [dim]flushing network traffic...[/dim]") + import time + + time.sleep(1) + status.update(" [dim]saving har file...[/dim]") - self._context.close() # This saves the HAR file - except Exception: - pass + self._context.close() + + if self.har_path.exists(): + har_size = self.har_path.stat().st_size + status.update(f" [dim]har saved: {har_size:,} bytes[/dim]") + else: + console.print( + " [yellow]warning: har file was not created[/yellow]" + ) + + except Exception as e: + console.print(f" [yellow]warning: error saving har: {e}[/yellow]") + if self.har_path.exists(): + console.print(f" [dim]har file exists despite error[/dim]") self._context = None # Only close browser if not using persistent context diff --git a/uv.lock b/uv.lock index dbf5464..bf432be 100644 --- a/uv.lock +++ b/uv.lock @@ -240,7 +240,7 @@ wheels = [ [[package]] name = "browser-use" version = "0.11.2" -source = { git = "https://github.com/browser-use/browser-use.git?rev=49a345fb19e9f12befc5cc1658e0033873892455#49a345fb19e9f12befc5cc1658e0033873892455" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohttp" }, { name = "anthropic" }, @@ -280,6 +280,10 @@ dependencies = [ { name = "typing-extensions" }, { name = "uuid7" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/77/42/aacaba1ee2599101ccb14fde3c4732d6e994d9d616b3a7b9c12f8ac5d5b4/browser_use-0.11.2.tar.gz", hash = "sha256:543face2fd5662ee89526d2099a79e01468b51784cdcc85faa36a81fdae4aa68", size = 501474, upload-time = "2025-12-16T22:07:49.749Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3d/04/9d0b9ee9b176fe329d424bf4337982b021b264295aa2fb9a7aef885abd61/browser_use-0.11.2-py3-none-any.whl", hash = "sha256:6ac57c0e2a495749fc83c1faee85001737567f8cd4301ebfcda2a886018a325b", size = 599219, upload-time = "2025-12-16T22:07:48.39Z" }, +] [[package]] name = "browser-use-sdk" @@ -5298,7 +5302,7 @@ wheels = [ [[package]] name = "reverse-api-engineer" -version = "0.2.0" +version = "0.2.2" source = { editable = "." } dependencies = [ { name = "aiohttp" }, @@ -5324,7 +5328,7 @@ requires-dist = [ { name = "aiohttp", specifier = ">=3.12.15" }, { name = "anthropic", specifier = ">=0.40.0" }, { name = "brotli", specifier = ">=1.2.0" }, - { name = "browser-use", marker = "extra == 'agent'", git = "https://github.com/browser-use/browser-use.git?rev=49a345fb19e9f12befc5cc1658e0033873892455" }, + { name = "browser-use", marker = "extra == 'agent'" }, { name = "claude-agent-sdk", specifier = ">=0.1.0" }, { name = "click", specifier = ">=8.1.0" }, { name = "playwright", specifier = ">=1.40.0" },