# Close the simulated browser, saving states and backing up profiles
awaitsimulated_browser.close()
asyncdefmain():
"""Main entry point to test both modes."""
"""
HOW TO USE
----------
This script provides a unified solution for managing multiple Playwright browser contexts with persistent states (session data, extensions, cache) using two approaches:
1. launch_persistent_context mode: Uses Playwright's launch_persistent_context() for native persistence via user data directories.
2. browser.launch mode: Uses Playwright's browser.launch() with manual persistence via storage state files and profile directories.
Prerequisites:
- Install Playwright: Run "pip install playwright" in your terminal.
- Install Chromium: Run "playwright install chromium" to download the Chromium browser used by Playwright.
- Ensure Python 3.7+ is installed to support async/await syntax.
Setting Up Extensions:
- Update the EXTENSION_PATHS list in the run() function with paths to unpacked extension directories, each containing a manifest.json file.
- Example:
EXTENSION_PATHS = [
Path("./my_extension1"),
Path("./my_extension2")
]
- To obtain unpacked extensions:
- On Linux/macOS: Extract a .crx file using "unzip <extension>.crx".
- On Windows: Use 7-Zip to extract a .crx file (it is a ZIP archive).
- Alternatively, pre-install extensions in a Chromium browser and copy its profile directory (e.g., ~/.config/chromium on Linux, ~/Library/Application Support/Chromium on macOS, %LocalAppData%\\Chromium\\User Data on Windows) to chromium_profile_<context_id> for each context.
- Note: Extensions load natively in launch_persistent_context mode but may not load dynamically in browser.launch mode without additional setup (e.g., automating chrome://extensions/).
Running the Script:
- Save the script as script.py.
- Run it from the terminal: "python script.py".
- The script will:
- Create chromium_profiles and browser_states directories in the script's working directory.
- Run two tests:
1. launch_persistent_context mode: Creates 3 contexts, each with a unique user data directory (chromium_profile_<context_id>) and storage state file (browser_state_<context_id>.json).
2. browser.launch mode: Creates 3 contexts using a single browser instance, with manual persistence.
- For each context:
- Copies all extensions from EXTENSION_PATHS to the context's profile directory (chromium_profile_<context_id>/Extensions).
- Loads session data (cookies, local storage) from browser_state_<context_id>.json if it exists.
- Navigates to https://example.com and prints the page title as a sample action.
- Saves session data and backs up the profile directory (in launch_persistent_context mode) when closing.
- Output will include logs for directory creation, extension copying, state loading/saving, and page titles.
Subsequent Runs:
- The script restores profile directories and session states for each context using unique context IDs (UUIDs), ensuring persistence across runs.
- Backed-up profile directories (chromium_profile_backup_<context_id>) are used to restore chromium_profile_<context_id> if needed.
- Session data persists in browser_state_<context_id>.json files.
Customization:
- Change the number of contexts by modifying num_contexts in run().
- Switch modes by setting use_persistent_context=True (launch_persistent_context) or False (browser.launch) in run().
- Update EXTENSION_PATHS with your extension directories.
- Add context options (e.g., user_agent, locale) by passing them to new_context(**kwargs) in run_context().
DEBUGGING TIPS
--------------
If you encounter issues while running the script, consider the following debugging strategies:
Extension Not Loading:
- Verify each path in EXTENSION_PATHS points to a valid unpacked extension directory containing a manifest.json file.
- Check the chromium_profile_<context_id>/Extensions directory to ensure extensions were copied correctly.
- In launch_persistent_context mode:
- Open the browser (since headless=False) and navigate to chrome://extensions/ to confirm extensions are loaded.
- Ensure extensions are compatible with Chromium and have a valid manifest.
- In browser.launch mode:
- Extensions may not load dynamically due to Playwright's limitations.
- To enable extensions, pre-install them in a Chromium browser and copy the profile to chromium_profile_<context_id>.
- Alternatively, automate extension installation by navigating to chrome://extensions/ and enabling developer mode (not implemented in this script).
- If extensions fail to load, check console logs for errors related to install_extension().
Session Data Issues:
- Ensure browser_state_<context_id>.json files in the browser_states directory contain valid JSON.
- Open these files to verify cookies and local storage data are correctly formatted.
- Check console output for messages like "Loaded browser state..." or "Saved browser state..." to confirm state handling.
- If session data does not persist, verify write permissions for the browser_states directory.
- Test by logging into a website in one run and checking if the login persists in the next run.
Backup Errors:
- The copytree_ignore_errors function prevents errors related to SingletonLock, SingletonCookie, and SingletonSocket files by ignoring them during backups.
- If backup issues persist, check console logs for messages like "Skipped problematic file..." or "Non-critical errors during copy...".
- Ensure no other processes (e.g., lingering Chromium instances) are accessing chromium_profile_<context_id> directories.
- Verify write permissions for the chromium_profiles directory.
- If backups fail, manually inspect chromium_profile_backup_<context_id> to ensure critical files (e.g., extensions, cache) were copied.
Indentation Errors:
- The code uses consistent 4-space indentation per PEP 8. If syntax errors occur, ensure no tabs are mixed with spaces.
- Copy the code directly to avoid indentation issues introduced by text editors or copy-paste operations.
- Use an editor with Python linting (e.g., VS Code with Pylance) to detect indentation problems.
Resource Usage:
- In launch_persistent_context mode, each context runs a separate Chromium instance, increasing memory and CPU usage. Monitor system resources if using many contexts.
- In browser.launch mode, a single browser instance is used, but extension/cache persistence is limited.
- If performance is an issue, reduce num_contexts or switch to browser.launch mode.
Other Errors:
- If you encounter runtime errors (e.g., network issues, Playwright exceptions), check the full traceback printed by the script.
- Share the error message and traceback for specific debugging assistance.
- Common issues include:
- Network errors: Ensure internet connectivity and that https://example.com is accessible.
- Playwright errors: Verify Playwright and Chromium are installed correctly.
- File permission errors: Run the script with appropriate permissions (e.g., as administrator on Windows if needed).
- To isolate issues, try running with num_contexts=1 and a single extension.
Logging:
- The script includes verbose logging for key actions (e.g., directory creation, extension copying, state loading/saving).
- Review console output to trace execution and identify where errors occur.
- Add custom print statements in functions like new_context() or install_extension() for deeper debugging.
Testing:
- Test with a small number of contexts (e.g., num_contexts=1) to verify basic functionality.
- Test each mode separately by commenting out one call in main().
- Test with and without extensions to isolate extension-related issues.
- Run on different platforms (Linux, macOS, Windows) to confirm cross-platform compatibility.
"""
asyncwithasync_playwright()asplaywright:
try:
# Test with launch_persistent_context mode
print("Running with launch_persistent_context...")