VBA 网页抓取 - 更改日历的日期 [英] VBA web scraping - change date of a calendar

查看:22
本文介绍了VBA 网页抓取 - 更改日历的日期的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想编写一个从网页自动下载历史股票数据的 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:

我想更改日期的元素的 HTML 代码

我现在使用的代码如下:

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