使用vba从网站上搜索数据

时间:2014-11-21 17:25:20

标签: vba excel-vba web-scraping excel

我试图从网站上抓取数据:http://uk.investing.com/rates-bonds/financial-futures通过vba,就像实时价格一样,即德国5 YR Bobl,美国30Y T-Bond,我尝试过excel网页查询,但它只搜索整个网站,但我只想提高利率,有没有办法做到这一点?

5 个答案:

答案 0 :(得分:67)

有几种方法可以做到这一点。这是我写的一个答案,希望在浏览关键词“从网站抓取数据”时可以找到Internet Explorer自动化的所有基础知识,但请记住,没有什么值得作为您自己的研究(如果您不想坚持您无法自定义的预编码。

请注意,这是单向,我不喜欢性能(因为它取决于浏览器速度),但这很好理解互联网自动化的基本原理。< / p>

1)如果我需要浏览网页,我需要一个浏览器!所以我创建了一个Internet Explorer浏览器:

Dim appIE As Object
Set appIE = CreateObject("internetexplorer.application")

2)我要求浏览器浏览目标网页。通过使用属性“.Visible”,我决定是否要查看浏览器是否正在执行其工作。在构建代码时很高兴有Visible = True,但是当代码用于抓取数据时,不要每次都看到它Visible = False

With appIE
    .Navigate "http://uk.investing.com/rates-bonds/financial-futures"
    .Visible = True
End With

3)网页需要一些时间来加载。所以,我会等着它忙...

Do While appIE.Busy
    DoEvents
Loop

4)好了,现在页面已加载。让我们说我想要刮掉US30Y T-Bond的变化: 我要做的就是在Internet Explorer上单击F12以查看网页的代码,因此使用指针(在红色圆圈中)我将点击我想要抓取的元素,看看我如何达到我的目的。

enter image description here

