版本:Microsoft Visual Basic for Applications 7.1
我正在从事小型数据挖掘/网络数据提取个人项目。我的问题是关于数据提取的。
使用IE从网页中提取数据是可行的,但运行速度非常慢,因此,我倾向于使用XML HTTP请求。但是,当我在打算使用的网站上试用时,除了一些静态内容之外,我无法提取所需的数据。检查响应文本后,我发现它不包含我需要的数据。可能是由JavaScript或类似技术生成的。我不确定这些脚本是否像在Web浏览器中一样使用XML HTTP请求在VBA中呈现。
此外,在这里值得注意的是从开发人员工具>网络检查网页时,它提供了一个Request URL,其中响应包含我需要的大多数数据,但它是JSON格式。我不知道如何解析它,但我只是提供了此信息,因此,以防无法使用XML HTTP请求从动态网页提取数据,您可能会指出正确的方向。
我希望您可以花几分钟查看我的代码以及我在哪里可能做错了代码。
非常感谢大家。非常感谢您的帮助。
这是我要做什么的基本概念:
使用XML(无法提取所需的数据):
Option Explicit
Sub dataMinExProject_XML()
Dim xmlPage As MSXML2.XMLHTTP60
Dim htmlDoc As MSHTML.HTMLDocument
Dim coName As MSHTML.IHTMLElement
Dim secSym As MSHTML.IHTMLElement
Dim closePrice As MSHTML.IHTMLElement
Dim URL As String
URL = "https://www.pse.com.ph/stockMarket/companyInfo.html?id=260&security=468&tab=0"
Set xmlPage = New MSXML2.XMLHTTP60
With xmlPage
.Open "POST", URL, False
.send
End With
Do Until xmlPage.ReadyState = 4
DoEvents
Loop
Set htmlDoc = New MSHTML.HTMLDocument
htmlDoc.body.innerHTML = xmlPage.responseText
Set coName = htmlDoc.getElementById("comTopInfoHead").Children(0)
Set secSym = htmlDoc.getElementById("secSymbol")
Set closePrice = htmlDoc.getElementById("headerLastTradePrice")
Debug.Print "Company Name: ", """" & coName.innerText & """"
Debug.Print "Security Symbol: ", """" & secSym.innerText & """"
Debug.Print "Closing Price: ", """" & closePrice.innerText & """"
xmlPage.abort
Set xmlPage = Nothing
MsgBox ("alright!")
End Sub
Immediate Window
Company Name: "BDO Unibank, Inc."
Security Symbol: ""
Closing Price: " "
检查立即窗口后,显示Security Symbol
和Closing Price
未被提取。
为了进行比较,并为了证明要提取的数据存在,我在这里还提供了使用IE实例的代码。
使用IE(提取了数据,但运行速度相对较慢):
Option Explicit
Sub dataMinExProject_IE()
Dim ieApp As SHDocVw.InternetExplorer
Dim htmlDoc As MSHTML.HTMLDocument
Dim coName As MSHTML.IHTMLElement
Dim secSym As MSHTML.IHTMLElement
Dim closePrice As MSHTML.IHTMLElement
Dim URL As String
URL = "https://www.pse.com.ph/stockMarket/companyInfo.html?id=260&security=468&tab=0"
Set ieApp = New SHDocVw.InternetExplorer
With ieApp
.Navigate (URL)
.Visible = vbTrue
End With
Do Until ieApp.ReadyState = READYSTATE_COMPLETE
DoEvents
Loop
Set htmlDoc = ieApp.Document
Set coName = htmlDoc.getElementById("comTopInfoHead").Children(0)
Set secSym = htmlDoc.getElementById("secSymbol")
Set closePrice = htmlDoc.getElementById("headerLastTradePrice")
Do Until secSym.innerText <> vbNullString And closePrice.innerText <> vbNullString
Loop
DoEvents
Debug.Print "Company Name: ", """" & coName.innerText & """"
Debug.Print "Security Symbol: ", """" & secSym.innerText & """"
Debug.Print "Closing Price: ", """" & closePrice.innerText & """"
ieApp.Quit
Set ieApp = Nothing
MsgBox ("alright!")
End Sub
Immediate Window
Company Name: "BDO Unibank, Inc."
Security Symbol: "BDO"
Closing Price: "130.50"
查看立即窗口,它表明已成功提取数据。但是,正如我之前所说的那样,它的糟糕表现使我不得不考虑其他选择。
参考文献:
答案 0 :(得分:0)
处理HTTP请求是一种方法。如您所说,IE浏览器运行缓慢且效率低下。
找到响应后返回感兴趣的数据的请求后,您的工作就相对容易了,并且很可能涉及以下其中一项:
Microsoft HTML Object Library
,将响应HTML分配给HTMLDocument
,然后使用现有方法解析对象。为此,您需要引用Microsoft HTML Object Library
。JSON
字符串。在这种情况下,您可以将响应存储在字符串变量中,然后使用VBA JSON将其解析为json对象。链接中给出的说明和示例非常有用。使用在线JSON查看器了解响应的结构,您将能够提取所需的任何信息。为此,您当然需要引用Microsoft Scripting Runtime
以及VBA JSON
模块。就请求本身而言,请确保使用对请求必不可少的标头。标头Content-Type:
是其中之一,它对于POST
请求是必不可少的。您可以使用.setRequestHeader
方法。包含请求参数的请求正文也很重要。我建议您使用WinHTTP Services, version 5.1
进行请求。
一旦掌握了这些知识,就可以完全控制要检索的数据。
答案 1 :(得分:0)
有一组APIs。目前,Stock API端点似乎无法正常工作。我提出了一个问题。如果它可以再次工作,则可以使用以下语法。 json解析器为jsonconverter.bas。您将.bas添加到您的项目中,然后转到VBE>工具>参考>添加对Microsoft Scripting运行时的引用
Option Explicit
Public Sub dataMinExProject_XML()
Dim xmlPage As MSXML2.XMLHTTP60, aDate As String, symbol As String, json As Object, url As String
Set xmlPage = New MSXML2.XMLHTTP60
aDate = Format$(Date - 1, "MM-DD-YYYY")
symbol = "JFC"
url = "http://pseapi.com/api/Stock/" & symbol & "/" & aDate
With xmlPage
.Open "GET", url, False
.send
Set json = JsonConverter.ParseJson(.responseText)
End With
End Sub
它返回一个字典对象,您可以通过按键解析信息
{
"symbol":"JFC",
"date":"15/03/2017",
"open":197.0000,
"high":197.4000,
"low":195.0000,
"close":196.0000,
"bid":195.5000,
"ask":196.0000,
"volume":141740,
"value":27747934.0000,
"netForeign":-6464136.0000
}
因此,以我的示例为例:
Dim key As Variant
For Each key In json.keys
Debug.Print key, json(key)
Next