我正在跟踪由WiseOwlTutorials频道制作的此视频https://www.youtube.com/watch?v=sGw6r5GVA5g&t=2803s的教程,并陷入了他在视频36:00位置解释的列出程序。
那时候,他开始解释如何通过称为Sub ListVideosOnPage(VidCatName As String, VidCatURL As String)
的迭代方法从特定类别返回视频网址和视频列表名称,该方法在另一个模块中使用,该模块循环浏览其网站的所有视频类别主视频页面https://www.wiseowl.co.uk/videos(左上角菜单列表)。
此过程开始时,它将进入每个视频类别的内部,并从该类别中获取每个视频的名称和URL,以便将其列出在页面上,该页面在上述Youtube视频的该部分中是调试页面。但是,实际的WiseOwl视频页面与制作教程视频时的页面不同。
因此,为了将正确的元素放在debbugin页面上,我稍微改变了他的方法,如下所示:
Sub ListVideosOnPage(VidCatName As String, VidCatURL As String)
Dim XMLReq As New MSXML2.XMLHTTP60
Dim HTMLDoc As New MSHTML.HTMLDocument
Dim VidTables As MSHTML.IHTMLElementCollection
Dim VidTable As MSHTML.IHTMLElement
Dim VidRows As MSHTML.IHTMLElementCollection
Dim VidRow As MSHTML.IHTMLElement
Dim VidLink As MSHTML.IHTMLElement
XMLReq.Open "GET", VidCatURL, False
XMLReq.send
If XMLReq.Status <> 200 Then
MsgBox "Problem" & vbNewLine & XMLReq.Status & " - " & XMLReq.statusText
Exit Sub
End If
HTMLDoc.body.innerHTML = XMLReq.responseText
'get the table element in each video category found by other module
'VidTables tag added by me to get the new element on the WiseOwl website
Set VidTables = HTMLDoc.getElementsByTagName("table")
'loop starts to search for row and link tags on the current table
For Each VidTable In VidTables
Set VidRows = VidTable.getElementsByTagName("tr")
For Each VidRow In VidRows
Set VidLink = VidRow.getElementsByTagName("a")(0) 'just pick the first link
Debug.Print VidRow.innerText, VidRow.getattribute("href") 'objetc variable not set error happpens here
Next VidRow
Next VidTable
End Sub
我找到了一种方法,可以通过更改vidrow循环内的代码,在代码中添加手动索引以仅获取每一行的第一个链接来规避此Object Variable or With Variable not set
错误:
For Each VidTable In VidTables
Set VidRows = VidTable.getElementsByTagName("tr")
For Each VidRow In VidRows
Index = 0
For Each VidLink In VidLinks
If Index = 0 Then
Debug.Print VidLink.innerText, VidLink.getAttribute("href")
Index = Index + 1
End If
Next VidLink
Next VidRow
Next VidTable
但是,在上述参考视频中,讲师以如下所示的方式对索引进行编码时并没有出现此错误:
VidLink = VidRow.getElementsByTagName("a")(0)
Debug.Print VidRow.innerText, VidRow.getattribute("href")
所以我的问题是如何获取这些未设置错误的对象变量,而在教学视频中讲师没有这样做?在我看来,这是相同的代码,每个元素都以正确的方式定义,并且使用if进行编码的效率更高。谁会更习惯VBA,请帮忙回答一下吗?也许我错过了一些东西。
答案 0 :(得分:1)
tl:dr:
VidCatName
似乎没有被使用,但我现在已经离开了。我个人将删除,除非您以后将开发使用此变量的代码。第二个子参数是passed by value,因此我在签名中添加了ByVal
。您的错误是因为您正在循环所有表行,并尝试访问a
标记和href
属性。每个表的第一行是标题行,它没有a
标签元素,也没有关联的href
属性。参见下图:
页面上的表格元素:
请注意,表中的第一个tr
标记元素包含一个子th
标记元素,指示它是表头,并且没有关联的a
标记元素。 / p>
有点像您在该视频的其他地方看到的那样,您想要将循环更改为For Next
,然后在这种情况下,从索引1开始以跳过标题行。
因此,包含以下行的部分:For Each VidRow In VidRows
变为以下内容:
Dim VidRowID As Long
For Each VidTable In VidTables
Set VidRows = VidTable.getElementsByTagName("tr")
For VidRowID = 1 To VidRows.Length - 1 'first row is actually header which doesn't have an a tag or href
Set VidLink = VidRows(VidRowID).getElementsByTagName("a")(0)
Debug.Print VidLink.innerText, VidLink.getAttribute("href")
Next VidRowID
Next VidTable
每页只有一个表,因此在这种情况下,所有表的循环都是不必要的代码。
完整调用示例(仅将代码与循环类型的更改一起使用):
Option Explicit
Public Sub test()
ListVideosOnPage "Business Intelligence (70)", "https://www.wiseowl.co.uk/business-intelligence/videos/"
End Sub
Public Sub ListVideosOnPage(ByVal VidCatName As String,ByVal VidCatURL As String)
Dim XMLReq As New MSXML2.XMLHTTP60
Dim HTMLDoc As New MSHTML.HTMLDocument
Dim VidTables As MSHTML.IHTMLElementCollection
Dim VidTable As MSHTML.IHTMLElement
Dim VidRows As MSHTML.IHTMLElementCollection
Dim VidRow As MSHTML.IHTMLElement
Dim VidLink As MSHTML.IHTMLElement
XMLReq.Open "GET", VidCatURL, False
XMLReq.send
If XMLReq.Status <> 200 Then
MsgBox "Problem" & vbNewLine & XMLReq.Status & " - " & XMLReq.statusText
Exit Sub
End If
HTMLDoc.body.innerHTML = XMLReq.responseText
Set VidTables = HTMLDoc.getElementsByTagName("table") 'Should limit to just one table
Dim VidRowID As Long
For Each VidTable In VidTables
Set VidRows = VidTable.getElementsByTagName("tr")
For VidRowID = 1 To VidRows.Length - 1 'first row is actually header which doesn't have an a tag or href
Set VidLink = VidRows(VidRowID).getElementsByTagName("a")(0)
Debug.Print VidLink.innerText, VidLink.getAttribute("href")
Next VidRowID
Next VidTable
End Sub
我会改用CSS selector combination来定位目标父a
元素内的table
标签元素。这被写为.bpTable a
。此组合的更正式术语是descendant selector。
后代组合器-通常用单个空格( )字符-组合两个选择器,使与 如果祖先元素匹配,则选择第二个选择器 第一个选择器。利用后代组合器的选择器是 称为后代选择器。
.bpTable
实际上本身就是class selector(例如.getElementsByClassName
)。前导"."
表示的类部分。因此,类名称为bpTable
的元素;这是每个页面上目标表的类名。
页面上的目标表元素:
通过.querySelectorAll
的{{1}}方法应用此选择器,并返回一个静态.document
。然后,您可以将此nodeList
的{{1}}从.Length
循环到nodeList
,按索引访问元素。
0
参考(VBE>工具>参考):