Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue with Rebrowser-patches in Python: page.evaluate() not returning values as expected #94

Open
cptlancia opened this issue Feb 15, 2025 · 3 comments

Comments

@cptlancia
Copy link

Im kind of new to github, so let me know if I'm doing this wrong.

page.evaluate() function is not returning anything when using rebrowser-patches and context isolation is activated in any way.
The script does not continue until the method returns something, causing the code to stall.
Both addBinding and enableDisable gives me the same error, but its not a problem while using the original playwright nor when
using this setting:
os.environ["REBROWSER_PATCHES_RUNTIME_FIX_MODE"] = "0"

For the methods that work fine, the following line would print out True, whilst with rebrowser-playwright-python nothing gets printed or returned.
print(await page.evaluate("window.dummyFn()"))

This causes me to believe it has to do with context isolation.

To reproduce the issue:
I used the drop-in method for rebrowser-playwright-python using this installation "pip install rebrowser-playwright"

Semi-minimum Viable Code to reproduce:

import os
import asyncio
from rebrowser_playwright.async_api import async_playwright

# Set environment variable to use addBinding to access the main context
os.environ["REBROWSER_PATCHES_RUNTIME_FIX_MODE"] = "addBinding"  # Allow access to main context although it's also on by default
os.environ["REBROWSER_PATCHES_DEBUG"] = "1"  # Enable debugging messages to see more logs

# Custom User-Agent for Chromium (can be any valid user-agent string)
user_agent = (
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
    "Chrome/91.0.4472.124 Safari/537.36"
)

async def run():
    async with async_playwright() as p:
        # Launch Google Chrome with minimal args
        browser = await p.chromium.launch(
            headless=False,
            channel = "chrome",
            args=["--disable-blink-features=AutomationControlled"]
        )

        # Create a new context with the specified user-agent
        context = await browser.new_context(
            user_agent=user_agent  # Apply the custom user-agent
        )

        # Create a new page within the context
        page = await context.new_page()

        # Go to the bot detector page
        await page.goto("https://bot-detector.rebrowser.net/")  # Visit the bot detector

        # Trigger the dummyFn test
        print("Running dummyFn test...")
        try:
            print(await page.evaluate("window.dummyFn()"))  # Execute dummyFn in the main context
        except Exception as e:
            print(f"Error executing dummyFn: {e}")

        # Pause for inspection (optional)
        await page.pause()

# Run the script with asyncio.run() for proper asynchronous execution
asyncio.run(run())

These are the results. Interesting to see that the "dummyFn" test actually still passes. But the code doesn't continue to run, so can't run more tests.

Image

Another thing that might be useful is that it actually fails the sourceUrlLeak, mainWorldExecution and exposeFunctionLeak tests. To test this they had to be the first evaluate function in the script as it will not run after the first one.

My code for running said tests

    # Source URL Leak test
    print("Running sourceUrlLeak test...")
    try:
        await page.evaluate("document.getElementById('detections-json')")
        print("sourceUrlLeak test passed")
    except Exception as e:
        print(f"Error executing sourceUrlLeak: {e}")

    # Main world execution test
    print("Running mainWorldExecution test...")
    try:
        await page.evaluate("document.getElementsByClassName('div')")
        print("mainWorldExecution test passed")
    except Exception as e:
        print(f"Error executing mainWorldExecution: {e}")

    # Expose function leak test
    print("Running exposeFunctionLeak test...")
    try:
        await page.expose_function('exposedFn', lambda: print('exposedFn call'))
        print("exposeFunctionLeak test passed")
    except Exception as e:
        print(f"Error executing exposeFunctionLeak: {e}")

But I understand that some of these are still waiting for a patch for the playwright-python version.
Which I'm very keenly waiting for by the way.

@nwebson
Copy link
Contributor

nwebson commented Feb 16, 2025

Thanks for such a detailed bug report. I see you have REBROWSER_PATCHES_DEBUG enabled, so what does it say in the console logs right when page.evaluate is called?

@cptlancia
Copy link
Author

Sorry for late response, didn't have access to my computer for a few days so couldn't double check.

But the REBROWSER_PATCHES_DEBUG doesn't seem to be producing any logs for me.

@cptlancia
Copy link
Author

Okay, so I'm understanding a little bit better about what is happening.

It seems that it might be specifically page.evaluate() that is the problem.

The following code doesn't return anything, stalling the script:
print(await page.evaluate("Test")

If I instead send CDP commands directly instead through for example:

await page.context.new_cdp_session(page).send('Runtime.evaluate', {
        'expression': 'window.dummyFn()'
    })

then I seem to be passing all the tests on bot-detector.rebrowser.net (except mainWorldExecution as it's not fixed yet for playwright).

Does this mean that any javascript being run through the browser using the ".page" object is currently not returning any values?
I wonder what other side-effects this might have for other functions I might be using.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants