无法使用vba

时间:2019-11-09 05:55:40

标签: excel vba web-scraping queryselector

我已经在VBA中创建了一个脚本来从网页中获取特定项目。我感兴趣的项目(Year Built)的值并不总是在同一索引中,因此在这里使用索引是错误的主意。我在下面给出两个链接仅仅是因为项目的值在两个网页中的索引不同。

site one

site two

我最初获取价值的方法是:

.NextSibling.getElementsByTagName("td")(3).innerText

我追求的值显示为:

enter image description here

我现在正在尝试的方法(可以工作,但位置仍然是假设的,如果位置发生变化,它将中断):

.NextSibling.LastChild.PreviousSibling.innerText

到目前为止,我已经创建了:

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


        With Htmldoc.querySelectorAll("tr")
            For i = 0 To .Length - 1
                If InStr(.item(i).innerText, "Year Built") > 0 Then
                    r = r + 1: ws.Cells(r, 1) = .item(i).NextSibling.LastChild.PreviousSibling.innerText
                End If
            Next i
        End With
    Next link
End Sub

如何从网页上获得商品的特定价值?

顺便说一句,如果.querySelector()支持:nth-of-type(),那么当我在无法使用的脚本中使用.querySelector("table:nth-of-type(2) tr")时,怎么了?{p}

1 个答案:

答案 0 :(得分:3)

  

如果.querySelector()支持:nth-​​of-type(),那怎么了   .querySelector(“ table:nth-​​of-type(2)tr”)当我在   脚本不起作用

使用Microsoft Internet Controls自动执行浏览器(IE8 +)并在HTMLDocument之外创建ie.Document时,支持该功能。然后,您可以访问极少量的pseudo class selectors。通过HTMLDocument提供innerHTML时,MSXML2.XMLHTTP并非如此。请记住,您输入到HTMLDocument变量.innerHTML中的内容在无法运行JavaScript的XHR中与将运行js并且浏览器将修改内容/请求其他内容的IE有所不同留下修改后的.document的文件。如开头所述,当然还有后者的浏览器/文档模式依赖性。

选择器table:nth-of-type(2) tr即使受支持,在这里也不适合。

  

我感兴趣的商品的价值(年份)并不总是在   相同的索引,因此在这里使用索引是错误的想法

根据对代码的仔细检查,您似乎要考虑的可变性是目标表中列数的潜在差异,因此元素可能位于td给定行中的其他索引(例如,您不尝试考虑行的可变性...)。因此,我们总体上在寻找一种不同的关系。元素之间没有关系;或动态确定适当的索引;甚至是这些的组合。

IMO的考虑因素是:

  • 相同的URI,但页面上的替代元素具有更短,希望更强大的选择器;
  • 不同的XHR URI,其中所需元素与更强大的选择器关联,例如唯一的ID;
  • 带有不错的正则表达式可抓取字符串的script标签(var yearBuilt = 1234;);
  • 具有较少依赖性和/或基于经验的随时间推移具有较高稳定性的位置策略

另外,

  • 针对更快的检索进行了优化

我认识到以上内容是对相同总体思想的重新散布。

注意事项和提供的两个链接:

MAIN AREA关联的建造年份仅出现在文档中的一个位置。注意:我保留以下假设:这是相应标题行下方的下一行。我还未检查足够的链接来知道这一年的价值是否会随房屋面积的变化而变化,并且您还没有说明这是必需的。在该示例中,MAIN AREA似乎是列出了构建日期的第一部分。

该页面似乎未从其他请求中检索所需的内容,因此备用来源并不立即可见。似乎没有专用的公共API。 search functionality未提供其POST请求中的必要信息,而downloadable files的滞后时间为3-4个月,主要是.txt,并且没有提供任何现实的机会来更快地识别所需的信息(实际上,这会增加工作量,降低可靠性)。

这需要考虑4。您需要一种方法在右表中找到右列。 html具有非常重复的结构,几乎没有“钩子”。明智的选择是在tr(应该在表中)上循环,而不是根据表的关系生成更脆弱的路径,而在tr {{1}中寻找关键标头字符串}。因此,要权衡报头字符串出现在不同的列和/或不同的表中的风险,以获取更短的遍历路径和灵活性,以移动到假定包含目标数据的下一行。

到目前为止,我认为是不错的选择,尽管我个人会选择将搜索限制在标头(innerText)之后,然后再选择上级。这里的另一个好处是我可以减轻您的下一部分负担:

th

在这里,您已经建立了不必要的假设/风险,即您所关注的列将永远是倒数第二个。尽管您可以循环所有标头并转到父节点,但我会冒这样的风险,即在面板标头中搜索唯一的字符串,然后在检查标头之前抓取.Item(i).NextSibling.LastChild.PreviousSibling.innerText 表,以限制使用适当的表。它为IMO引入了关于next-siblingpanel headingtable内容之间关系的合理假设。然后,这使我们能够基于panel找到标题的正确索引,并使用该索引索引到下一行的table。这减轻了位置不是倒数第二个的情况。然后,您可以寻找进一步的优化。我将匹配项设置为变量以加快引用速度。

多了几行代码,但没有更多的复杂性,尽管有两个循环结构,但在正确的元素上进行匹配时具有更高的安全性,合适的退出策略以及更少的循环(由于定位表)。

总体而言,这是一个不错的策略。我个人认为假设正确的列是倒数第二列,会冒着尝试获得正确表的风险。我采用稍微不同的关系,并动态确定正确的索引。 我对解决方案并不完全满意,但是感觉还不错。


VBA:

tds

参考(VBE>工具>参考):

  1. Microsoft HTML对象库
  2. Microsoft XML v(n)'您的版本