【问题标题】:Accessing object in iframe using VBA使用 VBA 访问 iframe 中的对象
【发布时间】:2020-09-07 02:19:33
【问题描述】:

重点:

我已成功使用 VBA 完成以下操作:

  • 使用 getElementsByName 登录网站

  • 为将要生成的报告选择参数(使用 getelementsby...)

  • 在选择参数后生成报告,将生成的数据集呈现到同一页面上的 iframe 中

重要提示 - 该网站是客户端

以上是简单的部分,困难的部分如下:

点击 iframe 中的 gif 图像将数据集导出到 csv

我尝试了以下方法:

Dim idoc As HTMLDocument
Dim iframe As HTMLFrameElement
Dim iframe2 As HTMLDocument

Set idoc = objIE.document
Set iframe = idoc.all("iframename")
Set iframe2 = iframe.contentDocument

    Do Until InStr(1, objIE.document.all("iframename").contentDocument.innerHTML, "img.gif", vbTextCompare) = 0
        DoEvents
    Loop

为上面的逻辑提供一些上下文-

  • 我访问了主框架
  • 我通过名称元素访问了 iframe
  • 我访问了 iframe 中的内容
  • 我试图找到需要点击导出到 csv 的 gif 图片

正是在这一行,它会说“对象不支持此属性或方法”

还尝试通过 a 元素和 href 属性访问 iframe gif,但这完全失败了。我还尝试从其源 URL 中获取图像,但所有这些都将我带到了图像来自的页面。

注意:iframe 没有 ID,奇怪的是 gif 图像没有“onclick”元素/事件

最终考虑 - 尝试使用 R 抓取 iframe

访问 iframe 的 HTML 节点很简单,但是尝试访问 iframe 的属性以及随后表的节点被证明是不成功的。它返回的只是“Character(0)”

library(rvest)
library(magrittr)

Blah <-read_html("web address redacted") %>%
  html_nodes("#iframe")%>%
  html_nodes("#img")%>%
  html_attr("#src")%>%
  #read_html()%>%
  head()
Blah

只要 i 包含 read_html,脚本就会返回以下错误:

if (grepl("", x)) { : 参数长度为零时出错

我怀疑这是指 Character(0)

在这里感谢任何指导!

非常感谢,

HTML

<div align="center"> 
    <table id="table1" style="border-collapse: collapse" width="700" cellspacing="0" cellpadding="0" border="0"> 
        <tbody>
            <tr>
                <td colspan="6"> &nbsp;</td>
            </tr> 
            <tr> 
                <td colspan="6"> 
                    <a href="href redacted">
                        <img src="img.gif" width="38" height="38" border="0" align="right">
                    </a>
                    <strong>x - </strong>
                </td>
            </tr> 
        </tbody>
    </table>
</div>

【问题讨论】:

  • 向我们展示 gif 周围的 HTML 代码。您已经可以通过 contentDocument 访问 iframe,对吧?现在只需要围绕 GIF 的 HTML。然后我们可以看到
  • @MacroMarc 需要查看html的哪一部分?
  • 是href吗?
  • gif的父元素和gif本身...

标签: html excel vba iframe web-scraping


【解决方案1】:

iframes 有时很棘手。根据您提供的html,我创建了这个示例。哪个适用于本地,但它也适用于您吗?

要访问IFrame,可以使用frames 集合。希望你知道IFramename 吗?

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

然后去image我们可以使用querySelector方法例如像这样:

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

选择器a[href^='https://stackoverflow.com'] 选择anchor,它具有以给定文本开头的href 属性。 The ^ denotes the beginning.

然后,当我们拥有图像时,只需在其父级上简单调用click,即所需的anchor。高温


完整示例:

Option Explicit

' Add reference to Microsoft Internet Controls (SHDocVw)
' Add reference to Microsoft HTML Object Library

Sub 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.Quit
End Sub

使用的主页 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>x -</title>
</head>

<body>
<iframe name="iframename" src="iframe1.html">
</iframe>
</body>

</html>

使用的 IFrame HTML(保存为文件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"> &nbsp;</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>

顺便说一句,该框架可能被它的索引也引用doc.frames(0).document。感谢 Paulo Bueno。

【讨论】:

  • 好的,所以成功地让它点击了gif!谢谢!但是... gif 导出一个 csv 文件,其中包含 iframe 中的数据。导出为空... csv 中没有任何内容,但 iframe 中有我可以看到
  • 所以困难的部分还没有完成:)。在anchor 上的click 之后,在iframe 内部加载的数据应该导出到csv-file。您会在iframe 中看到数据,但在anchor 上的click 之后csv-file 是空的。我理解正确吗?
  • 是的,没错。我收到网络浏览器提示以打开或另存为文件。我手动打开它,但文件是空的
  • 您必须检查请求,例如通过IE Developer Tools - F12。当您以编程方式单击锚点时,将请求与案例中的请求进行比较。查看query string 等并尝试找出差异。但是如果不直接看到就很难说。
  • 您究竟需要查看什么来解决这个问题? DOM 资源管理器/F12 工具中有很多区域
【解决方案2】:

我想我会扩展已经给出的答案。

对于 Internet Explorer,您可能需要处理有关 iframe 的两种常见情况之一。

  1. iframe 的 src 受同源策略限制:

iframe src 与着陆页的来源不同,在这种情况下,由于same origin policy,尝试访问它会产生拒绝访问

分辨率:

考虑使用 selenium basic 来自动化不同的浏览器,例如允许 CORS 的 Chrome/您可以切换到 iframe 并继续使用 iframe 文档

示例:

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 library
Public 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 With
End Sub

  1. iframe 的 src 不受同源策略限制:

分辨率:

已经给出的答案中详述的方法。另外,您可以提取iframe.Navigate2的src来访问

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

如果您只想使用 iframe 的内容,那么只需执行初始的 .Navigate2iframe src,甚至不要访问初始登录页面

示例:

Option Explicit
Public 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 With
End Sub

  1. ShadowRoot 中的 iframe

不太可能的情况是shadowroot 中的iframe。你真的应该有one or the other,而不是一个在另一个中。

解析:

在这种情况下,您需要一个额外的访问器

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

其中Element 是您的父元素,附有shadowRoot。此方法仅在 shadowRoot mode 设置为 Open 时有效。

旁注:

这里给出了一个很好的基于硒的示例,使用ExecuteScript 返回shadowRootHow Do I Access Elements in the Shadow DOM using Selenium in VBA?

【讨论】:

    【解决方案3】:

    添加到给出的答案:

    如果您可以使用 DLL 并重写代码,则可以使用 VBA 运行 Microsoft 的 Edge 浏览器(基于 Chrome 的浏览器)。有了它,你几乎可以做任何你想做的事情。但是请注意,对 DOM 的访问是由 javascript 执行的,而不是由像 Dim IE As New InternetExplorer 这样的对象执行的。查看 VBA 示例,您就会掌握。

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

    旁注:C# 和 C++ 的示例也包括在内。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-01-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-21
      相关资源
      最近更新 更多