5)我应该做的是直截了当。首先,我将通过ID属性获取包含值<{p>>的tr元素

Set allRowOfData = appIE.document.getElementById("pair_8907")

在这里,我将获得td个元素的集合(具体来说,tr是一行数据,td是它的单元格。我们正在寻找第8个,所以我会写:

Dim myValue As String: myValue = allRowOfData.Cells(7).innerHTML

为什么我写7而不是8?因为单元格集合从0开始,所以第8个元素的索引是7(8-1)。简要分析这行代码:

  • .Cells()让我访问td元素;
  • innerHTML是包含我们查找的值的单元格的属性。

一旦我们获得了现在存储在myValue变量中的值,我们就可以关闭IE浏览器并通过将其设置为Nothing来释放内存:

appIE.Quit
Set appIE = Nothing

好吧,现在你有了自己的价值,你可以用它做任何你想做的事情:把它放进一个单元格(Range("A1").Value = myValue),或者放到一个表格的标签(Me.label1.Text = myValue)。

我只想指出,这不是StackOverflow的工作原理:在这里您发布有关特定编码问题的问题,但您应首先进行自己的搜索。我之所以回答一个没有展示太多研究成果的问题,只是因为我看到它多次询问,回到我学习如何做到这一点的时候,我记得我本来希望有一些更好的支持入门。所以我希望这个答案只是一个“学习输入”而不是最好/最完整的解决方案,可以为下一个遇到同样问题的用户提供支持。因为我已经学会了如何编程感谢这个社区,我想你和其他初学者可能会使用我的输入来发现编程的美丽世界。

享受你的练习;)

答案 1 :(得分:5)

提到了其他方法,因此让我们请您承认,在撰写本文时,我们处于21世纪。让我们停放 local bus 浏览器打开的窗口,并通过一个XMLHTTP GET请求(简称XHR GET) fly

Wiki moment:

  

XHR是对象形式的API,其方法可以传输数据   在Web浏览器和Web服务器之间。该对象由   浏览器的JavaScript环境

这是一种无需打开浏览器即可检索数据的快速方法。可以将服务器响应读取到HTMLDocument中,并从那里继续获取表。

在下面的代码中,表的ID为cr1

table

在帮助子WriteTable中,我们先循环各列(td标签),然后再循环表行(tr标签),最后遍历每个表行的长度,表格单元格。因为我们只想要第1列和第8列中的数据,所以使用Select Case语句指定要写到工作表的内容。


示例网页视图:

Sample page view


示例代码输出:

Code output


VBA:

Option Explicit
Public Sub GetRates()
    Dim sResponse As String, html As New HTMLDocument '<== Tools > References > HTML Object Library
    Dim hTable As HTMLTable
    Application.ScreenUpdating = False
    With CreateObject("MSXML2.XMLHTTP")
        .Open "GET", "https://uk.investing.com/rates-bonds/financial-futures", False
        .setRequestHeader "If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT" 
        .send
        sResponse = StrConv(.responseBody, vbUnicode)
    End With
    sResponse = Mid$(sResponse, InStr(1, sResponse, "<!DOCTYPE "))
    With html
        .body.innerHTML = sResponse
        Set hTable = .getElementById("cr1")
        WriteTable hTable, 1, ThisWorkbook.Worksheets("Sheet1")
    End With
    Application.ScreenUpdating = True
End Sub

Public Sub WriteTable(ByVal hTable As HTMLTable, Optional ByVal startRow As Long = 1, Optional ByVal ws As Worksheet)
    Dim tSection As Object, tRow As Object, tCell As Object, tr As Object, td As Object, r As Long, C As Long, tBody As Object
    r = startRow: If ws Is Nothing Then Set ws = ActiveSheet
    With ws
        Dim headers As Object, header As Object, columnCounter As Long
        Set headers = hTable.getElementsByTagName("th")
        For Each header In headers
            columnCounter = columnCounter + 1
            Select Case columnCounter
            Case 2
                .Cells(startRow, 1) = header.innerText
            Case 8
                .Cells(startRow, 2) = header.innerText
            End Select
        Next header
        startRow = startRow + 1
        Set tBody = hTable.getElementsByTagName("tbody")
        For Each tSection In tBody
            Set tRow = tSection.getElementsByTagName("tr")
            For Each tr In tRow
                r = r + 1
                Set tCell = tr.getElementsByTagName("td")
                C = 1
                For Each td In tCell
                    Select Case C
                    Case 2
                        .Cells(r, 1).Value = td.innerText
                    Case 8
                        .Cells(r, 2).Value = td.innerText
                    End Select
                    C = C + 1
                Next td
            Next tr
        Next tSection
    End With
End Sub

答案 2 :(得分:1)

您可以使用winhttprequest对象而不是Internet Explorer,因为它可以加载除了图片广告之外的数据,而不是下载包含广告n图片的完整网页,这些图片使得互联网浏览器对象比winhttpRequest对象更重要。

答案 3 :(得分:0)

很久以前就提出过这个问题。但我认为以下信息对新手有用。实际上,您可以轻松地从类名中获取值。

Sub ExtractLastValue()

Set objIE = CreateObject("InternetExplorer.Application")

objIE.Top = 0
objIE.Left = 0
objIE.Width = 800
objIE.Height = 600

objIE.Visible = True

objIE.Navigate ("https://uk.investing.com/rates-bonds/financial-futures/")

Do
DoEvents
Loop Until objIE.readystate = 4

MsgBox objIE.document.getElementsByClassName("pid-8907-last")(0).innerText

End Sub

如果您不熟悉网页抓取,请阅读此博文。

Web Scraping - Basics

还有各种从网页中提取数据的技术。本文通过示例解释其中的一些。

Web Scraping - Collecting Data From a Webpage

答案 4 :(得分:0)

我修改了一些为我弹出错误的东西,并最终得到了这个,以便根据需要提取数据:

Sub get_data_web()

Dim appIE As Object
Set appIE = CreateObject("internetexplorer.application")

With appIE
    .navigate "https://finance.yahoo.com/quote/NQ%3DF/futures?p=NQ%3DF"
    .Visible = True
End With

Do While appIE.Busy
    DoEvents
Loop

Set allRowofData = appIE.document.getElementsByClassName("Ta(end) BdT Bdc($c-fuji-grey-c) H(36px)")

Dim i As Long
Dim myValue As String

Count = 1

    For Each itm In allRowofData

        For i = 0 To 4

        myValue = itm.Cells(i).innerText
        ActiveSheet.Cells(Count, i + 1).Value = myValue

        Next

        Count = Count + 1

    Next

appIE.Quit
Set appIE = Nothing


End Sub