Другие языки программирования и технологии

VBA - Парсинг в Excel-VBA курса ЦБ

Коллеги, посмотрел видео годичной давности по подтягиванию актуального курса в Excel, но теперь код не работает. Не могу понять почему. Функция не сложная, но непонятно почему данные не подтягиваются. Выскакивает ошибка#13 VBA. Ссылку на сайт я поменял. А так.. для проверки вписываем эту функцию в любую ячейку KursCB( "01.01.2017";"USD") для примера и всё должно работать? Прошу себе в VBA вставить и протестить. Возможно что-то устарело по html, но почему-то не получается...

Public Function KursCB(Optional ByVal dtDate, Optional ByVal txtCurr) As Double
Dim query$, otvet$, rate$
Dim oHttp As Object

If IsMissing(dtDate) Then dtDate = Date
On Error Resume Next
If Not IsDate(dtDate) Then dtDate = CDate(dtDate)
If Err.Number <> 0 Then Exit Function
query = "https://www.cbr.ru/currency_base/daily/?UniDbQuery.Posted=True&UniDbQuery.To=" & dtDate
On Error Resume Next
Set oHttp = CreateObject("MSXML.XMLHTTPRequest")
If Err.Number <> 0 Then Set oHttp = CreateObject("MSXML2.XMLHTTP")
On Error GoTo 0
If oHttp Is Nothing Then Exit Function
Call oHttp.Open("GET", query, False)
oHttp.Send
otvet = UCase(oHttp.responseText) ‘// где-то здесь ошибка
rate = CCur(Mid(otvet, InStr(InStr(1, otvet, txtCurr), otvet, "") - 7, 7)) ‘// где-то здесь ошибка

Dim startCurr As Integer
startCurr = InStr(1, otvet, txtCurr, vbTextCompare)
MsgBox startCurr
Set oHttp = Nothing
KursCB = rate
См. рисунки и код, - так работает.

НО! такая технология получения курса не всегда оправдана.
Каждая ячейка екселя делает запрос к сайту CBR.

Получается поток GET-запросов, такая FLOOD-атака на сайт..

Лучше переделать, запрашивать только новые значения,
и накапливать их где-то в хранилище (XML-например).

Тогда обращения должны :
1) вначале идти к XML-хранилищу (всех валют) для минувших дат,
2) для новых дат обращаемся к CBR с параллельной записью в XML.
----------------
Public Function KursCB(Optional dtDate As Variant, Optional txtCurr$ = "USD") As Variant
Const cErr = "Дизайн Html страницы поменяли, этот код теперь не работает!"
Dim s$, otvet$, oHttp As Object
If Not IsDate(dtDate) Then dtDate = Date
If dtDate > Date Then KursCB = "Дата больше текущей! '" & dtDate & "'!": Exit Function
On Error Resume Next
Set oHttp = CreateObject("MSXML2.XMLHTTP")
If Err.Number Then KursCB = "Установите обновление системы с MSXML2!": Exit Function
On Error GoTo eh
s = "https://www.cbr.ru/currency_base/daily/?UniDbQuery.Posted=True&UniDbQuery.To=" & Format(dtDate, "DD.MM.YYYY")
Call oHttp.Open("GET", s, False)
oHttp.Send
On Error GoTo 0
otvet = UCase(oHttp.responseText)
Dim i&, j&
i = InStr(1, otvet, "" & txtCurr & "", vbTextCompare)
If i = 0 Then KursCB = "Не найдена валюта '" & txtCurr & "'!": Exit Function
j = InStr(i, otvet, "")
If j = 0 Then KursCB = cErr: Exit Function
i = InStrRev(otvet, "", j)
If i = 0 Then KursCB = cErr: Exit Function
otvet = Mid(otvet, i + 4, 20)
KursCB = Val(Replace(otvet, ",", "."))
Exit Function
eh:
KursCB = "ошибка в URL!"
End Function
ИБ
Ишемгул Байзигитов
4 442
Лучший ответ
Ишемгул Байзигитов С датой косяк:
If Not IsDate(dtDate) Then dtDate = Date
всегда текущую подставляет
ну если вы парсите html сейчас там таблица по пять столбцов в каждой строке, курс пятый, имя второе
кода не будет, будет словестное описание и ссылки на доки
вам понадобится одна лишняя или ненужная (уже) переменная (далее idxBeg)

в тексте ищем прямым поиском индекс имени курса (уже есть), в том же тексте ищем обратным поиском открывающий тэг строки таблицы начиная с позиции найденой шаг назад, к результату прибавляем 4 и записываем в idxBeg
снова в тексте прямым поиском ищем закрывающий тэг строки таблицы, начиная с idxBeg, от результата отнимаем idxBeg, обрезаем текст начиная с idxBeg, в качестве длины указываем результат последнего поиска, обрезанную строку делим по открывающему ячейку таблицы тэгу, берем нужный элемент (5) и пишем его в rate
в rate прямым поиском ищем закрывающий ячейку таблицы тэг и отнимаем 1, обрезаем rate начиная с 1, в качестве длины указываем результат последнего поиска, обрезанную строку можно скармливать CCur-у

все ссылки на MDN
прямой поиск
обратный поиск
обрезка строки
деление строки
получение значения из массива по индексу: var_array(idx)
Никита Бидуля Да я уже полностью переписал код. Искал информацию везде по немногу.