我在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?&cocode=INE117A01022&Cname=ABB-India-Ltd&srno=17019039003&opt=9">ABB India Limited - Press Release</a>
</div>
我想抓住该页面链接的图片:
从创建此线程的第一天起,我严格要求不使用此URL http://hindubusiness.cmlinks.com/Companydetails.aspx?cocode=INE117A01022
来查找数据。我已经请求了此main_page_link的任何解决方案,但未触及iframe中的链接。但是,每个人都在努力提供我已在帖子中展示过的解决方案。那时我给了什么赏金?
答案 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中编写的库中的函数
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