0

A block of code, from the webpage I'm working on looks like the following -

<div class="A">
  <iframe id="frameA">
    #document
      <html style>
        <head></head>
        <body style>
          <p style>Random Text Goes Here</p>
        </body>
      </html>
  </iframe>
</div>

I would like to extract the text in the paragraph tag, "Random Text Goes Here". However, many articles on the internet suggest that iframes cannot be identified directly using an XPath or a CSS Selector like divs and spans are, using their classes or ids. I've experienced the same, upon trying this piece of code -

exem = driver.find_element_by_tag_name("frameA")
driver.switch_to.frame(exem)
required_field = driver.find_element_by_xpath("html/body/p").text
print(required_field) 

I'm not sure if the aforementioned code is even right, but I've just tried doing this on the basis of things I've understood from some online sources. This fails to find the paragraph in the iframe, i.e. a NoSuchElementException is raised.

Can someone help me out with this?

Pranav N
  • 49
  • 5

3 Answers3

2
driver.find_element_by_tag_name("frameA")

FrameA is id not tag , change locator to iframe

driver.find_element_by_tag_name("iframe")

Or

driver.find_element_by_id("frameA")

Note:

driver.switch_to_frame or driver.switch_to.frame both support frame_name . Eg

driver.switch_to.frame("frameSOmething") but as the iframe doesn't have any attribute 'name' in your case . You can use only above mentioned methods

PDHide
  • 18,113
  • 2
  • 31
  • 46
  • NoSuchElementException Traceback (most recent call last) in 51 52 ---> 53 exem = driver.find_element_by_id("frameA") 54 driver.switch_to.frame(exem) 55 required_field = driver.find_element_by_xpath("html/body/p").text NoSuchElementException: Message: no such element: Unable to locate element: {"method":"css selector","selector":"[id="frameA"]"} (Session info: chrome=87.0.4280.88) Sorry for multiple edits, mate, I'm new to StackOverflow, and a beginner in Selenium – Pranav N Jan 05 '21 at 18:00
  • Is this frame inside another frame ? How many frames are there in the page ? – PDHide Jan 05 '21 at 18:09
  • Nope, but this iframe is nested in a multitude of divisions. Do I have to mention the "ids" of these div tags before I access the iframe or something ? ( could this be why it isn't working ) Also, there's another iframe in the page, however, it's at the bottom of the page, so technically, the iframe I've mentioned above is supposed to come first when an iframe is searched for using the `find_element_by_tag_name` method – Pranav N Jan 05 '21 at 18:15
  • Thank you for the suggestion, @PDHide, my code now works! It didn't work because of a completely different cause though :) – Pranav N Jan 05 '21 at 19:48
1

Your Xpath is off:

exem = driver.find_element_by_tag_name("frameA")
driver.switch_to.frame(exem)
required_field = driver.find_element_by_xpath("/html/body/p").text
print(required_field) 

Should work. You could also just use //p in this case.

DMart
  • 2,401
  • 1
  • 14
  • 19
0

Apparently, turns out that the problem I faced ( as mentioned in the question ) wasn't because the XPath was wrong, it was because of two things, which I'd like to explain further in this answer, by drawing a comparison between

a) The code I initially wrote and posted in the question, (wrong)

exem = driver.find_element_by_tag_name("frameA")
driver.switch_to.frame(exem)
required_field = driver.find_element_by_xpath("html/body/p").text
print(required_field)

versus

b) The modified version of it ( which is now error-free and perfectly working )

driver.implicitly_wait(20)
exem = driver.find_element_by_tag_name("iframe")
driver.switch_to.frame(exem)
required_field = driver.find_element_by_xpath("html/body/p").text
print(required_field)

(or)

driver.implicitly_wait(20)
exem = driver.find_element_by_id("frameA")
driver.switch_to.frame(exem)
required_field = driver.find_element_by_xpath("html/body/p").text
print(required_field)
  1. As aptly mentioned by @PDHide, frameA in this example is the id of the iframe, and not a tag. Hence, using frameA as the argument to driver.find_element_by_tag_name() would be meaningless, and hence, I've replaced it by

driver.find_element_by_tag_name("iframe") (or) driver.find_element_by_id("frameA")

In simple use cases ( when web pages contain just one iframe ), either of these may be used.

  1. The actual cause of my initial code failing was inadequate time given to the web page for all of its components to load, i.e. in the absence of a mechanism to pause the operations of the driver for few seconds, the driver would not wait for components such as iframes to load, and would hence not find the iframe in the script of the page, eventually returning no element, leading to the NoSuchElementException.

To avoid this, a mechanism to instruct the driver to wait for few seconds is needed, and that is exactly what the method driver.implicitly_wait() does. It takes the number of seconds the driver has to wait for as its argument, and instructs the driver to wait accordingly. This is what you see in the first line of my modified code.

Also, @DMart aptly mentions the use of //p in the XPath, because it does work, without having to use html/body/p, so the code works with //p in the XPath too.


Note: Waits may be explicit too, i.e. triggered by/after the execution of a series of conditions or statements.

Find a detailed read on "waits" here - https://selenium-python.readthedocs.io/waits.html

A site explaining some usecases of iframes with Selenium - Python - https://chercher.tech/python/iframe-selenium-python#handle-single-iframe

A similar issue on StackOverflow, Selenium with Java - Selenium WebDriver can't locate element in iframe even when switching to it


Pranav N
  • 49
  • 5