如果 .querySelector() 支持 :nth-of-type(),当我在不起作用的脚本中使用 .querySelector("table:nth-of-type(2) tr") 时有什么问题
Microsoft Internet Controls
用于自动化浏览器(IE8+)和创建HTMLDocument
时支持它ie.Document
。然后,您可以访问极少数的伪类选择器。HTMLDocument
当通过时innerHTML
提供时,情况并非如此MSXML2.XMLHTTP
。请记住,您输入HTMLDocument
变量的内容.innerHTML
在 XHR 中会有所不同,其中 javascript 不会运行与IE
js 将运行并且浏览器将修改内容/请求其他文件,从而为您留下修改后的.document
. 如开头所述,后者当然还有浏览器/文档模式依赖项。
选择器table:nth-of-type(2) tr
,即使支持,在这里也不合适。
我感兴趣的项目(Year Built)的值并不总是在同一个索引中,所以在这里使用索引是一个错误的想法
根据对代码的仔细检查,您试图考虑的可变性似乎是目标表中列数的潜在差异,因此您的元素可能驻留在td
给定行内的不同索引处(例如,您没有尝试考虑行可变性...)。所以我们总体上正在寻找一种不同的关系;不需要元素之间的关系;或动态确定合适的索引;或者甚至是这些的组合。
国际海事组织的考虑是:
- 相同的 URI,但页面上的替代元素具有更短,希望更健壮的选择器;
- 不同的 XHR URI,其中所需元素与更健壮的选择器相关联,例如唯一 id;
- 一个
script
带有漂亮正则表达式可抓取字符串的标签 (var yearBuilt = 1234;);
- 一种具有较少依赖性和/或根据经验具有较高稳定性概率的定位策略
此外,
我承认以上是对相同整体想法的重新散列。
查看考虑因素和提供的两个链接:
与 相关联的构建年份MAIN AREA
仅出现在文档中的一个位置。注意:我保留这样的假设,即这是相应标题行的下一行。我没有检查足够多的链接来了解今年的价值是否会因房产面积而异,而且您没有说明哪个是必需的。MAIN AREA
在此示例中,显示为列出构建日期的第一部分。
该页面似乎没有从其他请求中检索所需的内容,因此替代来源不是很明显。似乎没有专用的公共 API。搜索功能不提供来自其 POST 请求的必要信息,并且可下载文件有 3-4 个月的延迟,主要是 .txt,并且不提供任何实际机会来更快地识别所需信息(实际上将是更多的工作和更少的可靠性)。
这留下了考虑 4。您需要一种方法来定位右表中的右列。html 具有非常重复的结构,几乎没有漂亮的“钩子”。而不是根据表的关系生成更脆弱的路径,您明智地选择了tr
s 上的循环(ergo 应该在表中)在tr
innerText
. 因此,权衡了标题字符串出现在不同列和/或不同表中的风险,以换取较短的遍历路径和移动到假定包含感兴趣数据的下一行的灵活性。
到目前为止,我认为是不错的选择,尽管我个人会选择将搜索限制在标题 ( th
) 中,然后升级到父级。这里的额外好处是我可以为你的下一部分减轻压力:
.Item(i).NextSibling.LastChild.PreviousSibling.innerText
在这里,您建立了一个不必要的假设/风险,即您感兴趣的列将始终是倒数第二个。虽然您可以循环所有标题并转到父节点,但我会冒险通过在面板标题中搜索唯一字符串来限制到适当的表,然后next-sibling
在检查标题之前抓取该表。它为 IMO 引入了关于内容和内容关系panel heading
的合理假设。然后,这使我们能够根据 为标题找到正确的索引,并使用该索引来索引下一行的 。这减轻了位置不是倒数第二的情况。然后,您可以寻找一些进一步的优化。我将匹配项设置为变量以便更快地引用。table
panel
table
tds
尽管有两个循环结构,但更多的代码行但没有更大的复杂性,在正确元素上匹配的安全性更高,合适的退出策略和更少的循环(由于表的目标)。
总体而言,您的策略是一个不错的策略。我个人会冒着尝试获得正确表格的风险,而不是假设正确的列是倒数第二列。我采用了稍微不同的关系并动态确定了正确的索引。我对解决方案并不完全满意,但感觉足够好。
VBA:
Option Explicit
Public Sub GetInformation()
Dim Http As New XMLHTTP60, links, i&
Dim htmlDoc As New HTMLDocument, link
Dim Wb As Workbook, ws As Worksheet, r&
Set Wb = ThisWorkbook
Set ws = Wb.Worksheets("Sheet1")
links = Array( _
"https://esearch.brazoscad.org/Property/View/114414", _
"https://esearch.brazoscad.org/Property/View/117608" _
)
For Each link In links
With Http
.Open "GET", link, False
.send
htmlDoc.body.innerHTML = .responseText
End With
Dim panels As Object, table As Object, headers As Object
Set panels = htmlDoc.querySelectorAll(".panel-heading")
For i = 0 To panels.Length - 1
If InStr(panels.Item(i).innerText, "Property Improvement - Building") > 0 Then
Set table = panels.Item(i).NextSibling 'assumption on relationship
Exit For
End If
Next i
If Not table Is Nothing Then
Set headers = table.getElementsByTagName("th")
For i = 0 To headers.Length - 1
If InStr(headers(i).innerText, "Year Built") > 0 Then
r = r + 1: ws.Cells(r, 1) = headers(i).ParentNode.NextSibling.Children(i).innerText
Exit For
End If
Next
End If
Set htmlDoc = Nothing: Set table = Nothing
Next link
End Sub
参考资料(VBE>工具>参考资料):
- Microsoft HTML 对象库
- Microsoft XML v(n) '你的版本