Accessing object in iframe using VBA Accessing object in iframe using VBA vba vba

Accessing object in iframe using VBA


It is sometimes tricky with iframes. Based on html you provided I have created this example. Which works locally, but would it work for you as well?

To get to the IFrame the frames collection can be used. Hope you know the name of the IFrame?

Dim iframeDoc As MSHTML.HTMLDocumentSet iframeDoc = doc.frames("iframename").document

Then to go the the image we can use querySelector method e.g. like this:

Dim img As MSHTML.HTMLImgSet img = iframeDoc.querySelector("div table[id='table1'] tbody tr td a[href^='https://stackoverflow.com'] img")

The selector a[href^='https://stackoverflow.com'] selects anchor which has an href attribute which starts with given text. The ^ denotes the beginning.

Then when we have the image just a simple call to click on its parent which is the desired anchor. HTH


Complete example:

Option Explicit' Add reference to Microsoft Internet Controls (SHDocVw)' Add reference to Microsoft HTML Object LibrarySub Demo()    Dim ie As SHDocVw.InternetExplorer    Dim doc As MSHTML.HTMLDocument    Dim url As String        url = "file:///C:/Users/dusek/Documents/My Web Sites/mainpage.html"    Set ie = New SHDocVw.InternetExplorer    ie.Visible = True    ie.navigate url    While ie.Busy Or ie.readyState <> READYSTATE_COMPLETE        DoEvents    Wend        Set doc = ie.document        Dim iframeDoc As MSHTML.HTMLDocument    Set iframeDoc = doc.frames("iframename").document    If iframeDoc Is Nothing Then        MsgBox "IFrame with name 'iframename' was not found."        ie.Quit        Exit Sub    End If        Dim img As MSHTML.HTMLImg    Set img = iframeDoc.querySelector("div table[id='table1'] tbody tr td a[href^='https://stackoverflow.com'] img")    If img Is Nothing Then        MsgBox "Image element within iframe was not found."        ie.Quit        Exit Sub    Else        img.parentElement.Click    End If        ie.QuitEnd Sub

Main page HTML used

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><!-- saved from url=(0016)http://localhost --><meta content="text/html; charset=utf-8" http-equiv="Content-Type" /><title>x -</title></head><body><iframe name="iframename" src="iframe1.html"></iframe></body></html>

IFrame HTML used (saved as file iframe1.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><!-- saved from url=(0016)http://localhost --><meta content="text/html; charset=utf-8" http-equiv="Content-Type" /><title>Untitled 2</title></head><body><div align="center">     <table id="table1" style="border-collapse: collapse" width="700" cellspacing="0" cellpadding="0" border="0">         <tbody>            <tr>                <td colspan="6">  </td>            </tr>             <tr>                 <td colspan="6">                     <a href="https://stackoverflow.com/questions/44902558/accessing-object-in-iframe-using-vba">                        <img src="img.gif" width="38" height="38" border="0" align="right">                    </a>                    <strong>x - </strong>                </td>            </tr>         </tbody>    </table></div></body></html>

BTW, The frame may be referenced by it's index also doc.frames(0).document. Thanks to Paulo Bueno.


I thought I would expand on the answer already given.

In the case of Internet Explorer you may have one of two common situations to handle regarding iframes.

  1. src of iframe is subject to same origin policy restrictions:

The iframe src has a different origin to the landing page in which case, due to same origin policy, attempts to access it will yield access denied.

Resolution:

Consider using selenium basic to automate a different browser such as Chrome where CORS is allowed/you can switch to the iframe and continue working with the iframe document

Example:

Option Explicit'download selenium https://github.com/florentbr/SeleniumBasic/releases/tag/v2.0.9.0'Ensure latest applicable driver e.g. ChromeDriver.exe in Selenium folder'VBE > Tools > References > Add reference to selenium type libraryPublic Sub Example()    Dim d As WebDriver    Const URL As String = "https://www.rosterresource.com/mlb-roster-grid/"    Set d = New ChromeDriver    With d        .Start "Chrome"        .get URL        .SwitchToFrame .FindElementByCss("iframe") '< pass the iframe element as the identifier argument        ' .SwitchToDefaultContent ''to go back to parent document.        Stop '<== delete me later        .Quit    End WithEnd Sub

  1. src of iframe is not subject to same origin policy restrictions:

Resolution:

The methods as detailed in answer already given. Additionally, you can extract the src of the iframe and .Navigate2 that to access

.Navigate2 .document.querySelector("iframe").src

If you only want to work with the contents of the iframe then simply do your initial .Navigate2 the iframe src and don't even visit the initial landing page

Example:

Option ExplicitPublic Sub NavigateUsingSrcOfIframe()    Dim IE As New InternetExplorer    With IE        .Visible = True        .Navigate2 "http://www.bursamalaysia.com/market/listed-companies/company-announcements/5978065"        While .Busy Or .readyState < 4: DoEvents: Wend                .Navigate2 .document.querySelector("iframe").src                While .Busy Or .readyState < 4: DoEvents: Wend        Stop '<== delete me later        .Quit    End WithEnd Sub

  1. iframe in ShadowRoot

An unlikely case might be an iframe in shadowroot. You should really have one or the other and not one within the other.

Resolution:

In that case you need an additional accessor of

Element.shadowRoot.querySelector("iframe").contentDocument

where Element is your parent element with shadowRoot attached. This method will only work if the shadowRoot mode is set to Open.

Side note:

A nice selenium based example, using ExecuteScript to return shadowRoot is given here: How Do I Access Elements in the Shadow DOM using Selenium in VBA?


Adding to the answers given:

If you're ok with using a DLL and rewrite your code, you can run Microsoft's Edge browser (a Chrome-based browser) with VBA. With that you can do almost anything you want. Note however, that access to the DOM is performed by javascript, not by an object like Dim IE As New InternetExplorer. Look at the VBA sample and you'll get the grasp.

https://github.com/peakpeak-github/libEdge

Sidenote: Samples for C# and C++ are also included.