无法解析iframe

时间:2018-02-10 11:20:34

标签: vba excel-vba iframe web-scraping internet-explorer-11

我在vba中编写了一个脚本,使用IE来解析网页上的一些链接。问题是链接在iframe内。我以这样的方式抽动了我的代码,以便脚本首先在iframe内找到一个链接并导航到该新页面并从那里解析所需的内容。如果我这样做,那么我可以获得所有链接。

网页网址:weblink

成功的方法(工作方法):

Sub Get_Links()
    Dim IE As New InternetExplorer, HTML As HTMLDocument
    Dim elem As Object, post As Object

    With IE
        .Visible = True
        .navigate "put here the above link"
        While .Busy = True Or .readyState < 4: DoEvents: Wend
        Set elem = .document.getElementById("compInfo")   #it is within iframe
        .navigate elem.src
        While .Busy = True Or .readyState < 4: DoEvents: Wend
        Set HTML = .document
    End With

    For Each post In HTML.getElementsByClassName("news")
        With post.getElementsByTagName("a")
         If .Length Then R = R + 1: Cells(R, 1) = .Item(0).href
        End With
    Next post
    IE.Quit
End Sub 

我在iframe内看到很少有网站没有此类链接,因此,我无法使用任何链接来跟踪内容。

如果您通过跟踪链接来查看以下方法,那么您可以注意到我已经解析了Iframe内的网页内容。 Iframe内没有此类链接可导航到新网页以查找内容。所以,我使用contentWindow.document代替它,发现它完美无缺。

链接到解析来自其他网站的Iframe内容的工作代码:         contentWindow approach

但是,我的问题是:为什么我应该导航到新网页来收集链接,因为我可以看到目标网页中的内容?我尝试使用contentWindow.document,但它给了我访问被拒绝错误。如何像上面那样使用contentWindow.document使我的下面的代码工作?

我试过这样但是它会抛出拒绝访问错误:

Sub Get_Links()
    Dim IE As New InternetExplorer, HTML As HTMLDocument
    Dim frm As Object, post As Object

    With IE
        .Visible = True
        .Navigate "put here the above link"
        While .Busy = True Or .readyState < 4: DoEvents: Wend
        Set HTML = .document
    End With

    ''the code breaks when it hits the following line "access denied error"

    Set frm = HTML.getElementById("compInfo").contentWindow.document

    For Each post In frm.getElementsByClassName("news")
        With post.getElementsByTagName("a")
         If .Length Then R = R + 1: Cells(R, 1) = .Item(0).href
        End With
    Next post
    IE.Quit
End Sub

我附上了一张图片,告诉您我之后的哪些链接(用铅笔标记)。

这些是找到一个这样的链接(我想抓住)的元素:

<div class="news">
    <span class="news-date_time"><img src="images/arrow.png" alt="">19 Jan 2018 00:01</span>
    <a style="color:#5b5b5b;" href="/HomeFinancial.aspx?&amp;cocode=INE117A01022&amp;Cname=ABB-India-Ltd&amp;srno=17019039003&amp;opt=9">ABB India Limited - Press Release</a>
 </div>

我想抓住该页面链接的图片:

enter image description here

从创建此线程的第一天起,我严格要求不使用此URL http://hindubusiness.cmlinks.com/Companydetails.aspx?cocode=INE117A01022来查找数据。我已经请求了此main_page_link的任何解决方案,但未触及iframe中的链接。但是,每个人都在努力提供我已在帖子中展示过的解决方案。那时我给了什么赏金?

3 个答案:

答案 0 :(得分:2)

这样的事情应该有效。关键是要意识到iFrame在技术上是另一个Document。查看您列出的页面上的iFrame,您可以轻松使用Web请求获取所需的数据。如前所述,您收到错误的原因是由于Same-Origin策略。你可以写一些内容来获取src的{​​{1}},然后按照我在下面显示的那样执行web请求,或者使用IE来抓取页面,获取{ {1}},然后加载看起来像你所做的那样的页面。

我建议使用Web请求方法,Internet Explorer可能会变得烦人,快速。

<强>代码

iFrame

<强>结果

src

答案 1 :(得分:2)

您可以在浏览器中看到<iframe>中的链接,但由于Same-origin policy而无法以编程方式访问这些链接。

有一个示例显示如何使用XHR和RegEx检索链接:

Option Explicit

