Sunday, 17 October 2021

iframe element missing from selenium

I am trying to do some automated functionality using python selenium, and I'm coming across some weird behavior.

General layout of the html:

<html>
  <body>
    <div class="parent">
      <iframe style="display: none"> ... </iframe>
      <iframe style="display: none"> ... </iframe>
      <iframe style="display: block">
        #document
        ...
        <div class="someClass"> ... </div>
      </iframe>
      <iframe style="display: none"> ... </iframe>
      <iframe style="display: none"> ... </iframe>
    </div>
  </body>

Now, each iframe actually has the same inner html, and the code from the website seems to be randomly choosing which iframe is getting the display="block". However, I can't find any of the iframes.

I tried a standard way: iframe = driver.find_elements_by_xpath("//iframe[contains(@style, 'display:block')]")

That failing, I then tried just to find any iframe: driver.find_element_by_tag_name("iframe")

Neither of those found any iframe elements. I'm seeing the following error:

Traceback (most recent call last):
  File "myfile.py", line 60, in <module>
    iframe = driver.find_element_by_xpath("//iframe[contains(@style, 'display: block')]")
  File "C:\Python27\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 394, in find_element_by_xpath
    return self.find_element(by=By.XPATH, value=xpath)
  File "C:\Python27\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 978, in find_element
    'value': value})['value']
  File "C:\Python27\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 321, in execute
    self.error_handler.check_response(response)
  File "C:\Python27\lib\site-packages\selenium\webdriver\remote\errorhandler.py", line 242, in check_response
    raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.InvalidSelectorException: Message: invalid selector: The result of the xpath expression "//iframe[contains(@style, 'display: block')]" is: [object HTMLIFrameElement]. It should be an element.
  (Session info: chrome=93.0.4577.63)

Any thoughts on why the xpath is returning [object HTMLIFrameElement] and why I can't access that as I do other objects when searching by xpath?

Edit

New code option 1:

iframes = driver.find_elements_by_xpath(".//iframe[contains(@style,'display: block')]")

This still throws the exact same error as above

New code option 2:

parent = driver.find_element_by_xpath("//div[@class='parent']")
iframes = parent.find_elements_by_tag_name("iframe")
// when I print typeof iframes here, it's a list of dicts
// find the right index. Here, for simplicity, I just set it a default value
index = 4
// ...
driver.switch_to.frame(iframes[index])

I get the following error:

Traceback (most recent call last):
  File "myfile.py", line 76, in <module>
    driver.switch_to.frame(iframe)
  File "C:\Python27\lib\site-packages\selenium\webdriver\remote\switch_to.py", line 89, in frame
    self._driver.execute(Command.SWITCH_TO_FRAME, {'id': frame_reference})
  File "C:\Python27\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 321, in execute
    self.error_handler.check_response(response)
  File "C:\Python27\lib\site-packages\selenium\webdriver\remote\errorhandler.py", line 242, in check_response
    raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.InvalidArgumentException: Message: invalid argument: missing 'ELEMENT'
  (Session info: chrome=93.0.4577.82)

And when I print out iframes:

[{}, {}, {}, {}, {u'ontouchmove': {}, u'ontouchstart': {}}, {}, {}, {}, {}, {}]

For reference, this is the page I'm trying to hit. Sometimes you have to refresh a few times to get the challenge, and it comes far more frequent when using selenium. Also, using headless mode causes the challenge to happen everytime... https://catalog.usmint.gov/coins/coin-programs/morgan-and-peace-silver-dollar-coins/



from iframe element missing from selenium

No comments:

Post a Comment