How can I select a button contained within an iFrame in Playwright (python) by index?
Asked Answered
A

2

7

I am attempting to select a button within an iframe utilizing Python & Playwright... in Selenium I know you can do this by using indexes. Is this possible in playwright? I've been digging through the documentation and can't seem to figure it out. The button contained within the iframe that I am trying to select is:

"button:has-text(\"Add New User\")"

The html code for the iframe I am using looks similar to this:

<iframe src="https://www.urlthatcannotbereturnedinpagehtml.com/veryparticularparameters" width="100%" style="height: 590px;"></iframe>

Does anyone have any thoughts? I've attempted to find the URL by parsing the code for the webpage, but this portion can't be selected like that. I may just be at a loss with the documentation in Playwright, I've spent so much time in selenium that this seems like an entirely new language.

Ailee answered 21/9, 2022 at 22:42 Comment(0)
G
11

From what I understand, you have a page that has content within an iframe. You want to use Playwright to access elements within that frame.

The official docs to handle frames: Official docs: https://playwright.dev/python/docs/frames

You could then try something like this:

// Locate element inside frame
const iframeButton = await page.frameLocator('iFrame').locator("button:has-text(\"Add New User\")");
await iframeButton.click();

Notice that the example has the iFrame tag as locator, but you could and should use something more accurate like and id, name or url.

Gehenna answered 22/9, 2022 at 4:26 Comment(1)
A common misconception is that locators need to be awaited. They don't return a promise, so you can remove await from await page.frameLocator('iFrame'). The only await necessary is on the action taken on the locator, .click() in this case. Technically, there's nothing wrong with awaiting a locator, but it's a bit misleading and it's extra syntax that doesn't need to be there. Also, the question is tagged Python, so I'm not sure how this answers OP's question.Ozzy
O
1

You can try using frame_locator and the [src^=...] CSS "starts with" attribute selector:

frame_sel = '[src^="https://www.urlthatcannotbereturnedinpagehtml.com"]'
frame = page.frame_locator(frame_sel)
frame.get_by_role("button", name="Add New User").click()

That said, it's generally a good idea to show the actual page because there may be a better way to select that frame based on its enclosing context, or presence of other elements on the page with the same attributes.

I'm not sure what a "URL that cannot be returned in page HTML" means, but I assume it's loaded asynchronously. Since locators auto-wait, this shouldn't pose an issue.

Complete, runnable example for demonstration:

from playwright.sync_api import sync_playwright # 1.43.0


html = """<!DOCTYPE html><html><body>
<iframe src="http://localhost:8000/test.html"></iframe>
</body></html>"""


with sync_playwright() as p:
    browser = p.chromium.launch()
    page = browser.new_page()
    page.set_content(html)
    frame_sel = '[src^="http://localhost:8000/"]'
    frame = page.frame_locator(frame_sel)
    frame.get_by_role("button", name="Add New User").click()
    browser.close()

test.html (serve on localhost with python -m http.server):

<!DOCTYPE html>
<html>
<body>
<button>Add New User</button>
</body>
</html>

Another option is to use page.frame(url=r""):

# ...
    page.set_content(html)
    frame = page.frame(url=r"http://localhost:8000/*")
    frame.get_by_role("button", name="Add New User").click()
    browser.close()
Ozzy answered 13/4, 2024 at 20:21 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.