VBA 网页抓取 - 更改日历的日期 [英] VBA web scraping - change date of a calendar
问题描述
我想编写一个从网页自动下载历史股票数据的 vba 程序.选择数据并单击下载按钮已经可以工作了.但我也想更改对我的代码不起作用的日期.
I would like to write a vba Programm which downloads automaticaly historical stock data from a web-page. Selecting the data and click on the download button is already working. But I also would like to change the date what doesn't work with my code.
我想更改日期的元素的相应 HTML 代码,您可以在以下链接中找到:
The correspindent HTML-Code of the Element where I would like to change the date you can find under following link:
我现在使用的代码如下:
The code I'm using now is as follows:
Public Sub MakeChanges()
'VBE > Tools > References > Selenium Type Library
'Download: https://github.com/florentbr/SeleniumBasic/releases/tag/v2.0.9.0
Dim d As WebDriver, t As Date
Set d = New ChromeDriver
Const url = "https://www.dukascopy.com/swiss/english/marketwatch/historical/"
With d
.Start "Chrome"
.get url
.SwitchToFrame .FindElementByCss("script + iframe")
t = Timer
Do
With .FindElementByCss("[data-instrument='EUR/USD']")
.Click
If .Attribute("aria-selected") Then Exit Do
End With
Loop While Timer - t < 10
MsgBox "please login"
'set the date
With .FindElementByCss("a-b-c.a-ab-v-y-x > div")
.FindElementByTag("span").innerText = "2017-01-01"
End With
'end set date
With .FindElementByCss(".d-wh-vg-v-p > div")
If Not .Attribute("aria-disabled") Then .Click
End With
Stop
.Quit
End With
End Sub
非常感谢您的帮助!
推荐答案
请尝试以下操作.它本质上是单击年份和月份的下拉菜单,并通过 itemindex
属性值选择适当的项目.
Try the following. It essentially clicks the dropdowns for year and month and selects the appropriate item by itemindex
attribute value.
在年份的情况下,根据当前显示的内容,所需的年份可能不在下拉列表中.该代码使用 <> 按钮的固定点击次数来确定是否可以找到所需的年份.这个数字可以设置为一个常量,在代码的顶部,如果需要,可以在那里更改.
In the case of year, depending on what is currently displayed, the desired year may not be in the drop down. The code uses a fixed number of clicks of the <> buttons to determine if the desired year can be found. This number could be set as a constant, at the top of the code, and altered there if required.
要选择日期,将循环收集日期,如果找到所需的日期值,则选择它.
To select day, the collection of days is looped, and if the desired day value found then it is selected.
Javascript 用于等待某些元素变为可点击状态,以及用于出现下拉菜单的定时循环.这会根据事件可操作的时间对事件进行计时,以产生预期结果.
Javascript is used to wait for certain elements to become clickable, as well as a timed loop for a drop down to appear. This times events according to when they are actionable in order to yield desired results.
Option Explicit
Public Sub MakeChanges()
'VBE > Tools > References > Selenium Type Library
'Download: https://github.com/florentbr/SeleniumBasic/releases/tag/v2.0.9.0
Const url = "https://www.dukascopy.com/swiss/english/marketwatch/historical/"
Const MAX_WAIT_SEC As Long = 10
Const JS_WAIT_CLICKABLE = _
"var target = this, endtime = Date.now() + arguments[0];" & _
"(function check_clickable() {" & _
" var r = target.getBoundingClientRect(), x = r.left+r.width/2, y = r.top+r.height/2;" & _
" for (var e = document.elementFromPoint(x , y); e; e = e.parentElement)" & _
" if (e === target){ callback(target); return; }" & _
" if (Date.now() > endtime) { callback(target); return; }" & _
" setTimeout(check_clickable, 60);" & _
"})();" 'by @florentbr
Dim d As WebDriver, t As Date
Dim myYear As String, myMonth As String, myDay As String
Set d = New ChromeDriver
myYear = "2017"
myMonth = "January"
myDay = "1"
With d
.start "Chrome"
.get url
.SwitchToFrame .FindElementByCss("script + iframe") '<==switch to frame
'You should add tests for acceptable values e.g. January-December for MonthName, day as appropriate for month
Dim monthIndex As Long, yearIndex As Long, item As Object, dropDown As Object
monthIndex = Month(DateValue("01 " & myMonth & " 2019")) - 1 '<== get month number from name and -1 to get value to use in attribute selector
t = Timer
Do '<== timed loop for month dropdown to be present
On Error Resume Next
Set dropDown = .FindElementByCss(".d-wh-vg-xh span span")
On Error GoTo 0
If Timer - t > MAX_WAIT_SEC Then Exit Do
Loop While dropDown Is Nothing
If dropDown Is Nothing Then Exit Sub
With dropDown '<== wait for drop down to be clickable
.ExecuteAsyncScript(JS_WAIT_CLICKABLE, 3000) _
.Click
End With
With .FindElementByCss(".d-Ch-fi-mi")
.ExecuteAsyncScript(JS_WAIT_CLICKABLE, 3000) _
.Click '<== display month dropdown
End With
.FindElementByCss(".d-Ch-fi-u [itemindex='" & monthIndex & "']").Click '<select month by index
Dim yearIndices As Object, i As Long, j As Long, currentYear As String, z As Long, dayFound As Boolean
currentYear = .FindElementByCss(".d-Ch-fi-ni").Text '<= find currently displayed year
Set yearIndices = CreateObject("Scripting.Dictionary")
For i = CLng(currentYear) - 5 To CLng(currentYear) + 5 '<== gather range of year options in dropdown into
'dictionary where key is year and value is the value required to select in attribute selector
yearIndices(CStr(i)) = CStr(j)
j = j + 1
Next
If yearIndices.Exists(myYear) Then '<check dictionary to see if year desired present
yearIndex = yearIndices(myYear)
.FindElementByCss(".d-Ch-fi-ni").Click '<== display year dropdown
.FindElementByCss("div:nth-child(11) [itemindex='" & yearIndex & "']").Click '<==select year
Else '<== year not present so loop clicking either year add or year subtract to see if desired year does become present
Dim adjustButton As Object
Set adjustButton = IIf(CLng(currentYear) > CLng(myYear),.FindElementByCss("d-Ch-fi-previousYear"), .FindElementByCss("d-Ch-fi-nextYear"))
Do
adjustButton.Click
If z > 15 Then Exit Sub
z = z + 1
Loop Until .FindElementByCss(".d-Ch-fi-ni").Text = myYear
End If
Dim daysList As Object
Set daysList = .FindElementsByCss("div:nth-child(11) td") '<==gather all the days
For Each item In daysList '<==loop days in month until required one found
If item.Text = myDay Then
item.Click
Exit For
End If
Next
Stop
.Quit
End With
End Sub
这篇关于VBA 网页抓取 - 更改日历的日期的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!