Sub Test()

    Dim sContent As String
    Dim sUrl As String
    Dim aLinks() As String
    Dim i As Long

    ' Retrieve initial webpage HTML content via XHR
    With CreateObject("MSXML2.XMLHTTP")
        .Open "GET", "https://www.thehindubusinessline.com/stocks/abb-india-ltd/overview/", False
        .Send
        sContent = .ResponseText
    End With
    'WriteTextFile sContent, CreateObject("WScript.Shell").SpecialFolders("Desktop") & "\tmp\tmp.htm", -1
    ' Extract target iframe URL via RegEx
    With CreateObject("VBScript.RegExp")
        .Global = True
        .MultiLine = True
        .IgnoreCase = True
        ' Process all a within div.news
        .Pattern = "<iframe[\s\S]*?src=""([^""]*?Companydetails[^""]*)""[^>]*>"
        sUrl = .Execute(sContent).Item(i).SubMatches(0)
    End With
    ' Retrieve iframe HTML content via XHR
    With CreateObject("MSXML2.XMLHTTP")
        .Open "GET", sUrl, False
        .Send
        sContent = .ResponseText
    End With
    'WriteTextFile sContent, CreateObject("WScript.Shell").SpecialFolders("Desktop") & "\tmp\tmp.htm", -1
    ' Parse links via XHR
    With CreateObject("VBScript.RegExp")
        .Global = True
        .MultiLine = True
        .IgnoreCase = True
        ' Process all anchors within div.news
        .Pattern = "<div class=""news"">[\s\S]*?href=""([^""]*)"
        With .Execute(sContent)
            ReDim aLinks(0 To .Count - 1)
            For i = 0 To .Count - 1
                aLinks(i) = .Item(i).SubMatches(0)
            Next
        End With
    End With
    Debug.Print Join(aLinks, vbCrLf)

End Sub

一般情况下,建议不要使用RegEx进行HTML解析,因此there is disclaimer。在这种情况下处理的数据非常简单,这就是使用RegEx解析的原因。

我的输出如下:

/HomeFinancial.aspx?&cocode=INE117A01022&Cname=ABB-India-Ltd&srno=17047038016&opt=9
/HomeFinancial.aspx?&cocode=INE117A01022&Cname=ABB-India-Ltd&srno=17046039003&opt=9
/HomeFinancial.aspx?&cocode=INE117A01022&Cname=ABB-India-Ltd&srno=17045039006&opt=9
/HomeFinancial.aspx?&cocode=INE117A01022&Cname=ABB-India-Ltd&srno=17043039002&opt=9
/HomeFinancial.aspx?&cocode=INE117A01022&Cname=ABB-India-Ltd&srno=17043010019&opt=9

我还尝试使用命令将<iframe>的内容从IE复制到剪贴板(以便进一步粘贴到工作表):

IE.ExecWB OLECMDID_SELECTALL, OLECMDEXECOPT_DODEFAULT
IE.ExecWB OLECMDID_COPY, OLECMDEXECOPT_DODEFAULT

但实际上,除非我手动点击框架,否则命令会选择并复制主文档,不包括框架。因此,如果可以从VBA中复制点击帧,则可以应用这一点(.focus.click等帧节点方法没有帮助。

答案 2 :(得分:1)

像所有人建议的简单解决方案是直接进入链接。这会使IFRAME失去图片,你可以更容易地循环链接。但是如果你仍然不喜欢这种方法,那么你需要深入了解这个洞。

下面是我在VB.NET中编写的库中的函数

https://github.com/tarunlalwani/ScreenCaptureAPI/blob/2646c627b4bb70e36fe2c6603acde4cee3354b39/Source%20Code/ScreenCaptureAPI/ScreenCaptureAPI/ScreenCapture.vb#L803

http://127.0.0.1:8000/?var=fea40u7b94

所以基本上这是一个低于C ++版本的VB.NET版本

Accessing body (at least some data) in a iframe with IE plugin Browser Helper Object (BHO)

现在您只需将其移植到VBA即可。您可能遇到的唯一问题是找到Private Function _EnumIEFramesDocument(ByVal wb As HTMLDocumentClass) As Collection Dim pContainer As olelib.IOleContainer = Nothing Dim pEnumerator As olelib.IEnumUnknown = Nothing Dim pUnk As olelib.IUnknown = Nothing Dim pBrowser As SHDocVW.IWebBrowser2 = Nothing Dim pFramesDoc As Collection = New Collection _EnumIEFramesDocument = Nothing pContainer = wb Dim i As Integer = 0 ' Get an enumerator for the frames If pContainer.EnumObjects(olelib.OLECONTF.OLECONTF_EMBEDDINGS, pEnumerator) = 0 Then pContainer = Nothing ' Enumerate and refresh all the frames Do While pEnumerator.Next(1, pUnk) = 0 On Error Resume Next ' Clear errors Err.Clear() ' Get the IWebBrowser2 interface pBrowser = pUnk If Err.Number = 0 Then pFramesDoc.Add(pBrowser.Document) i = i + 1 End If Loop pEnumerator = Nothing End If _EnumIEFramesDocument = pFramesDoc End Function rerefernce。其余大部分都是VBA兼容的

所以一旦你得到了一个对象数组,你就会找到一个属于你的框架然后你可以只有那个

olelib