Excel createobject msxml2 xmlhttp

Excel is a powerful and most popular tool for data analysis! HTTP requests in VBA gives additional capabilities to Excel. XmlHttpRequest object is used to make HTTP requests in VBA. HTTP requests can be used to interact with a web service, API or even websites. Let’s understand how it works.

xmlhttprequest in excel vba

Open an excel file and open VBA editor (Alt + f11) > new module and start writing code in a sub

Public sub XmlHttpTutorial

End Sub

Define XMLHttpRequest

Define http client using following code

Dim xmlhttp as object
Set xmlhttp = CreateObject("MSXML2.serverXMLHTTP")

If you need VBA’s Intellisense autocomplete then do it this way :

First, Add a reference to MSXML (Tools > references)

Select appropriate version based on your PC :
1. Microsoft XML, v 3.0.
2. Microsoft XML, v 4.0 (if you have installed MSXML 4.0 separately).
3. Microsoft XML, v 5.0 (if you have installed Office 2003 – 2007 which provides MSXML 5.0 for Microsoft Office Applications).
4. Microsoft XML, v 6.0 for latest versions of MS Office.

Then define http client

Dim xmlhttp As New MSXML2.XMLHTTP
'Dim xmlhttp As New MSXML2.XMLHTTP60 for Microsoft XML, v 6.0 

VBA Intellisense will show you the right one when you start typing.

Make requests

Requests can be made using open and send methods. Open method syntax is as follows :

xmlhttp.Open Method, URL, async(true or false)

I’m using requestBin to test requests. Create a bin there and send requests to that URL to test requests.

A simple GET request would be :

Dim xmlhttp As New MSXML2.XMLHTTP60, myurl As String
myurl = "http://requestb.in/15oxrjh1" //replace with your URL
xmlhttp.Open "GET", myurl, False
xmlhttp.Send
MsgBox(xmlhttp.responseText)

Run this code, a message box is displayed with the response of the request.

Request headers

Request headers can be set using setRequestHeader method. Examples :

xmlhttp.setRequestHeader "Content-Type", "text/json"
xmlhttp.setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
xmlhttp.setRequestHeader "User-Agent", "Mozilla/5.0 (iPad; U; CPU OS 3_2_1 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Mobile/7B405"
xmlhttp.setRequestHeader "Authorization", AuthCredentials

Simple POST request to send formdata

POST requests are used to send some data, data can be sent in Send method. A simple POST request to send form data :

Public Sub httpclient()
Dim xmlhttp As New MSXML2.XMLHTTP, myurl As String
myurl = "http://requestb.in/15oxrjh1"
xmlhttp.Open "POST", myurl, False
xmlhttp.setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
xmlhttp.Send "name=codingislove&[email protected]"
MsgBox (xmlhttp.responseText)
End Sub

Basic Authentication in VBA

When we need to access web services with basic authentication, A username and password have to be sent with the Authorization header. Username and password should also be base64 encoded. Example :

user = "someusername"
password = "somepassword"
xmlhttp.setRequestHeader "Authorization", "Basic " + Base64Encode(user + ":" + password)

Here’s a paste of utility function that helps to encode string to Base64

Practical use cases

Practical use cases of http requests in VBA are unlimited. Some of them are pulling data from Yahoo finance API, weather API, pulling orders from Ecommerce store admin panel, uploading products, retrieving web form data to excel etc.

Read : Parse HTML in Excel VBA – Learn by parsing hacker news home page where I retrieve a web page using HTTP GET request and parse its HTML to get data from a web page.

Read How to build a simple weather app in Excel VBA where I make a HTTP Get request to weather API

Read JSON Api in Excel VBA where I call JSON Apis using HTTP GET and POST requests.

If you have and questions or feedback, comment below.

  • Author
  • Recent Posts

A CA- by education, self taught coder by passion, loves to explore new technologies and believes in learn by doing.

Уровень сложности
Средний

Время на прочтение
9 мин

Количество просмотров 14K

Работая в IoT-сфере и плотно взаимодействуя с одним из основных элементов данной концепции технологий – сетевым сервером, столкнулся вот с какой проблемой (задачей): необходимо отправлять много запросов для работы с умными устройствами на сетевой сервер. На сервере был реализован REST API с оболочкой Swagger UI, где из графической оболочки можно было отправлять только разовые запросы. Анализ сторонних клиентов, типа Postman или Insomnia показал, что простого визуального способа поместить в скрипт массив из необходимого перечня идентификаторов устройств (или любых других элементов сервера), для обращения к ним – не нашлось.

Так как большая часть работы с выгрузками и данными была в Excel, то решено было вспомнить навыки, полученные на учебе в университете, и написать скрипт на VBA, который бы мою задачку решал.

Необходимо было:

  • получать информацию по устройствам с различными параметрами фильтрации (GET);

  • применять изменения в конфигурации по устройствам: имя, профиль устройства, сетевые лицензии и пр. (PUT);

  • отправлять данные для конфигурации и взаимодействия с устройствами (POST).

И сегодня я расскажу вам про то, как с помощью Excel, пары формул и самописных функций на VBA можно реализовать алгоритм, отправляющий любое необходимое количество REST-API запросов с использованием авторизации Bearer Token.

Данная статья будет полезная тем, кто воспользуется данным решением под Windows, но еще больше она будет полезна тем людям, которые хотят использовать данное решение на MacOS (с Excel x64) . Как вы уже догадались, ниже будут рассмотрены два варианта реализации под разные системы, так как с MacOS есть нюанс.


Часть 1. Реализация решения под Windows

GET

Начнем с самого простого: GET – запросов. В данном примере необходимо получить ответ (информацию) от сервера по заданному списку устройств.

Для реализации GET – запросов нам дано:

1)   Ссылка, в которой указываются параметры запроса. 

https://dx-api.thingpark.io/core/latest/api/devices?deviceEUI=

2)   Заголовки запроса + Токен авторизации (Bearer Token)

—header ‘Accept: application/json’ —header ‘Authorization: Bearer

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzY29wZSI6WyJTVUJTQ1JJQkVSOjY3MDAiXSwiZXhwIjozNzc0MTY0MzE4LCJqdGkiOiI5OTNiOTk1Ny03NGY1LTQ5MDgtYjg4Ni0xYjk5NTVkZDQwZTEiLCJjbGllbnRfaWQiOiJkZXYxLWFwaS9lcnRoLnRlY2guZGVzayt2bGFkaXNsYXYuZ2F0Y2Vua29AZ21haWwuY29tIn0.dqybsMdVXXpQV8_ykufNZoQpSPZrVA67uieOJan-qs8W7rAImyy0552buniHXPWy6ilvdwJKPCdIKE__LghP6A

3)   Параметр, указываемый в ссылке (в данном примере это идентификаторы устройств – DevEUI):

1ABCDEFF00AABBCC

0016ACC4DCF15A23

D88039FFFE954DF4

0000000000001103

0000000000001104

Имея такие данные на входе, делаем в Excel лист-шаблон, который заполняем в соответствии с тем, что имеем:

  • столбец А уходит вот значения параметров

  • столбец F уходит под ссылку-родителя

  • столбец H уходит под заголовки, где в ячейке H1 единоразово для текущего листа указывается токен:

=СЦЕП("--header 'Accept: application/json' --header 'Authorization: Bearer ";$H$1;"'")

  • столбец I уходит под URL (ссылки-дети, на основе ссылки-родителя)

=СЦЕПИТЬ($F$1;A2)

  • столбец J уходит под результат (ответ от сервера)

Шаблон листа для GET-запросов

Шаблон листа для GET-запросов

Далее, нам необходимо реализовать подпрограмму(макрос) отправки GET-запросов. Состоит она из четырех частей:

  1. цикла, который считает количество строк для работы по листу, пробегая по столбцу А с 2 по первую пустую ячейку, чтобы у цикла был конец.

  2. функции, для работы с REST API (используется стандартная, библиотека Msxml2.XMLHTTP.6.0, встроенная в Windows., поэтому сложностей с реализацией не возникает. Для MacOS есть альтернатива)

  3. временной задержки, в случае если нужно отправлять запросы не сразу, после получения ответа, а задав время ожидания

  4. таймером, который показывает время выполнения всего макроса после завершения

    Код:

    Sub GET_Request()
    
    Dim i As Integer
    Dim j As Integer
    Dim objHTTP As Object
    Dim Json As String
    Dim result As String
    Dim URL As String
    Dim Token As String
    a = Timer
    
        i = 1
            Do While Not IsEmpty(Cells(i, 1))
            i = i + 1
            Loop
        i = i - 1
        'MsgBox i
    
        For j = 2 To i
            Json = Range("D" & j)
            URL = Range("I" & j)
            Token = Range("H1")
    
            Set objHTTP = CreateObject("Msxml2.XMLHTTP.6.0")
                objHTTP.Open "GET", URL, False
                objHTTP.setRequestHeader "Content-type", "application/json"
                objHTTP.setRequestHeader "Accept", "application/json"
                objHTTP.setRequestHeader "Authorization", "Bearer " + Token
                objHTTP.Send (Json)
                result = objHTTP.responseText
                Range("J" & j).Value = result
            Set objHTTP = Nothing
            'Application.Wait (Now + TimeValue("0:00:01"))
        Next j
    
    MsgBox Timer - a
    
    End Sub
    

Привязываем подпрограмму к кнопкам для удобства и выполним скрипт. Получается: 

Таким образом, скрипт проходит по столбцу I, забирая из значения каждой ячейки URL, для тех строк, где в столбце А есть значения (которые и подставляются в URL). Для удобства также сделаны кнопки очистки полей и подсветка запросов условным форматированием, в случае успешного ответа на запрос.

PUT

Чуть-чуть усложним задачу и перейдем к PUT-запросам. В данном примере необходимо изменить профиль устройства, чтобы сервер по-другому с ним взаимодействовал.

К исходным данным для GET – запроса добавляется тело запроса с ключем-значением (п4). Итого дано:

1)   Ссылка, в которой указываются параметры запроса.

https://dx-api.thingpark.io/core/latest/api/devices/

2)   Заголовки запроса + Токен авторизации (Bearer Token)

—header ‘Content-Type: application/json’ —header ‘Accept: application/json’ —header ‘Authorization: Bearer

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzY29wZSI6WyJTVUJTQ1JJQkVSOjY3MDAiXSwiZXhwIjozNzc0MTY0MzE4LCJqdGkiOiI5OTNiOTk1Ny03NGY1LTQ5MDgtYjg4Ni0xYjk5NTVkZDQwZTEiLCJjbGllbnRfaWQiOiJkZXYxLWFwaS9lcnRoLnRlY2guZGVzayt2bGFkaXNsYXYuZ2F0Y2Vua29AZ21haWwuY29tIn0.dqybsMdVXXpQV8_ykufNZoQpSPZrVA67uieOJan-qs8W7rAImyy0552buniHXPWy6ilvdwJKPCdIKE__LghP6A

3)   Параметр, указываемый в ссылке (в данном примере это внутренние идентификаторы устройств – hRef):

17272

18199

17242

17245

17248

4)   Тело запроса, с ключом и значением:

{«deviceProfileId»:»LORA/GenericA.1.0.3a_ETSI»}

Немного дополняем новый PUT-лист в Excel по сравнению с GET (остальное без изменений):

  • новый столбец B теперь отвечает за ключ deviceProfileId (ячейка B1), а все значения ниже за его возможные значения)

  • столбец D отвечает за формирование итогового тела сообщения в формате JSON.

=СЦЕПИТЬ("'{""";$B$1;""":""";B2;"""";"}'")

Немного поменяем макрос и вынесем его в отдельную подпрограмму: 

Код:

Sub PUT_Request()

Dim i As Integer
Dim j As Integer
Dim objHTTP As Object
Dim Json As String
Dim result As String
Dim URL As String
Dim Token As String
a = Timer

    i = 1
        Do While Not IsEmpty(Cells(i, 1))
        i = i + 1
        Loop
    i = i - 1
    'MsgBox i

    For j = 2 To i
        Json = Range("D" & j)
        URL = Range("I" & j)
        Token = Range("H1")

        Set objHTTP = CreateObject("Msxml2.XMLHTTP.6.0")
            objHTTP.Open "PUT", URL, False
            objHTTP.setRequestHeader "Content-type", "application/json"
            objHTTP.setRequestHeader "Accept", "application/json"
            objHTTP.setRequestHeader "Authorization", "Bearer " + Token
            objHTTP.Send (Json)
            result = objHTTP.responseText
            Range("J" & j).Value = result
        Set objHTTP = Nothing
        'Application.Wait (Now + TimeValue("0:00:01"))
    Next j

MsgBox Timer - a

End Sub

Привяжем макрос к кнопке и выполним. 

Логика абсолютно аналогична GET запросу.

POST

Для POST запросов все аналогично PUT. Только немного меняется код в части типа запроса. В данном примере на устройство отправляется команда-конфигурация с указанием тела посылки (payload_hex) и порта (fport) для конкретного устройства. 

Код:

Sub PUT_Request()

Dim i As Integer
Dim j As Integer
Dim objHTTP As Object
Dim Json As String
Dim result As String
Dim URL As String
Dim Token As String
a = Timer

    i = 1
        Do While Not IsEmpty(Cells(i, 1))
        i = i + 1
        Loop
    i = i - 1
    'MsgBox i

    For j = 2 To i
        Json = Range("D" & j)
        URL = Range("I" & j)
        Token = Range("H1")

        Set objHTTP = CreateObject("Msxml2.XMLHTTP.6.0")
            objHTTP.Open "PUT", URL, False
            objHTTP.setRequestHeader "Content-type", "application/json"
            objHTTP.setRequestHeader "Accept", "application/json"
            objHTTP.setRequestHeader "Authorization", "Bearer " + Token
            objHTTP.Send (Json)
            result = objHTTP.responseText
            Range("J" & j).Value = result
        Set objHTTP = Nothing
        'Application.Wait (Now + TimeValue("0:00:01"))
    Next j

MsgBox Timer - a

End Sub

Получившаяся таблица выглядит следующим образом:

 На этом часть для Windows заканчивается. Здесь все оказалось довольно просто: стандартная библиотека, простенький алгоритм перебора значений в цикле. 


Часть 2. Реализация решения под MacOS и Excel 64-bit

В виду того, что работал я на двух машинах под управлением разных ОС, хотелось, чтобы решение было универсальным. В итоге, собрав по крупицам информацию по интернет-форумам с данной тематикой у меня вышло следующее решение. Принцип работы его остается схожим, а изменения были внесены в часть, где использовалась стандартная библиотека WindowsMsxml2.XMLHTTP.6.0, которой в MacOS не было по понятным причинам. 

Чтобы обойти данное ограничение, был выбран единственный рабочий подход через cUrl, exec и функции. Данное решение точно работает под версией MacOS 10.14 и Excel 16.51. Функция ниже, в том или ином виде, встречается на различных форумах, однако на текущих версиях софта – не работает. В итоге, после небольших правок получили рабочий вариант:

 Была отлажена функция вызова ExecShell:

Код:

Option Explicit
Private Declare PtrSafe Function popen Lib "/usr/lib/libc.dylib" (ByVal Command As String, ByVal Mode As String) As LongPtr
Private Declare PtrSafe Function pclose Lib "/usr/lib/libc.dylib" (ByVal file As LongPtr) As Long
Private Declare PtrSafe Function fread Lib "/usr/lib/libc.dylib" (ByVal outStr As String, ByVal size As LongPtr, ByVal items As LongPtr, ByVal stream As LongPtr) As Long
Private Declare PtrSafe Function feof Lib "/usr/lib/libc.dylib" (ByVal file As LongPtr) As LongPtr

Function execShell(Command As String, Optional ByRef exitCode As Long) As String
    Dim file As LongPtr
    file = popen(Command, "r")

    If file = 0 Then
        Exit Function
    End If

    While feof(file) = 0
        Dim chunk As String
        Dim read As Long
        chunk = Space(500)
        read = fread(chunk, 1, Len(chunk) - 1, file)
        If read > 0 Then
            chunk = Left$(chunk, read)
            execShell = execShell & chunk
        End If
    Wend

    exitCode = pclose(file)
    
End Function

И написаны отдельные функции для работы с различным методами GET / PUT / POST, которые на входе принимают URL и параметры):

Код:

Function HTTPGet(sUrl As String, sQuery As String) As String

    Dim sCmd As String
    Dim sResult As String
    Dim lExitCode As Long

    sCmd = "curl -X GET " & sQuery & "" & " " & sUrl
    sResult = execShell(sCmd, lExitCode)
    HTTPGet = sResult

End Function

Function HTTPPost(sUrl As String, sQuery1 As String, sQuery2 As String) As String

    Dim sCmd As String
    Dim sResult As String
    Dim lExitCode As Long

    sCmd = "curl -X POST " & sQuery1 & "" & " -d " & sQuery2 & "" & " " & sUrl
    sResult = execShell(sCmd, lExitCode)
    HTTPPost = sResult

End Function

Function HTTPPut(sUrl As String, sQuery1 As String, sQuery2 As String) As String

    Dim sCmd As String
    Dim sResult As String
    Dim lExitCode As Long

    sCmd = "curl -X PUT " & sQuery1 & "" & " -d " & sQuery2 & "" & " " & sUrl
    sResult = execShell(sCmd, lExitCode)
    HTTPPut = sResult

End Function

Так как мы заменяем библиотеку Msxml2.XMLHTTP.6.0 – поменялась реализация макросов в этой части: мы заменили Msxml2 на написанные выше функции и получили следующее:

Код:

'GET-запросы
Sub SendGETRequest()

Dim i As Integer
Dim j As Integer
Dim result As String
Dim URL As String
Dim Auth As String

a = Timer

    'Подсчет заполненных ячеек первого столбца
    i = 1
        Do While Not IsEmpty(Cells(i, 1))
        i = i + 1
        Loop
    i = i - 1

    'Цикл, который отправляет запрос от 2 до последнего элемента
    For j = 2 To i
        URL = Range("I" & j)
        Auth = Range("H" & j)
        result = HTTPGet(URL, Auth)
        Range("J" & j).Value = result
        'Application.Wait (Now + TimeValue("0:00:01"))
    Next j

MsgBox Timer - a

End Sub


'PUT-запросы
Sub SendPUTRequest()

Dim i As Integer
Dim j As Integer
Dim result As String
Dim URL As String
Dim Auth As String
Dim Message As String


a = Timer

    'Подсчет заполненных ячеек первого столбца
    i = 1
        Do While Not IsEmpty(Cells(i, 1))
        i = i + 1
        Loop
    i = i - 1

    'Цикл, который отправляет запрос от 2 до последнего элемента
    For j = 2 To i
        Message = Range("D" & j)
        URL = Range("I" & j)
        Auth = Range("H" & j)
        result = HTTPPut(URL, Auth, Message)
        Range("J" & j).Value = result
        'Application.Wait (Now + TimeValue("0:00:01"))
    Next j

MsgBox Timer - a

End Sub


'POST-запросы
Sub SendPOSTRequest()

Dim i As Integer
Dim j As Integer
Dim result As String
Dim URL As String
Dim Auth As String
Dim Message As String

a = Timer

    'Подсчет заполненных ячеек первого столбца
    i = 1
        Do While Not IsEmpty(Cells(i, 1))
        i = i + 1
        Loop
    i = i - 1

    'Цикл, который отправляет запрос от 2 до последнего элемента
    For j = 2 To i
        Message = Range("D" & j)
        URL = Range("I" & j)
        Auth = Range("H" & j)
        result = HTTPPost(URL, Auth, Message)
        Range("J" & j).Value = result
        'Application.Wait (Now + TimeValue("0:00:01"))
    Next j

MsgBox Timer – a

Итог

В итоге, у меня получилось аналогичное windows по работе и функционалу решение для MacOS c использованием Excel 64-bit. 

На просторах интернета я не нашел какого-то сборного и единого описания, только фрагменты кода и подходов, которые в большинстве случаев не работали полностью или частично. Поэтому решил объединить все в рабочее решение и выложить на хабр для истории. 

На текущий момент я все еще не встретил иного решения, которое бы позволяло в пару кликов копипастить тысячи идентификаторов и параметров из excel и массово их отправлять на сервер. Надеюсь, кому-то пригодится  :)

Если такие сторонние решения есть, а я не в курсе, и все можно было сделать проще, быстрее и изящнее – делитесь опытом в комментариях.

Примечание:

Файл-пример, который можно потыкать, пока жив сервер и «бессрочный» токен: 

https://disk.yandex.ru/d/y7EVtn8afM4QPg

Открытое описание API, если кому-то будет любопытно

Пользовательские функции VBA Excel для парсинга сайтов, html-страниц и файлов, возвращающие их текстовое содержимое. Примеры записи текста в переменную.

Парсинг html-страниц (msxml2.xmlhttp)

Пользовательская функция GetHTML1 (VBA Excel) для извлечения (парсинга) текстового содержимого из html-страницы сайта по ее URL-адресу с помощью объекта «msxml2.xmlhttp»:

Function GetHTML1(ByVal myURL As String) As String

On Error Resume Next

    With CreateObject(«msxml2.xmlhttp»)

        .Open «GET», myURL, False

        .send

        Do: DoEvents: Loop Until .readyState = 4

        GetHTML1 = .responseText

    End With

End Function

Парсинг сайтов (WinHttp.WinHttpRequest.5.1)

Пользовательская функция GetHTML2 (VBA Excel) для извлечения (парсинга) текстового содержимого из html-страницы сайта по ее URL-адресу с помощью объекта «WinHttp.WinHttpRequest.5.1»:

Function GetHTML2(ByVal myURL As String) As String

On Error Resume Next

    With CreateObject(«WinHttp.WinHttpRequest.5.1»)

        .Open «GET», myURL, False

        .send

        Do: DoEvents: Loop Until .readyState = 4

        GetHTML2 = .responseText

    End With

End Function

Парсинг файлов (ADODB.Stream)

Пользовательская функция GetText (VBA Excel) для извлечения (парсинга) текстового содержимого из файла (.txt, .csv, .mhtml), сохраненного на диск компьютера, по его полному имени (адресу) с помощью объекта «ADODB.Stream»:

Function GetText(ByVal myFile As String) As String

On Error Resume Next

    With CreateObject(«ADODB.Stream»)

        .Charset = «utf-8»

        .Open

        .LoadFromFile myFile

        GetText = .ReadText

        .Close

    End With

End Function

Примеры записи текста в переменную

Общая формула записи текста, извлеченного с помощью пользовательских функций VBA Excel, в переменную:

Dim htmlText As String

htmlText = GetHTML1(«Адрес сайта (html-страницы)»)

htmlText = GetHTML2(«Адрес сайта (html-страницы)»)

htmlText = GetText(«Полное имя файла»)

Конкретные примеры:

htmlText = GetHTML1(«https://internettovary.ru/nabor-dlya-vyrashchivaniya-veshenki/»)

htmlText = GetHTML2(«https://internettovary.ru/nabor-dlya-vyrashchivaniya-veshenki/»)

htmlText = GetText(«C:UsersEvgeniyDownloadsНовый текстовый документ.txt»)

htmlText = GetText(«C:UsersEvgeniyDownloadsИспользование msxml2.xmlhttp в Excel VBA.mhtml»)

В понятие «парсинг», кроме извлечения текстового содержимого сайтов, html-страниц или файлов, входит поиск и извлечение конкретных данных из всего полученного текстового содержимого.

Пример извлечения email-адресов из текста, присвоенного переменной, смотрите в последнем параграфе статьи: Регулярные выражения (объекты, свойства, методы).

Парсинг содержимого тегов

Извлечение содержимого тегов с помощью метода getElementsByTagName объекта HTMLFile:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

Sub Primer1()

Dim myHtml As String, myFile As Object, myTag As Object, myTxt As String

    ‘Извлекаем содержимое html-страницы в переменную myHtml с помощью функции GetHTML1

    myHtml = GetHTML1(«https://internettovary.ru/sadovaya-nozhovka-sinitsa/»)

    ‘Создаем объект HTMLFile

    Set myFile = CreateObject(«HTMLFile»)

    ‘Записываем в myFile текст из myHtml

    myFile.body.innerHTML = myHtml

    ‘Присваиваем переменной myTag коллекцию одноименных тегов, имя которого

    ‘указанно в качестве аргумента метода getElementsByTagName

    Set myTag = myFile.getElementsByTagName(«p»)

    ‘Выбираем, содержимое какого тега по порядку, начинающегося с 0, нужно извлечь

    myTxt = myTag(5).innerText

    MsgBox myTxt

    ‘Большой текст может не уместиться в MsgBox, тогда для просмотра используйте окно Immediate

    ‘Debug.Print myTxt

End Sub

С помощью этого кода извлекается текст, расположенный между открывающим и закрывающим тегами. В примере — это текст 6-го абзаца (p) между 5-й (нумерация с 0) парой отрывающего <p> и закрывающего </p> тегов.

Примеры тегов, используемых в html: "p", "title", "h1", "h2", "table", "div", "script".

Пример извлечения содержимого тега "title":

Sub Primer2()

Dim myHtml As String, myFile As Object, myTag As Object, myTxt As String

    myHtml = GetHTML1(«https://internettovary.ru/sadovaya-nozhovka-sinitsa/»)

    Set myFile = CreateObject(«HTMLFile»)

    myFile.body.innerHTML = myHtml

    Set myTag = myFile.getElementsByTagName(«title»)

    myTxt = myTag(0).innerText

    MsgBox myTxt

End Sub

Парсинг содержимого Id

Извлечение текстового содержимого html-элементов, имеющих уникальный идентификатор — Id, с помощью метода getElementById объекта HTMLFile:

Sub Primer3()

Dim myHtml As String, myFile As Object, myTag As Object, myTxt As String

    myHtml = GetHTML1(«https://internettovary.ru/sadovaya-nozhovka-sinitsa/»)

    Set myFile = CreateObject(«HTMLFile»)

    myFile.body.innerHTML = myHtml

    ‘Присваиваем переменной myTag html-элемент по указанному в скобках Id

    Set myTag = myFile.getElementById(«attachment_465»)

    ‘Присваиваем переменной myTxt текстовое содержимое html-элемента с Id

    myTxt = myTag.innerText

    MsgBox myTxt

    ‘Большой текст может не уместиться в MsgBox, тогда для просмотра используйте окно Immediate

    ‘Debug.Print myTxt

End Sub

Для реализации представленных здесь примеров могут понадобиться дополнительные библиотеки. В настоящее время у меня подключены следующие (к данной теме могут относиться последние шесть):

  • Visual Basic For Applications
  • Microsoft Excel 16.0 Object Library
  • OLE Automation
  • Microsoft Office 16.0 Object Library
  • Microsoft Forms 2.0 Object Library
  • Ref Edit Control
  • Microsoft Scripting Runtime
  • Microsoft Word 16.0 Object Library
  • Microsoft Windows Common Controls 6.0 (SP6)
  • Microsoft ActiveX Data Objects 6.1 Library
  • Microsoft ActiveX Data Objects Recordset 6.0 Library
  • Microsoft HTML Object Library
  • Microsoft Internet Controls
  • Microsoft Shell Controls And Automation
  • Microsoft XML, v6.0

С этим набором библиотек все примеры работают. Тестирование проводилось в VBA Excel 2016.


Содержание

  1. VBA Excel. Парсинг сайтов, html-страниц и файлов
  2. Парсинг html-страниц (msxml2.xmlhttp)
  3. Парсинг сайтов (WinHttp.WinHttpRequest.5.1)
  4. Парсинг файлов (ADODB.Stream)
  5. Примеры записи текста в переменную
  6. Извлечение данных из html
  7. Парсинг содержимого тегов
  8. Парсинг содержимого Id
  9. Как Excel и VBA помогают отправлять тысячи HTTP REST API запросов
  10. Часть 1. Реализация решения под Windows
  11. Часть 2. Реализация решения под MacOS и Excel 64-bit
  12. How to get http request with XmlHttpRequest
  13. How to do that?
  14. How to declare XmlHttpRequest?
  15. 1. Reference – early binding
  16. 2.Object – late binding
  17. How to get original file name from URL?
  18. How to download file?
  19. Summary
  20. Author: Tomasz Płociński
  21. 11 thoughts on “How to get http request with XmlHttpRequest”

VBA Excel. Парсинг сайтов, html-страниц и файлов

Пользовательские функции VBA Excel для парсинга сайтов, html-страниц и файлов, возвращающие их текстовое содержимое. Примеры записи текста в переменную.

Парсинг html-страниц (msxml2.xmlhttp)

Пользовательская функция GetHTML1 (VBA Excel) для извлечения (парсинга) текстового содержимого из html-страницы сайта по ее URL-адресу с помощью объекта «msxml2.xmlhttp»:

Парсинг сайтов (WinHttp.WinHttpRequest.5.1)

Пользовательская функция GetHTML2 (VBA Excel) для извлечения (парсинга) текстового содержимого из html-страницы сайта по ее URL-адресу с помощью объекта «WinHttp.WinHttpRequest.5.1»:

Парсинг файлов (ADODB.Stream)

Пользовательская функция GetText (VBA Excel) для извлечения (парсинга) текстового содержимого из файла (.txt, .csv, .mhtml), сохраненного на диск компьютера, по его полному имени (адресу) с помощью объекта «ADODB.Stream»:

Примеры записи текста в переменную

Общая формула записи текста, извлеченного с помощью пользовательских функций VBA Excel, в переменную:

Извлечение данных из html

В понятие «парсинг», кроме извлечения текстового содержимого сайтов, html-страниц или файлов, входит поиск и извлечение конкретных данных из всего полученного текстового содержимого.

Пример извлечения email-адресов из текста, присвоенного переменной, смотрите в последнем параграфе статьи: Регулярные выражения (объекты, свойства, методы).

Парсинг содержимого тегов

Извлечение содержимого тегов с помощью метода getElementsByTagName объекта HTMLFile:

С помощью этого кода извлекается текст, расположенный между открывающим и закрывающим тегами. В примере — это текст 6-го абзаца (p) между 5-й (нумерация с 0) парой отрывающего

Примеры тегов, используемых в html: «p» , «title» , «h1» , «h2» , «table» , «div» , «script» .

Пример извлечения содержимого тега «title» :

Парсинг содержимого Id

Извлечение текстового содержимого html-элементов, имеющих уникальный идентификатор — Id, с помощью метода getElementById объекта HTMLFile:

Для реализации представленных здесь примеров могут понадобиться дополнительные библиотеки. В настоящее время у меня подключены следующие (к данной теме могут относиться последние шесть):

  • Visual Basic For Applications
  • Microsoft Excel 16.0 Object Library
  • OLE Automation
  • Microsoft Office 16.0 Object Library
  • Microsoft Forms 2.0 Object Library
  • Ref Edit Control
  • Microsoft Scripting Runtime
  • Microsoft Word 16.0 Object Library
  • Microsoft Windows Common Controls 6.0 (SP6)
  • Microsoft ActiveX Data Objects 6.1 Library
  • Microsoft ActiveX Data Objects Recordset 6.0 Library
  • Microsoft HTML Object Library
  • Microsoft Internet Controls
  • Microsoft Shell Controls And Automation
  • Microsoft XML, v6.0

С этим набором библиотек все примеры работают. Тестирование проводилось в VBA Excel 2016.

Источник

Как Excel и VBA помогают отправлять тысячи HTTP REST API запросов

Работая в IoT-сфере и плотно взаимодействуя с одним из основных элементов данной концепции технологий – сетевым сервером, столкнулся вот с какой проблемой (задачей): необходимо отправлять много запросов для работы с умными устройствами на сетевой сервер. На сервере был реализован REST API с оболочкой Swagger UI, где из графической оболочки можно было отправлять только разовые запросы. Анализ сторонних клиентов, типа Postman или Insomnia показал, что простого визуального способа поместить в скрипт массив из необходимого перечня идентификаторов устройств (или любых других элементов сервера), для обращения к ним – не нашлось.

Так как большая часть работы с выгрузками и данными была в Excel, то решено было вспомнить навыки, полученные на учебе в университете, и написать скрипт на VBA, который бы мою задачку решал.

получать информацию по устройствам с различными параметрами фильтрации (GET);

применять изменения в конфигурации по устройствам: имя, профиль устройства, сетевые лицензии и пр. (PUT);

отправлять данные для конфигурации и взаимодействия с устройствами (POST).

И сегодня я расскажу вам про то, как с помощью Excel, пары формул и самописных функций на VBA можно реализовать алгоритм, отправляющий любое необходимое количество REST-API запросов с использованием авторизации Bearer Token.

Данная статья будет полезная тем, кто воспользуется данным решением под Windows, но еще больше она будет полезна тем людям, которые хотят использовать данное решение на MacOS (с Excel x64). Как вы уже догадались, ниже будут рассмотрены два варианта реализации под разные системы, так как с MacOS есть нюанс.

Часть 1. Реализация решения под Windows

GET

Начнем с самого простого: GET – запросов. В данном примере необходимо получить ответ (информацию) от сервера по заданному списку устройств.

Для реализации GET – запросов нам дано:

1) Ссылка, в которой указываются параметры запроса.

2) Заголовки запроса + Токен авторизации (Bearer Token)

—header ‘Accept: application/json’ —header ‘Authorization: Bearer

3) Параметр, указываемый в ссылке (в данном примере это идентификаторы устройств – DevEUI):

Имея такие данные на входе, делаем в Excel лист-шаблон, который заполняем в соответствии с тем, что имеем:

столбец А уходит вот значения параметров

столбец F уходит под ссылку-родителя

столбец H уходит под заголовки, где в ячейке H1 единоразово для текущего листа указывается токен:

=СЦЕП(«—header ‘Accept: application/json’ —header ‘Authorization: Bearer «;$H$1;»‘»)

столбец I уходит под URL (ссылки-дети, на основе ссылки-родителя)

столбец J уходит под результат (ответ от сервера)

Шаблон листа для GET-запросов

Далее, нам необходимо реализовать подпрограмму(макрос) отправки GET-запросов. Состоит она из четырех частей:

цикла, который считает количество строк для работы по листу, пробегая по столбцу А с 2 по первую пустую ячейку, чтобы у цикла был конец.

функции, для работы с REST API (используется стандартная, библиотека Msxml2.XMLHTTP.6.0, встроенная в Windows., поэтому сложностей с реализацией не возникает. Для MacOS есть альтернатива)

временной задержки, в случае если нужно отправлять запросы не сразу, после получения ответа, а задав время ожидания

таймером, который показывает время выполнения всего макроса после завершения

Привязываем подпрограмму к кнопкам для удобства и выполним скрипт. Получается:

Таким образом, скрипт проходит по столбцу I, забирая из значения каждой ячейки URL, для тех строк, где в столбце А есть значения (которые и подставляются в URL). Для удобства также сделаны кнопки очистки полей и подсветка запросов условным форматированием, в случае успешного ответа на запрос.

PUT

Чуть-чуть усложним задачу и перейдем к PUT-запросам. В данном примере необходимо изменить профиль устройства, чтобы сервер по-другому с ним взаимодействовал.

К исходным данным для GET – запроса добавляется тело запроса с ключем-значением (п4). Итого дано:

1) Ссылка, в которой указываются параметры запроса.

2) Заголовки запроса + Токен авторизации (Bearer Token)

—header ‘Content-Type: application/json’ —header ‘Accept: application/json’ —header ‘Authorization: Bearer

3) Параметр, указываемый в ссылке (в данном примере это внутренние идентификаторы устройств – hRef):

4) Тело запроса, с ключом и значением:

Немного дополняем новый PUT-лист в Excel по сравнению с GET (остальное без изменений):

новый столбец B теперь отвечает за ключ deviceProfileId (ячейка B1), а все значения ниже за его возможные значения)

столбец D отвечает за формирование итогового тела сообщения в формате JSON.

Немного поменяем макрос и вынесем его в отдельную подпрограмму:

Привяжем макрос к кнопке и выполним.

Логика абсолютно аналогична GET запросу.

POST

Для POST запросов все аналогично PUT. Только немного меняется код в части типа запроса. В данном примере на устройство отправляется команда-конфигурация с указанием тела посылки (payload_hex) и порта (fport) для конкретного устройства.

Получившаяся таблица выглядит следующим образом:

На этом часть для Windows заканчивается. Здесь все оказалось довольно просто: стандартная библиотека, простенький алгоритм перебора значений в цикле.

Часть 2. Реализация решения под MacOS и Excel 64-bit

В виду того, что работал я на двух машинах под управлением разных ОС, хотелось, чтобы решение было универсальным. В итоге, собрав по крупицам информацию по интернет-форумам с данной тематикой у меня вышло следующее решение. Принцип работы его остается схожим, а изменения были внесены в часть, где использовалась стандартная библиотека WindowsMsxml2.XMLHTTP.6.0, которой в MacOS не было по понятным причинам.

Чтобы обойти данное ограничение, был выбран единственный рабочий подход через cUrl, exec и функции. Данное решение точно работает под версией MacOS 10.14 и Excel 16.51. Функция ниже, в том или ином виде, встречается на различных форумах, однако на текущих версиях софта – не работает. В итоге, после небольших правок получили рабочий вариант:

Была отлажена функция вызова ExecShell:

И написаны отдельные функции для работы с различным методами GET / PUT / POST, которые на входе принимают URL и параметры):

Так как мы заменяем библиотеку Msxml2.XMLHTTP.6.0 – поменялась реализация макросов в этой части: мы заменили Msxml2 на написанные выше функции и получили следующее:

В итоге, у меня получилось аналогичное windows по работе и функционалу решение для MacOS c использованием Excel 64-bit.

На просторах интернета я не нашел какого-то сборного и единого описания, только фрагменты кода и подходов, которые в большинстве случаев не работали полностью или частично. Поэтому решил объединить все в рабочее решение и выложить на хабр для истории.

На текущий момент я все еще не встретил иного решения, которое бы позволяло в пару кликов копипастить тысячи идентификаторов и параметров из excel и массово их отправлять на сервер. Надеюсь, кому-то пригодится 🙂

Если такие сторонние решения есть, а я не в курсе, и все можно было сделать проще, быстрее и изящнее – делитесь опытом в комментариях.

Файл-пример, который можно потыкать, пока жив сервер и «бессрочный» токен:

Источник

How to get http request with XmlHttpRequest

In this post You will learn how to get http request with XmlHttpRequest, get original file name from URL and download it to chosen location.

We got a list of URL links to files in column B. We want to download everything automatically and save files in chosen location with original names from server.

How to do that?

There are several methods to do that (one of them is in previous post). In this article I’ll show You how to deal with our case using XmlHttpRequest.

How to declare XmlHttpRequest?

There are 2 ways:

1. Reference – early binding

First of all You need to choose the reference in Tools/Reference -find Microsoft XML, v6.0 or other version.

And put this in code:

Quick note: there would be MSXML2.XMLHTTP for previous versions.

2.Object – late binding

Using this method You don’t have to choose a reference, just declare and create MSXML2.serverXMLHTTP object.

How to get original file name from URL?

After some attempts I “discovered”, that what we need is .getResponseHeader(“Content-Disposition”). It provides original file name.

Unfortunately it returns us something like this: filename=name of the file with extension. We need to erase filename= phrase.

If it returns empty, we will extract file name from URL.

FileNameFromPath is a simple function, which extracts everything after last slash from URL (function included in final code).

How to download file?

To make it nice and easy we will use function URLDownloadToFile from urlmon library.

To make it possible we need to declare this function from library, like shown below. That has to be at the beginning, at the top of our code.

This function returns 0, when download is successful and returns 1, when something goes wrong.

There is one more thing which I should mention.

It means location for downloaded files, which is needed for URLDownloadToFile function.

And now, the code.

Summary

Now You know how to get http request with XmlHttpRequest, download file and save it with original file name. Remember that HTTP requests can be used to interact with a web service, API or even whole websites. Also keep in mind, that XmlHttpRequest is one from many methods to get http request, which I already mentioned in the article.

I’m very advanced in VBA, Excel, also easily linking VBA with other Office applications (e.g. PowerPoint) and external applications (e.g. SAP). I take part also in RPA processes (WebQuery, DataCache, IBM Access Client Solutions) where I can also use my SQL basic skillset. I’m trying now to widen my knowledge into TypeScript/JavaScript direction. View all posts by Tomasz Płociński

11 thoughts on “How to get http request with XmlHttpRequest”

Thanks a lot for the awesome tutorials.
I can’t recognize “Content-Disposition” in the Response Headers and I have used the following link as an example: https://simpleexcelvba.com/wp-content/uploads/2019/12/downloadjpg.jpg and in Headers when pressing F12, I couldn’t see this “Content-Disposition”..

I appreciate that 🙂
Yes, that image is not returning that. Working with .WinHttpRequest code I noticed that if You got a link to file with no file name with extension included (unlike your example) links are returning names using “Content-Disposition”. And if there is file name in link usually there is no response, that’s why I suggested in article to get the file name from link.

Thank you very much for your swift reply. Can you give me an example of how to use “Content-Disposition”?

I just found specially for You a hyperlink with no file name in it, but when You enter this You can clearly see that this is PDF file.
Try to get its “Content-Disposition” and You will see what I described in the article 🙂
https://www.oras.com/datasheet/2222F/pl
(this is the link into catalog card of ORAS company product, You can try to find something like this by yourself ofc.)

Hi Tomasz,
thanks for the tutorial. I have a real layman’s problem: the script always ends at the point “counter = 0” with an “compiling error”: “Variable not defined.”
Can you tell me what I’m doing wrong?
Thank you very much, greetings,
Manfred

Hello Manfred
This variable is not declared, but also this variable is not needed anywhere. Just get rid of that and the rest should be fine!
Corrected this in article. Thanks!

Источник

Цель книги – предоставить инструменты Excel для автоматизации повторяющихся задач извлечения данных из Интернета. Автор предлагает несколько десятков программ VBA и описывает приемы работы в Power Query.

Eduardo Sanchez. Excel and The World Wide Web. Straight to the Point. – Holy Macro! Books, 2021. – 58 p.

Скачать заметку в формате Word или pdf, примеры в формате zip (внутри файл Excel с поддержкой макросов)

Примеры кода: https://www.mrexcel.com/download-center/excel-and-the-world-wide-web-8051/

Глава 1. Приступая к работе

Что такое HTML?

HTML (Hyper Text Markup Language) – язык гипертекстовой разметки. Он используется для создания веб-сайтов. Гипертекст – это контент, который ведет себя нелинейным образом. Представьте себе веб-сайт, на каждой странице которого есть несколько ссылок на другие страницы, как того же самого сайта, так и других сайтов. Пользователь перемещается, переходя с одной страницы на другую; это гипертекстовое поведение. Обычная печатная книга – это контрпример, ее предполагается читать последовательно.

Информация в HTML помечена тегами; ниже мы поговорим об этом подробнее. Существуют и другие языки, используемые для создания веб-сайтов, такие как CSS и JavaScript, но мы не будем подробно рассматривать их здесь.

CSS (Cascading Style Sheet) – каскадная таблица стилей, язык описания внешнего вида документа. Он работает вместе с HTML, который отвечать за содержимое страницы. Каскадирование означает, что можно использовать несколько CSS-файлов для создания окончательного визуального стиля. Этот язык управляет такими элементами, как размер шрифта, фоновые изображения и цветовая палитра.

JavaScript – язык программирования для реализации динамического поведения на веб-сайтах. С его помощью разработчики могут манипулировать содержимым страницы, создавать диаграммы и взаимодействовать с API (Application Programming Interface, интерфейс прикладного программирования). Обратите внимание, что JavaScript и Java – это два разных языка. Говорят, что в будущем JavaScript может заменить VBA в качестве языка программирования Office.

Одна из замечательных особенностей современных браузеров заключается в том, что они предоставляют исходный код страниц. Если вы используете Google Chrome, просто щелкните правой кнопкой мыши любой элемент страницы и выберите пункт Просмотреть код; в правой части окна появится панель, аналогичная показанной ниже:

Рис. 1. Фрагмент кода HTML веб-страницы; чтобы увеличить изображение кликните на нем правой кнопкой мыши и выберите Открыть картинку в новой вкладке

Обратите внимание:

  • Ключевые слова header, div, aside, nav, h4, li и другие являются тегами.
  • Когда маленькие черные треугольники указывают вправо, это означает, что их можно щелкнуть, чтобы развернуть и отобразить дополнительную информацию.
  • Ключевые слова id, class и href являются атрибутами.
  • <li – это открывающий тег, а </li> – закрывающий.
  • Элемент может принадлежать к нескольким различным классам.

Если вы чувствуете себя подавленным всем этим, не паникуйте; не обязательно быть программистом HTML, чтобы работать с такого рода автоматизацией. Позже мы увидим, как читать код HTML и извлекать информацию с помощью VBA.

Хотя веб-дизайнеры используют профессиональные редакторы, можно создавать HTML-файлы в стандартных приложениях Windows, например, в Блокноте. Это особенно быть полезно, когда вы хотите протестировать код VBA, который будет взаимодействовать с веб-страницей, но по какой-то причине реальный сайт недоступен.

Чтобы создать локальный HTML-файл, выполните следующие действия:

  • Откройте Блокнот и введите исходный код, как ниже.
  • Сохраните его с расширением htm.
  • Откройте этот файл с помощью браузера. Для этого, например, можно в Проводнике просто кликнуть на файле (если вы всё сделали верно, файл будет иметь иконку вашего браузера по умолчанию).
  • Чтобы позже отредактировать исходный код, переименуйте расширение в txt.

<!DOCTYPE html>

<html>

<body style=«background-color:powderblue;»>

<h1>My Heading</h1>

<p><i>This is italic.</i></p>

<p style=«color:red;»>Red paragraph.</p>

<button>Click me</button>

<bdo dir=«rtl»><br><br>12345<br><br></bdo>

</body>

</html>

Например, в Chrome файл выглядит так (я кликнул Просмотреть код):

Рис. 2. Файл, созданный в Блокноте и открытый в браузере

Выполнение запросов

Веб-запрос позволяет извлечь информацию, хранящуюся в HTML-файле. Обычно он используется для подключения к какому-либо веб-сайту, но также можно запросить локальный файл.

Если вы планируете извлекать данные из одного и того же источника снова и снова, сохраните запрос и просто обновляйте его. Веб-запросы Excel идентифицируют таблицы на выбранной странице в Интернете и позволяют импортировать таблицы в книгу.

Статический запрос

Стандартный запрос Excel является статическим, то есть он не принимает параметры. Чтобы выполнить статический веб-запрос, выполните следующие действия:

  1. Пройдите по меню Данные –> Получить и преобразовать данные –> из Интернета. (Хотя книга датируется 2021-м г., автор описывает импорт из Интернета в версии Excel 2013. На одном из ПК у меня установлена эта «древняя» версия, но, наверное, движок импорта настолько отстал от развития www, что мне не удалось с его помощью импортировать ни одной из страниц. Примеры в этом разделе выполнены в Excel)
  2. Откроется диалоговое окно, введите адрес страницы, которую хотите импортировать. Я ввел ссылку на страницу Википедии Список государств и зависимых территорий по населению.
  3. Нажмите Ok.

Рис. 3. Окно стандартного запроса Excel

  1. При первом обращении к сайту появится окно запроса уровня доступа. Оставьте настройку по умолчанию – Анонимно. Нажмите Подключение.
  2. Откроется окно навигатора Power Query. Кликайте по очереди на таблицы в левой части. Остановите свой выбор на подходящей (Table 0). Нажмите Преобразовать данные.

Рис. 4. Выбор таблицы для подключения

Удалите все столбцы, кроме Страна и Население. Преобразуйте тип данных в столбце Население в Целое число. Загрузите данные в умную таблицу на лист Excel. У вас получится что-то вроде:

Рис. 5. Начало умной таблицы с населением стран, импортированной из Интернета

Подробнее об импорте из Интернет с использование Power Query см. здесь.

Динамический веб-запрос

Допустим, вам нужно получить информацию с нескольких страниц одного веб-сайта, и в адресах страниц можно выявить шаблон. Можно передать переменную в веб-запрос с помощью функции Power Query. (Автор продолжает рассказ на основе версии Excel 2013. В ней запросы хранятся в отдельных текстовых файлах с расширением IQY. Поэтому метод основан на редактировании таких файлов.)

На первом шаге я создал обычный статический запрос к странице рейтинга АТР:

Рис. 6. Сайт АТР

Рис. 7. Умная таблица, полученная статическим запросом Power Query

Обратите внимание: вверху на рис. 6 адрес страницы https://www.atptour.com/en/rankings/singles. Страница рейтинга парных игроков отличается лишь последним фрагментом: https://www.atptour.com/en/rankings/doubles. В нашем учебном примере мы создадим функцию в Power Query, которая будет считывать с листа Excel, какой рейтинг запросить из Интернета.

Шаг 2. На новом листе Excel создайте умную таблицу:

Рис. 8. Таблица параметров на листе Excel

Следующие названия должны быть такими же, как на рисунке: заголовок первого столбца Parameter, заголовок второго столбца Value, имя таблицы Parameters. Это позволит использовать заготовленный текст функции. В ячейке А1 я применил инструмент Проверка данных, чтобы создать список выбора рейтинга:

Рис. 9. Список для выбора рейтинга

Формула в В5 считывает значение в А1 и возвращает полный путь к странице сайта: =»https://www.atptour.com/en/rankings/»&A1

Шаг. 3. Создадим пользовательскую функцию fnGetParameter в Power Query:

= (ParameterName as text) =>

let

ParamSource = Excel.CurrentWorkbook(){[Name=«Parameters»]}[Content],

ParamRow = Table.SelectRows(ParamSource, each ([Parameter]=ParameterName)),

Value=

if Table.IsEmpty(ParamRow)=true

then null

else Record.Field(ParamRow{0},«Value»)

in

Value

Функция подключается к таблице Parameters в книге Excel, и извлекает путь к сайту. Скопируйте текст функции в буфер. В Excel пройдите по меню Данные –> Получить данные –> Из других источников –> Пустой запрос. В редакторе Power Query перейдите на вкладку Главная –> Расширенный редактор. Выделите все строки кода и нажмите Ctrl+V, чтобы вставить содержимое из буфера обмена. Нажмите Готово. Измените имя функции на fnGetParameter. Пройдите по меню Главная –> Закрыть и загрузить. Для функций используется единственный тип загрузки – Только создать подключение.

Вызов функции fnGetParameter

Теперь в ранее созданном статическом запросе АТР заменим фиксированный URL на динамический, возвращаемый функцией fnGetParameter. В файле Excel пройдите по меню Данные –> Запросы и подключения. В области Запросы и подключения кликните правой кнопкой мыши на запросе АТР –> Изменить. В редакторе Power Query кликните Расширенный редактор:

Рис. 10. Исходный код статического запроса с именем ATP

Вставьте строку кода сразу после let (не забудьте про запятую в конце строки):

sitepath = fnGetParameter(«Site Path»),

Рис. 11. Функция fnGetParameter возвращает значение из таблицы листа Excel

Функция вернет путь к сайту из ячейки В5 таблицы Parameters. Вы создали новую переменную sitepath для хранения значения из строки File Path таблицы Excel. Нажмите Готово. Во второй строке кода в Расширенном редакторе выделите путь к сайту включая кавычки, и замените его на имя переменной – sitepath (как показано на рис. 11). Если вы всё делали верно, как только вы наберете букву s, редактор выдаст контекстную подсказку, в которой в том числе будет и имя переменной sitepath. Откроется окно:

Рис. 12. Подтверждение конфиденциальности данных

Нажмите Продолжить. Откроется еще одно окно:

Рис. 13. Не проверять уровень конфиденциальности для этого файла

Поставьте галочку, как показано выше.

Вы можете проверить, как работает переменная sitepath. В редакторе Power Query перейдите в область ПРИМЕНЕННЫЕ ШАГИ, и кликните на первый шаг. Отразится имя страницы сайта:

Рис. 14. Переменная sitepath правильно определяет название страницы сайта

В редакторе Power Query пройдите по меню Главная –> Закрыть и загрузить. Осталось проверить, как работает динамический запрос. В Excel перейдите на лист с таблицей Parameters, и в ячейке А1 выберите doubles. Перейдите на лист умной таблицы с рейтингом АТР, правой кнопкой щелкните на любой ее ячейке, и выберите Обновить. Таблица отразит данные рейтинга парных игроков:

Рис. 15. Рейтинг парных игроков, извлеченный с сайта АТР динамическим запросом Power Query

Запрос с помощью VBA

Можно написать код VBA, который автоматизирует этот процесс. Обратите внимание, что строковые переменные могут быть жестко закодированы или извлечены из рабочего листа. Результирующая таблица создается, начиная с ячейки A5 активного листа.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

Sub Query_one()

Dim part1$, part2$

‘part1 = «www.atptour.com/en/rankings/»

part2 = «singles»

part1 = [b2]    ‘ from cell B2

part2 = [b3]    ‘ from cell B3

Application.CutCopyMode = False

With ActiveSheet.QueryTables.Add(Connection:= _

«URL;https://» & part1 & part2, Destination:=Range(«$A$5»))

.Name = «wash»

.FieldNames = True

.RowNumbers = False

.FillAdjacentFormulas = False

.PreserveFormatting = True

.RefreshOnFileOpen = False

.BackgroundQuery = True

  .SavePassword = False

.SaveData = True

.AdjustColumnWidth = True

.RefreshPeriod = 0

.WebSelectionType = xlAllTables

.WebFormatting = xlWebFormattingNone

.WebPreFormattedTextToColumns = True

.WebSingleBlockTextImport = False

  .WebDisableDateRecognition = False

.WebDisableRedirections = False

.Refresh BackgroundQuery:=False

End With

End Sub

Рис. 16. Данные, полученные запросом на основе кода VBA

Глава 2. Взаимодействие с сайтами без использования браузера

Когда мы говорим о получении данных из Интернета, некоторые люди думают об автоматизации браузера, например, Internet Explorer. На самом деле, в зависимости от конкретных потребностей пользователя, это довольно неэффективно. В этой главе будут представлены методы получения или публикации данных через Интернет. Говоря о данных, давайте сделаем шаг назад и обсудим JSON.

Что такое JSON?

JSON (JavaScript Object Notation) – формат для хранения и обмена информацией, доступной для чтения человеком, как и XML. Поскольку он очень популярен в наши дни, мы будем использовать примеры JSON, чтобы продемонстрировать некоторые из методов в этой главе. JSON в основном работает с двумя сущностями, а именно объектами и массивами:

{

   «name»: «This is my site»,

   «url»: «https://bananas.com»

}

Имя и URL-адрес называются ключами с соответствующими значениями. Следующий синтаксис определяет массив:

[«Nicole»,»Elaine»,»Samantha»,»Tom»]

Эти два основных элемента могут быть объединены, как показано ниже; значение ключа Files представляет собой массив.

{

   «id»: 18,

   «personal»: {

      «name»: «Jean Ferguson»,

      «Files»: [«ftpA», «ftpB»]

   }

}

Это почти все, что вам нужно знать, чтобы начать работать с файлами JSON.

Получение данных из Интернета с помощью кода VBA

Объекты запроса VBA XMLHTTP/ServerXMLHTTP предоставляют необходимые ресурсы для выполнения задач связи с веб-страницами и службами. Чтобы использовать их в своем коде, выполните следующие действия:

  • Перейдите в редактор VBA
  • Нажмите кнопку Tools в строке меню и выберите References.
  • Отметьте строку Microsoft XML v6.0:

Рис. 17. Диалоговое окно VBA References

Когда Интернет начал расти в размерах, возникла необходимость в выделенных компьютерах для предоставления различных услуг (серверы), в то время как пользователи получают доступ к услугам (клиенты). Общие серверы – это веб-службы, электронная почта и FTP. Когда браузер открывает веб-страницу, он действует как клиент, а сайт, предлагающий информацию, размещен на сервере. Это называется архитектурой клиент-сервер.

В следующем примере мы получим данные JSON с веб-сайта, специально созданного для целей тестирования. Вот как выглядит этот сайт:

Рис. 18. Тестовый сайт для извлечения данных JSON

К сожалению, в Excel нет встроенной поддержки JSON. Следующий код просто поместит текст JSON в строковую переменную:

Public Sub Direct()

Dim http As Object, resp$

Set http = CreateObject(«MSXML2.XMLHTTP»)

http.Open «GET», «http://jsonplaceholder.typicode.com/» _

& «posts/1/comments», False

http.send

get the response

resp = http.responseText

MsgBox Left(resp, 350), 64, «The first 350 characters»

End Sub

Рис. 19. Данные JSON просто записаны в строковую переменную

Содержимое удалось извлечь, но работа с информацией, хранящейся в переменной, потребует неуклюжих манипуляций со строками.

Хорошей новостью является то, что в Интернете есть несколько бесплатных конвертеров JSON, которые обеспечат структурированный способ обработки данных. Один из них называется VBA-JSON. Чтобы воспользоваться им:

  1. Перейдите на главную страницу https://github.com/VBA-tools/VBA-JSON и нажмите кнопку Code, а затем Download ZIP.
  2. Извлеките папку VBA-JSON-master на свой ПК.
  3. Откройте книгу Excel, в которой вы хотите использовать код, и перейдите в редактор VBA.
  4. Щелкните правой кнопкой мыши любой модуль на левой панели и выберите опцию Import File…
  5. В появившемся диалоговом окне найдите и выберите файл JsonConverter.bas из разархивированного пакета.
  6. Нажмите кнопку Открыть, и в ваш проект VBA будет добавлен новый модуль. Исходный код не защищен, поэтому вы можете изучить его.
  7. Добавьте ссылку на библиотеку Microsoft Scripting Runtime. Нажмите Ok. Вы можете получать ошибки, если эта ссылка будет иметь низкий приоритет в списке. Чтобы избежать этого, вернитесь в окно Tools –> References и нажмите стрелку вверх, чтобы увеличить его приоритет, как показано ниже:

Рис. 20. Повышение приоритета ссылки на библиотеку Microsoft Scripting Runtime

Теперь можно запустить следующий код, чтобы перенести данные JSON на рабочий лист:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

Public Sub Use_Library()

Dim http As Object, json As Object, i%, item, _

head, dest As Range

Set http = CreateObject(«MSXML2.XMLHTTP»)

‘ create array with keys

head = Array(«id», «name», «postId», «email», «body»)

Set dest = [a1].Resize(1, UBound(head) + 1)

dest.Value = head       ‘ first row

http.Open «GET», «http://jsonplaceholder.typicode.com/» _

& «posts/1/comments», False

http.send

Set json = ParseJson(http.responseText)

i = 2

For Each item In json

Sheets(2).Cells(i, 1) = item(head(0))

Sheets(2).Cells(i, 2) = item(head(1))

Sheets(2).Cells(i, 3) = item(head(2))

Sheets(2).Cells(i, 4) = item(head(3))

Sheets(2).Cells(i, 5) = item(head(4))

i = i + 1   next row

Next

End Sub

Рис. 21. Эта таблица Excel была создана на основе данных в формате JSON

Получение данных из элементов веб-страницы

Ранее я показал HTML-код с веб-страницы (см. рис. 1), которая содержала класс с именем «nav-link». Следующий код найдет все элементы, принадлежащие этому классу, и извлечет строку, представляющую атрибут href. Этот атрибут указывает адрес назначения для ссылки. Затем все адреса поместятся на рабочий лист Excel. Но начните с подключения библиотеки Microsoft HTML Object Library.

Обратите внимание, что, набрав Н в строке объявления переменных, редактор VBA предложит доступные варианты для продолжения набора. Эта функция известна как Intellisense. Она позволяет выбирать свойства и методы для переменных, а также служит для автоматического завершения набора кода (аналогичная функция есть и в Excel, облегчая набор формул).

Рис. 22. Intellisense в действии

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

Public Sub Get_Class()

Dim http As Object, html As New H, _

topics As Object, topic As HTMLHtmlElement, i%

Set http = CreateObject(«MSXML2.XMLHTTP»)

http.Open «GET», «https://www.mrexcel.com/», False

http.send

html.body.innerHTML = http.responseText

‘ create a collection

Set topics = html.getElementsByClassName(«nav-link»)

MsgBox topics.Length, 64, «Number of items found»

i = 2

For Each topic In topics

    ‘ write to worksheet

Cells(i, 1) = topic.getAttribute(«href»)

i = i + 1

Next

End Sub

Рис. 23. Просмотр части очищенных данных

Размещение данных в Интернете

Как правило, мы используем код для получения данных с сайта, но бывают случаи, когда нам нужно отправить данные, например, чтобы сообщить приложению, сколько акций вы хотите купить. Приведенный ниже код отправляет данные JSON из ячейки D1 в точку тестирования.

Sub Post_example()

Dim HTTP As Object, json$, URL$

‘ get the JSON string from worksheet

json = Range(«d1»)

use server object

Set HTTP = CreateObject(«MSXML2.ServerXMLHTTP»)

URL = «https://jsonplaceholder.typicode.com/posts»

HTTP.Open «POST», URL, False

HTTP.setRequestHeader «Content-type», «application/json»

HTTP.send (json)

MsgBox HTTP.responseText, 64, «This is the result:»

Set HTTP = Nothing

End Sub

На рисунке показан текст ответа:

Рис. 24. В окне сообщения отображаются опубликованные данные

Некоторые важные моменты:

  • Строка в ячейке D1 – JSON-представление диапазона A1:C3. Он начинается и заканчивается квадратными скобками; следовательно, это массив.
  • В тексте ответа были созданы индексы «0», «1» и ключ идентификатора со значением 101.
  • Серверный XML-объект, используемый в этом примере, может запрашивать или отправлять данные.

Аутентифицированные запросы

Предыдущие разделы показали, что вполне возможно получить веб-данные с общедоступных сайтов. Однако некоторые приложения потребуют, чтобы вы вошли в службу. Например, финансовые приложения. Очевидно, что без учетных данных пользователя приложение не будет знать, к какой учетной записи принадлежит запрос.

В приведенном ниже примере кода используется учетная запись на веб-сайте Alpaca. Этот вид учетной записи предоставляет возможность выполнять файловые операции в целях тестирования, но у них также есть живая часть, где вы можете рисковать реальными деньгами… Веб-API дает пользователю взаимодействовать с интернет-сервером, извлекая информацию из его базы данных или отправляя определенные данные с помощью почтовых запросов. Адреса назначения часто называются конечными точками, и ответы обычно приходят в форматах JSON или XML.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

Sub authenticating()

Dim req As MSXML2.ServerXMLHTTP60, key_id, _

secretk$, secreth$, URL$, json As Object, item, s$

‘ create object

Set req = New MSXML2.ServerXMLHTTP60

key_id = CStr([b18])         ‘ id from cell B18

secretk = CStr([b19])        ‘ secret key from cell B19

get Microsoft information

URL = «https://paper-api.alpaca.markets/v1/assets/MSFT»

req.Open «GET», URL, False

req.setRequestHeader «APCA-API-KEY-ID», key_id

req.setRequestHeader «APCA-API-SECRET-KEY», secretk

req.send

‘ start building string

s = «Raw data:» & vbLf & req.responseText

s = s & vbLf & «**************» & vbLf & _

«Available data:» & vbLf

use the library

Set json = ParseJson(req.responseText)

For Each item In json   loop the collection

s = s & item & vbLf

Next

MsgBox s, 64

End Sub

Рис. 25. Два ключа на листе и полученные данные

Чтобы получить нужные данные, вам необходимо сообщить идентификатор, а также секретный ключ, который может храниться в ячейках рабочего листа, как показано на рисунке выше. Данные извлекаются в формате JSON; окно сообщения показывает их. (Поскольку автор скрыл ключ и пароль на листе Excel, протестировать код не удалось.)

Глава 3. Internet Explorer и VBA

В настоящее время браузером по умолчанию для Microsoft является Edge, и мы обсудим его позже. Однако Internet Explorer – единственный браузер, у которого есть встроенная поддержка VBA. Поскольку он все еще существует, стоит потратить несколько страниц на его обсуждение.

Первое, что нужно сделать, это добавить ссылку в VBA на библиотеку Microsoft Internet Controls. Если вы используете Windows 10, для запуска IE попробуйте один из вариантов:

  • Нажмите Пуск –> Все приложения и посмотрите в разделе Стандартные – Windows
  • На панели задач кликните кнопку Поиск в Windows и введите Internet Explorer
  • Нажмите клавиши Windows + R и введите iexplore.exe

Некоторые сайты, такие как YouTube, больше не будут открываться в Internet Explorer, поэтому рекомендуется вручную открыть сайт, который вы планируете автоматизировать с помощью IE.

Перенос веб-таблицы на рабочий лист

Рассмотрим веб-сайт, показанный ниже; задача состоит в том, чтобы перенести таблицу на лист Excel вместе с флагами стран.

Рис. 26. Эта таблица будет скопирована в Excel

Глядя на HTML-код ниже, вы заметите теги tr, td и th. Тег <tr> определяет строку в таблице HTML. Элемент <tr> содержит один или несколько элементов <th> или <td>. Таблица HTML имеет два типа ячеек: ячейки заголовка, созданные с помощью элемента <th>, и ячейки данных, созданные с помощью элемента <td>. Также обратите внимание, что существуют элементы, определенные тегом img и содержащие атрибут src; они используются для хранения флагов стран.

Рис. 27. HTML-код веб-страницы с рис. 26

Вот ключевые шаги приведенного ниже кода:

  1. Назовите активный лист Excel sheet1, или измените его имя в коде.
  2. Перейдите на веб-страницу.
  3. Создайте коллекцию всех объектов с тегом img.
  4. Создайте коллекцию всех таблиц страниц; нас будет интересовать вторая таблица этой группы. Поскольку коллекция начинается с индекса #0, мы ссылаемся на индекс #1.
  5. Выполните цикл по строкам таблицы, перенося информацию о каждой стране в отдельные строки рабочего листа. Существует внутренний цикл, который повторяет столбцы таблицы.

При взаимодействии с веб-страницей мы, как правило, ищем определенные элементов в структуре HTML. Вот три самых популярных метода:

  • GetElementbyID – находит один элемент, который имеет уникальный идентификатор. К сожалению, не все элементы страницы будут иметь такой идентификатор.
  • GetElementsbyClassName – создает коллекцию элементов, принадлежащих определенному классу.
  • GetElementsbyTagName – создает коллекцию элементов с определенным тегом.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

Sub Web_Table()

Dim tob As Object, ws As Worksheet, im As shape, rowc%, _

colv%, objie As InternetExplorer, bod As HTMLBody, ic, s$

s = «https://rates.currencywholesale.com/rates/»

Set ws = ThisWorkbook.ActiveSheet

Set objie = New InternetExplorer

objie.Visible = True

objie.navigate s & «rates.html»

‘ wait for page loading

Application.Wait (Now + TimeValue(«0:00:05»))

Set bod = objie.Document.body

Set ic = bod.getElementsByTagName(«img»)

get all tables

Set tob = bod.getElementsByTagName(«table»)

On Error Resume Next    if a flag is missing

For rowc = 0 To tob(1).Rows.Length 1

Set im = ws.Shapes.AddPicture(s & _

ic(rowc + 1).getAttribute(«src»), msoFalse, msoTrue, _

50, 50, 50, 50)

For colv = 0 To tob(1).Rows(rowc).Cells.Length 1

ws.Cells(rowc + 1, colv + 1) = _

tob(1).Rows(rowc).Cells(colv).innerText

With im

.LockAspectRatio = 0

.Top = ws.Cells(rowc + 2, 1).Top

.Left = ws.Cells(rowc + 2, 1).Left

.Width = ws.Cells(rowc + 2, 1).Width

.Height = ws.Cells(rowc + 2, 1).Height

End With

Next

Next

On Error GoTo 0

End Sub

У меня макрос работал около 15 минут.

Рис. 28. Таблица в Excel, полученная макросом

Работа с событиями

Некоторые веб-сайты запрограммированы так, чтобы реагировать на события, генерируемые пользователем; это позволяет создавать более интерактивную и динамичную страницу. В следующем примере используется локальный HTML-файл, чтобы показать основы такого поведения.

В Блокноте создайте файл Code2.txt со следующим кодом:

<!DOCTYPE html>

<html>

<body style=«background-color:powderblue;»>

<h1>My Heading</h1>

<p><i>This is italic.</i></p>

<p style=«color:red;»>Red paragraph.</p>

<button>Click me</button>

<input name=«q» onchange=«alert(‘Alert message’);»/input>

<bdo dir=«rtl»><br><br>12345<br><br></bdo>

</body>

</html>

В Проводнике переименуйте расширение – *.hmt. Чтобы убедиться в работоспособности, дважды кликните на файле, и он откроется в браузере по умолчанию. Обратите внимание, что определено событие on-change, то есть оно будет срабатывать при изменении значения поля ввода. В Excel выполните следующий код. Но перед этим отредактируйте путь к файлу Code2.hmt.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

Sub IE_event()

Dim iea As InternetExplorer, doc, search, _

event_onChange As Object

Set iea = CreateObject(«InternetExplorer.Application»)

iea.Visible = True

iea.navigate «C:UserspublicCode2.htm»

Do Until Not iea.Busy

DoEvents

Loop

Application.Wait Now + TimeValue(«0:00:03»)

Set doc = iea.document

Set search = doc.getElementsByName(«q»)(0)

search.Value = «Pogacar»

‘Exit Sub    ‘exiting here does not display the message

Set event_onChange = iea.document.createEvent(«HTMLEvents»)

event_onChange.initEvent «change», True, False

search.dispatchEvent event_onChange

iea.Quit   close IE window

Set iea = Nothing

End Sub

Макрос открывает локальный файл с помощью Internet Explorer, определяет переменную поиска в качестве поля ввода и записывает в него. После этого код отправляет событие on-change, вызывая появление предупреждающего сообщения:

Рис. 29. Это сообщение страницы было вызвано кодом VBA

При открытии IE с помощью VBA может возникнуть ошибка, связанная с параметрами безопасности. Если вы не используете IE в качестве браузера, измените два параметра. Перейдите в меню Свойства браузера –> Безопасность и снимите флажок Включить защищенный режим. Далее на вкладке Дополнительно установите флажок Разрешить запуск активного содержимого файлов на моем компьютере. Если вы все еще используете IE для просмотра веб-страниц или загрузки файлов для локального использования, безопаснее восстановить эти параметры до значений по умолчанию после завершения задач VBA.

Рис. 30. Изменение параметров безопасности Internet Explorer

Глава 4. Введение в Selenium

Selenium – это инструмент с открытым исходным кодом, используемый для автоматизации тестирования веб-приложений. Он может быстро выполнять десятки функциональных тестов и тестов на совместимость, взаимодействуя с бета-скриптами браузеров. При разработке сложного коммерческого программного обеспечения этап тестирования необходим для минимизации ошибок при развертывании продукта на нескольких платформах.

Флорент Бреер (Florent Breheret) разработал Selenium Basic, который представляет собой фреймворк, позволяющий напрямую использовать Selenium в Excel; так что это две разные вещи:

  • Selenium – платформа автоматизации браузера и экосистема, первоначально созданная Джейсоном Хаггинсом.
  • Selenium Basic (SB) – платформа автоматизации браузера на основе Selenium для VB.Net, VBA и VBScript.

Автор далее называет SB просто Selenium.

Selenium предоставляет интерфейс, который позволяет вашей электронной таблице автоматизировать различные браузеры (кроме Internet Explorer). Например, более стабильный Chrome.

Установка Selenium

Шаг. 1. Загрузите и установите исполняемый файл со страницы GitHub

Рис. 31. Загрузите и установите исполняемый файл Selenium

Шаг. 2. В редакторе VBА добавьте ссылку на библиотеку Selenium Type Library:

Рис. 32. Добавление ссылки на Selenium Type Library

Шаг. 3. Обновите драйвер Chrome, установленный на первом шаге. Дело в том, что пакет установки Selenium включает не самую свежую версию этого драйвера. Для этого перейдите на сайт https://chromedriver.chromium.org/downloads и скачайте драйвер, совместимый с вашей текущей версией Chrome.

Рис. 33. Загрузите последнюю версию драйвера Chrome

Чтобы узнать, какая у вас версия, в Chrome пройдите по меню:

Рис. 34. О браузере Chrome

В открывшемся окне, вы увидите номер версии:

Рис. 35. Версия Chrome 90

Шаг. 4. Замените старую версию драйвера Chrome новой. Сделайте это в папке:

Рис. 36. Папка с компонентами Selenium

Chrome имеет быстрый цикл разработки, и через некоторое время используемый вами драйвер станет несовместимым с новой версией браузера. Когда это произойдет, вы получите ошибки, подобные тем, которые показаны ниже. Чтобы всё снова заработало, опять обновите драйвер.

Рис. 37. Сообщения об ошибках, связанных с версией драйвера

Internet Explorer и Selenium

В большинстве случаев мы будем использовать Selenium для автоматизации современных браузеров, таких как Chrome или Edge. Тем не менее, вы можете взаимодействовать со старым браузером IE; пример ниже показывает, как это сделать.

Public bot As New IEDriver

Sub Test()

With bot

.get «https://www.mrexcel.com/»

.Window.Maximize

.Quit

End With

End Sub

Просто обратитесь к установленному драйверу Internet Explorer, и все будет работать нормально.

Глава 5. Google Chrome и VBA

Установив Selenium займемся автоматизацией браузера Chrome из кода VBA. Selenium имеет свое собственное дерево свойств и методов, но он будет работать аналогично Internet Explorer.

Запуск JavaScript на странице

Для первого примера создадим еще один локальный HTML-файл с исходным кодом, который очень похож на реальную веб-страницу. Он содержит несколько элементов, а также встроенный код JavaScript, завернутый в теги <script>. В Блокноте введите текст:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

<!DOCTYPE html>

<html>

<head>

    <meta charset=«utf-8» />

    <title></title>

</head>

<body>

   <input id=«B1» type=«button» value=«click to change textbox value»

onclick=«TAlert()» />

    <form class=«OF_form»>

        <ul class=«OF_t2»>

            <li class=«OF_3T OF_active»>FIRST</li>

            <li class=«OF_3T»>SECOND</li>

            <li class=«OF_3T»>STOP</li>

        </ul>

        <ul class=«OF_toggle»>

            <li class=«OF_ttab_ OF_buy OF_active»>THIRD</li>

            <li class=«OF_ttab OF_sell»>FOURTH</li>

        </ul>

        <div class=«MOr»>

            <div class=«OF_section»>

                <div class=«OF_section-h»>Amount</div>

                <div class=«OF_input-box_Xk»>

                <input type=«number» step=«0.1» min=«0» name=«amount»

placeholder=«0.00» value=«»

       autocomplete=«off» oninput=«OIHandler()»>

                    <span>USD</span>

                </div>

            </div>

        </div>

        <div class=«OF_OT»>

            <div>

                <b>Total</b>

                <span>(corrected)</span>

                <b></b>

            </div>

            <div class=«OF_total» >0.00000</div>

        </div>

    </form>

    <script language=«javascript»>

        function OIHandler() {

            print_call_stack(); alert(‘input detected…’);}

        function print_call_stack() { console.trace(); }

        function TAlert() { setIB(document); }

        function setIB() {

            try {

            var inputBox = document.querySelector(‘div.OF_input-box_Xk input’);

            inputBox.value = 50;

    if (document.createEvent) { var ev2 = document.createEvent(«HTMLEvents»);

    ev2.initEvent(«input», true, true); ev2.eventName = «input»;

    inputBox.dispatchEvent(ev2); }

            return ({ success: true });   }

            catch (ex) {

               return ({ exception: ex, myMsg: ‘#error in setIB!’ });

            }

        }

    </script>

</body>

</html>

Измените расширение файла на Code3.htm. В Проводнике дважды кликните на файле. Он откроется в Chrome:

Рис. 38. Локальная страница с окном сообщения, вызванным событием ввода

Кликните на кнопку в левом верхнем углу. Появится окно для подтверждения действия. Нажмите Ok. Значение в поле Amount изменится. Щелчок по стрелкам вверх и вниз, появляющимся при наведении курсора мыши на поле Amount, изменяет его значение. Любые действия ввода приводят к появлению окна сообщения Подтвердите действие.

Рис. 39. Изменение значения ввода

Следующий VBA выполняет функцию настройки, содержащуюся в файле Code3.htm. Это приводит к запуску нового окна Chrome и открытию файла Code3.htm, а затем к его закрытию. Укажите вашу папку, где вы разместили файл Code3.htm. Если вы хотите, чтобы загруженная веб-страница оставалась открытой после завершения выполнения кода, объявите переменную веб-драйвера вне подпрограммы. Т.е., разместите первую строку кода в отдельном модуле. Если переменная объявлена внутри подпрограммы, память освобождается, когда код заканчивается и страница автоматически закрывается.

Public d As WebDriver

Public Sub Exec()

Dim url$

url = Environ(«USERPROFILE») & _

«DocumentsENSExcel & VBAWeb STPpage_w_JS.htm»

Set d = New ChromeDriver

With d

    .Start «Chrome»

    .get url

    .Wait 1000

    .ExecuteScript («setIB()»)

End With

End Sub

Iframes и перенос таблиц без цикла

Iframes – это встроенные элементы HTML, которые можно использовать для включения содержимого с других страниц в текущую страницу. Допустим, вам нужно программно ввести фрейм, чтобы получить доступ к его элементам. Например, цель состоит в том, чтобы перенести приведенную ниже веб-таблицу на рабочий лист Excel. Понаблюдайте за HTML-кодом, чтобы увидеть, что таблица находится внутри фрейма, который, в свою очередь, вложен в родительский фрейм. Следовательно, код должен ввести два фрейма, чтобы получить нужную таблицу.

Помните, как в главе 3 наш макрос мучительно перебирали строки и столбцы, чтобы получить таблицу с флагами? У Selenium есть классный метод, который скопирует таблицу за один проход!

Рис. 40. Сайт с нужной таблицей

Рис. 41. Исходный html-код

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

Public d As WebDriver

Public Sub Table_no_loop()

Dim col As Object, i%, col2 As Object, s$, col3 As Object

Const url As String = «http://intrinsicedge.blogspot.com/»

Set d = New ChromeDriver

With d

    .Start «Chrome»

    .get url

    .Wait 800

    Set col = d.FindElementsByTag(«iframe»)

    For i = 1 To col.Count

        s = col.item(i).Attribute(«src»)

        If s Like «*docs.google*» Then Exit For

    Next

    .Wait 1000

    .SwitchToFrame col.item(3)

    Set col2 = .FindElementsByTag(«iframe»)

    .SwitchToFrame col2.item(1)

    Set col3 = .FindElementsByTag(«table»)

    .Wait 500

End With

col3.item(1).AsTable.ToExcel _

ThisWorkbook.Worksheets(«table»).[a1]

End Sub

Код открывает Chrome, загружает страницу и создает коллекцию всех присутствующих Iframes. Затем он находит нужный, используя атрибут scr. После этого входит в первый фрейм, находит дочерний фрейм и переключается на него. Наконец, таблица идентифицируется и копируется с помощью одного оператора:

Рис. 42. Представление данных в Excel

Как и Internet Explorer, Selenium предлагает несколько методов поиска объектов страницы: FindElementbyID, FindElementsbyClass и многие другие. Используйте функцию Intellisense, чтобы просмотреть полный список:

Рис. 43. Использование Intellisense для визуализации доступных опций

Использование XPath для поиска элементов

XPath, XML Path Language – язык запросов к элементам XML-документа. Он реализован в Selenium и может использоваться для навигации по HTML-структуре веб-страницы, поиска любого элемента с помощью определенного синтаксиса. Существует две основные категории XPath:

  • Абсолютный: это полный путь для элемента, начиная с корневого элемента. Недостатком этой категории является то, что она может быть довольно длинной и более подвержена сбою при изменении структуры HTML DOM (Document Object Model). Вы можете распознать абсолютный путь по начальной единственной прямой косой черте.
  • Относительный: эта ссылка начинается где-то в середине структуры DOM. Относительный XPath начинается с двойной прямой косой черты и обычно является предпочтительным вариантом.

DOM – это API для документов HTML и XML. Он обеспечивает структурное представление документа, позволяя изменять его содержимое и визуальное представление с помощью языка сценариев, такого как JavaScript. Для наших целей думайте о DOM как о виртуальном представлении структуры веб-страницы в виде дерева со всеми ее объектами, стилями, содержимым и событиями. Вот шаги, чтобы получить XPath для элемента страницы:

  • Щелкните правой кнопкой мыши интересующий объект страницы (1) и выберите Просмотреть код (2)
  • Когда исходный код появится в правом окне, строка, относящаяся к интересующему объекту будет подсвечена. Щелкните на ней правой кнопкой мыши (3)
  • Пройдите по меню Copy (4) –> Copy XPath (5)
  • Информация о XPath скопирована в буфер обмена. Для нашего примера она выглядит так: //*[@id=»Blog1″]/div/div/div/div/div[1]/h3/a

Рис. 44. Получение XPath для элемента страницы

Предложенный ниже код делает следующее:

  • Открывает финансовый сайт и заполняет учетные данные для входа на него, беря их из ячеек рабочего листа В85 и В86.
  • Получает дескриптор для кнопки всплывающего окна и нажимает на нее, чтобы закрыть всплывающее окно.
  • Переходит на личную страницу автора на этом сайте; результат представлен на рис. 45.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

Public driver As New ChromeDriver

Sub Filling_Fields()

Dim pt As WebElement, ac As WebElement

driver.get «https://www.investing.com/portfolio/»

Application.Wait Now + TimeValue(«0:00:04»)

Set pt = driver.FindElementByXPath _

(«//*[@id=»«loginFormUser_email»«]»).SendKeys _

(CStr(Sheets(«test»).[b85]))

Set pt = driver.FindElementByXPath _

(«//*[@id=»«loginForm_password»«]»).SendKeys _

(CStr(Sheets(«test»).[b86]))

Set pt = driver.FindElementByXPath(«//*[@id=»«signup»«]/a»)

DoEvents

get popup button

Set ac = driver.FindElementById(«onetrust-accept-btn-handler»)

ac.Click

DoEvents

pt.Click

Application.Wait Now + TimeValue(«0:00:03»)

Set pt = driver.FindElementByXPath _

(«//*[@id=»«navMenu»«]/ul/li[9]/a»)

pt.Click: DoEvents

Application.Wait Now + TimeValue(«0:00:02»)

End Sub

Рис. 45. Вход в систему с помощью кода

Глава 6. Microsoft Edge и VBA

Microsoft разработала одиннадцать версий Internet Explorer с 1995 по 2013 год. Затем они объявили, что Internet Explorer 11 станет последним в этой линейке, и начали фокусироваться на Edge. Хорошей новостью для пользователей IE является то, что он является частью Windows 10; поэтому, если у вас есть какое-то приложение, которое использует определенные функции IE 11, нет причин для немедленного беспокойства. Следующая большая новость появилась в 2019 году, когда стало известно, что эта начальная версия Edge, часто называемая Edge HTML, была заменена новой версией Edge на основе Chromium. Т.е. они используют ту же реализацию с открытым исходным кодом, которая является основой для Google Chrome, Opera и других менее известных браузеров. Вы можете визуально распознать семейство Microsoft, как показано ниже:

Рис. 46. Браузеры Microsoft на протяжении последних лет

Поскольку я не использую Edge, то для начала скачал версию 90 со страницы Microsoft. Далее необходимо обновить драйвер Selenium. Проверьте версию Edge и тип операционной системы, и загрузите драйвер с этой страницы. Найдите папку с элементами Selenium – C:UsersСергейAppDataLocalSeleniumBasic. Удалите файл edgedriver.exe. Поместите в эту папку загруженный драйвер и переименуйте его в edgedriver.exe. Мы готовы к первому примеру этой главы.

Поиск элементов с помощью селекторов CSS

Еще один способ найти элемент веб-страницы – это селектор CSS. CSS – это язык, используемый для применения стилей к странице.

Рис. 47. Ссылка на два конкретных элемента веб-страницы

Допустим, вы хотите заполнить поле поиска на этом веб-сайте, и нажать кнопку поиска, чтобы получить результаты. Обратите внимание, что поле имеет входной тег, в то время как кнопка имеет тег кнопки. Поскольку поле ввода имеет уникальный идентификатор, на него можно ссылаться напрямую. Кнопка, с другой стороны, не имеет идентификатора, поэтому она идентифицируется по пути DOM, начиная с элемента формы. Когда код завершает выполнение, на вкладке Edge отображаются результаты поиска по выбранному объекту.

Чтобы узнать, что такое CSS-селектор для конкретного элемента, выполните те же действия, описанные в главе Chrome, чтобы получить XPath, но вместо этого выберите опцию Copy selector. Для кнопки это: #search-block-form > div > div > div.input-group > span > button.

Public driver As New EdgeDriver

Private Sub Use_Edge()

Dim e As WebElement

driver.get «https://www.seleniumeasy.com»

driver.Wait 3000

Set e = driver.FindElementByCss(«#edit-search-block-form—2»)

If e.IsDisplayed Then

    e.SendKeys («css»)              ‘ write search string

    Set e = driver.FindElementByCss _

    («#search-block-form > div > div >» & _

    » div.input-group > span > button»)

    driver.Wait 1000

    e.Click

End If

driver.Quit

End Sub

У меня этот код не заработал((

Загрузка файла

Обычная задача при работе в Интернете – загрузить файл. Для этого существуют эффективные методы, такие как клиенты FTP (протокол передачи файлов) или P2P (одноранговые) системы. Однако вы можете столкнуться с веб-сайтом, где единственным способом загрузки является щелчок по значку. В следующем примере показано, как автоматизировать этот процесс.

Рис. 48. Определение адресов файлов

На рисунке показана часть исходного кода HTML страницы. Каждый файл Excel имеет свой адрес, содержащийся в атрибуте href, поэтому все, что нам нужно сделать, это использовать эту информацию для загрузки.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

Public ed As New EdgeDriver

Public Sub Dload()

Dim col, i%, s$, p$, v

ed.get «https://www.wisdomaxis.com/technology/» & _

«software/data/for-reports/»

ed.Wait 2000

Set col = ed.FindElementsByTag(«a»)

For i = 1 To col.Count

    s = col.item(i).Attribute(«href»)

    If s Like «*Refresh*» Then Exit For     ‘ desired file

Next

ed.SetProfile «Download», persistant:=True

ed.SetPreference «browser.download.folderList», 2

ed.SetPreference «browser.helperApps.neverAsk.saveToDisk», _

«application/vnd.ms-excel, application/msword,» & _

» application/msexcel,» & _

» application/xls, application/csv, text/csv,» & _

» application/pdf, text/html, text/plain»

ed.SetPreference «browser.download.manager.showWhenStarting», 0

ed.SetPreference «browser.download.manager.focusWhenStarting», 0

ed.SetPreference «browser.download.useDownloadDir», True

ed.SetPreference «browser.helperApps.alwaysAsk.force», False

ed.SetPreference «browser.download.manager.alertOnEXEOpen», False

ed.SetPreference «browser.download.manager.closeWhenDone», True

ed.SetPreference «browser.download.manager.showAlertOnComplete», 1

ed.SetPreference «browser.download.manager.useWindow», False

ed.SetPreference «pdfjs.disabled», True

ed.get s                                        ‘ download file

p = Split(Environ$(41), «=»)(1) & «downloads» ‘ build path

v = Split(s, «/«)

Workbooks.Open p & Replace(v(UBound(v)), «%20«, « «)

ed.Window.Maximize

Workbooks(Workbooks.Count).Activate

End Sub

Этот код:

  • Создает коллекцию элементов с тегом <a>
  • Организует цикл, чтобы найти нужный файл
  • Устанавливает несколько настроек загрузки
  • Загружает и открывает книгу

Если вы хотите открыть Microsoft Edge без установки Selenium, следующий небольшой код позволит вам это сделать. Обратите внимание, что нет необходимости знать путь установки Edge.

Sub ShellEdge()

VBA.Shell Environ$(comspec) & » /c start microsoft-edge:» & _

«http://www.mrexcel.com»

End Sub

Создание PDF-файла с нуля

Допустим, вы хотите каталогизировать несколько веб-страниц в формате PDF для последующего анализа. В следующем примере показано, как создать файл.

  • Код использует массив для хранения поисковых запросов, которые будут переданы в Google. В качестве альтернативы можно получать информацию из диапазона ячеек Excel.
  • Код использует атрибут заголовка поля ввода; эта строка будет отличаться в зависимости от вашего языка. На рисунке ниже показано, как это выглядит для португальской версии автора.
  • Макрос использует цикл создавая новую вкладку Google для каждого элемента. После выполнения поиска будет сделан снимок экрана и добавлен в PDF-файл. В конце файл сохраняется на диск.

Рис. 49. Код HTML для поля поиска Google, русская версия

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

Public Sub CreatePDF()

Dim ed As EdgeDriver, arr(), i%, pdf As Object

Set ed = New EdgeDriver

Set pdf = CreateObject(«Selenium.PdfFile»)

pdf.SetPageSize 210, 300, «mm»

pdf.SetMargins 5, 5, 5, 15, «mm»

arr = Array(«burj khalifa», «petronas towers»)

With ed

    .Start «edge»

    .get «https://google.com/»

    For i = LBound(arr) To UBound(arr)

        If Not IsEmpty(arr(i)) Then

            If i > 0 Then

                .ExecuteScript «window.open(arguments[0])», _

                «https://google.com/»

                .SwitchToNextWindow

            End If

            .FindElementByCss(«[title=Pesquisar]»).SendKeys _

            arr(i) & » images»

            .SendKeys .keys.Enter

            pdf.AddImage .TakeScreenshot, True

        End If

    Next

End With

pdf.SaveAs «c:tempseleniumarch.pdf»

Stop

End Sub

Рис. 50. Этот PDF-файл был создан макросом из Excel

Оболочка Selenium

Как вы, возможно, уже заметили, не имеет значения, какой браузер мы используем с Selenium, поскольку его дерево свойств и методов одно и то же. Последний фрагмент кода VBA иллюстрирует это; все три браузера открываются с одинаковыми операторами. Выбранный сайт – это еще один сайт, на котором Internet Explorer больше не может работать хорошо…

Public ed As New EdgeDriver

Public cr As New ChromeDriver

Public ie As New IEDriver

Sub Choice()

Dim url$

url = «http://www.startrek.com»

Select Case InputBox(«1 — Edge / 2 — Chrome / 3 — IE», _

«Select a browser:»)

    Case 1: ed.get url

    Case 2: cr.get url

    Case 3: ie.get url   does not load completely

End Select

End Sub

Глава 7. Power Query и Интернет

Мы живем в эпоху бизнес-аналитики, и Power Query является частью пакета инструментов BI от Microsoft. Он позволит извлекать данные из различных источников, включая Интернет, изменять их и переносить готовый продукт на рабочий лист Excel. Для Excel 2010 и 2013 Power Query был надстройкой; начиная с Excel 2016 и далее, это встроенный ресурс. Примеры в этой главе будут основаны на Excel 365.

Простое подключение к веб-таблице

В первом примере мы увидим простую процедуру создания соединения с данными, хранящимися на веб-странице.

Шаг 1. В Excel пройдите по меню Данные –> Из Интернета:

Рис. 51. Запуск Power Query

Шаг 2. Вставьте адрес веб-страницы в диалоговое окно и нажмите Ok. Автор использовал страницу Вики с результатами соревнований

Рис. 52. Запрос в странице https://en.wikipedia.org/wiki/Athletics_at_the_2013_Mediterranean_Games_%E2%80%93_Results

Если вы первый раз обращаетесь к Википедии, появится запрос об уровне доступа:

Рис. 53. Уровень доступа

Оставьте установку по умолчанию – Анонимно. Нажмите Подключение. При последующих обращениях к Википедии это окно не будет появляться.

Шаг 3. В окне Навигатора отобразятся все доступные таблицы. Я выбрал таблицу 5000 metres. В правой части окна отобразилось содержимое таблицы. Видно, что это результаты женского финала в беге на 5000 м. Нажмите Преобразовать данные:

Рис. 54. Окно Навигатора

Откроется окно Редактор Power Query:

Рис. 55. Окно редактора Power Query

Шаг 4. Важно понимать, что, хотя у вас есть лента, строка формул, строки и столбцы с данными и язык программирования (называемый M), Power Query – это не Excel. Это два разных приложения, но они очень тесно взаимосвязаны друг с другом.

Как вы видите на рис. 55, данные уже есть, но они требуют обработки. Удалите столбцы Ранг и Примечания. Для этого выделите столбец, который вы хотите удалить, и на вкладке Главная нажмите кнопку Удалить столбцы. Или кликните на столбец правой кнопкой мыши, и выберите Удалить. Можно также удалить столбцы, которые не выбраны. Для выделения нескольких столбцов выделяйте их при нажатой клавише Ctrl. Чтобы выделить диапазон столбцов, кликните на первом, нажмите Shift, и кликните на последнем.

Шаг 5. Добавьте столбец, чтобы отразить место спортсмена. Для этого на вкладке Добавить столбец выберите Столбец индекса > От 1. После вставки перетащите его по строке заголовка влево. Таблица готова для экспорта в Excel.

Рис. 56. Таблица обработана в Power Query

Шаг 6. Выберите Файл > Закрыть и загрузить в…, чтобы определить, куда следует поместить данные:

Рис. 57. Опции загрузки запроса в книгу Excel

Нажмите Ok. Запрос будет помещен в умную таблицу на текущий лист, начиная с ячейки А1:

Рис. 58. Лист Excel с данными из запроса

Запрос построен и может быть обновлен в любое время; описанные выше шаги повторять не нужно.

Обходной путь подключения к веб-таблице

Power Query – развивающийся продукт, но пока он не может автоматически обнаруживать все таблицы на веб-странице. Иногда мы вообще не получаем таблиц при открытии диалогового окна Навигатор. Однако есть обходной путь, предложенный Microsoft MVP Gil Raviv. Мы можем вручную находить и импортировать данные.

В следующем примере мы пройдем по HTML-структуре страницы, пока не найдем нужную таблицу. На самом деле, Power Query находит эту таблицу в автоматическом режиме, но мы сделаем вид, что не находит, чтобы потренироваться.

Шаг 1. Начините, как в предыдущем примере: Данные –> Из Интернета. Укажите страницу подключения: https://climatedata.eu/climate.php?loc=szxx0038&lang=en

Рис. 59. Сайт для запроса таблицы

Оставьте уровень доступа Анонимно, выберите для подключения Document. Нажмите Преобразовать данные, чтобы загрузить Редактор Power Query. Идея состоит в том, чтобы кликать правильные узлы в столбце Children для перемещения по дереву HTML к нужным данным. Вот как выглядит HTML-код. Здесь также указаны некоторые из шагов, упомянутых ниже. Целевая таблица подсвечивается слева.

Рис. 60. HTML-код страницы

Выполняя следующие шаги, сравнивайте их с приведенным выше HTML-кодом, чтобы лучше понять процедуру:

  1. Щелкните ссылку на таблицу Table в единственной доступной строке.
  2. Щелкните Table во второй строке (элемент BODY).
  3. Щелкните Table в первой строке (элемент DIV).
  4. Щелкните Table во второй строке (элемент DIV).
  5. Щелкните Table в третьей строке (элемент DIV).
  6. Щелкните Table в третьей строке (элемент DIV).
  7. Щелкните Table в первой строке (элемент TABLE), Это уже наша таблица!
  8. Щелкните Table на единственной доступной строке, которая является элементом TBODY.
  9. На данный момент у нас уже есть шесть строк таблицы; теперь разверните столбец Children, щелкнув две маленькие стрелки, обращенные друг к другу в заголовке таблицы. В диалоговом окне снимите флажки с других столбцов, так как нам не нужно их разворачивать (рис. 63). Снимите флажок Использовать исходное имя столбца, как префикс.

Рис. 61. Шаги с первого по пятый

Рис. 62. Шаги с шестого по девятый

Рис. 63. Настройки окна Развернуть

Power Query показывает 42 одинаковые строки:

Рис. 64. Очередной шаг обработки

Разверните столбец Children1. Для раскрытия укажите только поле Text:

Рис. 65. Настройки второго окна Развернуть

Наши данные отобразятся, правда все в одном столбце:

Рис. 66. Столбец Text после команды Развернуть

Удалить все столбцы, кроме столбца Text.1. На вкладке Добавить столбец выберите Столбец индекса –> От 0:

Рис. 67. Добавлен столбец индекса

На вкладке Преобразование выберите Стандартный –> Остаток от деления. Когда появится диалоговое окно, введите число 7, которое является числом строк в исходной таблице:

Рис. 68. Преобразование индекса в остаток от деления на 7

На вкладке Добавить столбец выберите Столбец индекса –> От 0. Добавится второй столбец индекса. Снова перейдите на вкладку Преобразование, но теперь выберите Стандартный –> Целочисленное значение. Снова введите число 7:

Рис. 69. Второй индекс показывает целое от деления на 7

Выберите столбец Индекс и на вкладке Преобразование щелкните Столбец сведения. Когда появится диалоговое окно, выберите следующие параметры:

Рис. 70. Параметры сведения

Нажмите кнопку Оk. Далее удалите столбец Индекс.1. Пройдите по меню Главная –> Использовать первую строку в качестве заголовков. Присвойте первому столбцу имя Параметр. Ваш запрос принял нужный формат, и его можно загрузить!

Рис. 71. Обработанный запрос

Выберите Файл > Закрыть и загрузить в…, укажите Таблица на Имеющийся лист, как на рис. 57.

Рис. 72. Умная таблица на листе Excel, созданная запросом

Заключение

Excel и Интернет – две быстро развивающиеся динамические сущности, а эта небольшая книга способна показать вам интересные возможности, и придать импульс, чтобы вы начали заниматься этой увлекательной темой подробнее. Последний совет: вполне вероятно, что в какой-то момент вы застрянете при разработке своих проектов. Если это произойдет, подумайте о том, чтобы обратиться за помощью на веб-форумы, таких как MrExcel Message Board или Stack Overflow (есть на русском). Там вы найдете знающих людей, которые всегда готовы помочь. Удачи!

I have access to an API. The API takes an XML post as input and then returns an XML response with the relevant data.

I want to

  1. Send the HTTP Post to the Server (Authentication and Request will be sent together)
  2. Receive the response (One of the options to be returned is CSV or XML)
  3. Insert the data into the appropriate rows and columns and then perform data analysis using pivot tables.

I don’t have a programming background in excel but am comfortable with different web scripting languages, HTML, CSS, Javascript etc.

Any ideas?

Community's user avatar

asked Nov 30, 2009 at 15:03

Scott's user avatar

The Excel request side can be handled with this VBA code.

Sub GetStuff()

Dim objXML As Object
Dim strData As String
Dim strResponse As String

 strData = "Request"
 Set objXML = CreateObject("MSXML2.XMLHTTP")

 objXML.Open "POST", "www.example.com/api?" & strData, False
 objXML.Send
 strResponse = objXML.responsetext

MsgBox strResponse

End Sub

answered Nov 30, 2009 at 18:26

Robert Mearns's user avatar

Robert MearnsRobert Mearns

11.8k3 gold badges38 silver badges42 bronze badges

If you need to send your input xml as the message body here is how you can do it.
You may need to add more or change the Request headers to get it to work for you.

Using the DOMDocument object make it easy to work with your xml documents.

Add a project references to;

  • Microsoft WinHTTP Services, version 5.1
  • Microsoft XML, v6.0

Example:

Dim xmlInput As String
xmlInput = "<YourXmlRequest></YourXmlPayload>"

Dim oXmlHttp As MSXML2.XMLHTTP60
Set oXmlHttp = New MSXML2.XMLHTTP60

oXmlHttp.Open "POST", serviceURL, False, "UserName", "Password"
oXmlHttp.setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
oXmlHttp.setRequestHeader "Connection", "Keep-Alive"
oXmlHttp.setRequestHeader "Accept-Language", "en"

oXmlHttp.send xmlInput

Debug.Print oXmlHttp.responseText

Dim oXmlReturn As MSXML2.DOMDocument60
Set oXmlReturn = New MSXML2.DOMDocument60
oXmlReturn.loadXML oXmlHttp.responseText

answered Dec 2, 2009 at 14:03

Andrew's user avatar

AndrewAndrew

9677 silver badges8 bronze badges

2

This is what I ended up using:

Set objHTTP = CreateObject("MSXML2.ServerXMLHTTP")
objHTTP.Open "POST", urlPath, False
objHTTP.setRequestHeader "Content-Type", "text/xml"
objHTTP.send (request)

answered Dec 18, 2009 at 21:47

Scott's user avatar

ScottScott

8874 gold badges12 silver badges24 bronze badges

I suggest to use WinHttp.WinHttpRequest.5.1 instead of MSXML2.XMLHTTP whenever you need windows authentication, because it allows you to use current user credential to login. Here is an example

Dim http As Object
Set http = CreateObject("WinHttp.WinHttpRequest.5.1")
http.SetAutoLogonPolicy 0
http.Open "POST", "http://myUrl.html?param1=value1", False
http.setRequestHeader "Content-Type", "text/json"
http.setRequestHeader "User-Agent", "Mozilla/5.0 (iPad; U; CPU OS 3_2_1 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Mobile/7B405"
http.send ("")

Reference: https://github.com/VBA-tools/VBA-Web/issues/15

answered Oct 4, 2017 at 7:14

Naigel's user avatar

NaigelNaigel

8,85615 gold badges68 silver badges105 bronze badges

 

Arfonit

Пользователь

Сообщений: 5
Регистрация: 20.11.2019

#1

20.11.2019 13:52:25

Добрый день!

Подскажите, пожалуйста, как авторизироваться на сайте из-под Excel через msxml2.xmlhttp? Перечитал, наверное, все форумы, ответа так и не нашел, точнее нашел, но не понимаю какому заголовку передавать значения.

Прошу подсказать как заставить макрос авторизироваться. Спасибо.
Код вкратце получился такой, где URL = «

https://provagon.com»

;, а заголовок Authorization взят из одного из примеров, найденных на форумах. Поля login и Password заданы корректно, и в ручную с их помощью можно пройти авторизацию.

Код
...
With oHttp
   .Open "get", URL, False, login, Password
   .setRequestHeader "Authorization", "Basic " + login + ":" + Password
   .send
   arr = Split(.responsetext, vbLf)
'   MsgBox .getAllResponseHeaders()
End With
....

Изменено: Arfonit20.11.2019 13:52:37

 

doober

Пользователь

Сообщений: 2201
Регистрация: 09.04.2013

#2

20.11.2019 14:11:40

Информация для размышления.

Скрытый текст

<#0>

 

Arfonit

Пользователь

Сообщений: 5
Регистрация: 20.11.2019

#3

20.11.2019 14:24:40

Цитата
doober написал:
Информация для размышления.

doober

, спасибо за наводку. Однако, мне явно не хватает знаний, чтобы сообразить что к чему.

Правильно ли я понял, что:
1. В качестве URL должна быть указана ссылка на страницу с авторизацией?
2. Я должен в SiteID вместо «Ник» и «Пароль» подставить свои значения и отправить эту строку запросом?
3. В чем отличие методов get от post? Где можно подробнее про них почитать?
4. Я могу как-то проверить, что авторизация на сайте прошла успешно?

В целом буду рад советам, где почитать побольше про эту функцию.

 

Игорь

Пользователь

Сообщений: 3631
Регистрация: 23.12.2012

Вы нашли где-то кусок кода для авторизации, но у вас не тот случай
В вашем случае (как и на 99% сайтов) авторизацию надо выполнять POST запросом
пример кода можно посмотреть здесь:

https://excelvba.ru/code/atsenergo_login

видеоинструкция, где посмотреть в браузере, какие данные нужны для POST запроса:

https://www.youtube.com/watch?v=4bRwPIX8Wc0&feature=youtu.be&t=568

 

Arfonit

Пользователь

Сообщений: 5
Регистрация: 20.11.2019

Игорь, спасибо большое! Все получилось!

 

Arfonit

Пользователь

Сообщений: 5
Регистрация: 20.11.2019

#6

27.11.2019 15:28:06

Добрый день!

К сожалению, вынужден опять вернуться к этому вопросу.

Иногда при попытке авторизоваться выдает такую ошибку (Сбой скачивания указанного ресурса).

Вот часть кода, в котором ошибка (на строке с .Send).

Код
PostData = "username=" & login & "&password=" & Password
'авторизация на сайте
With oHttp
   .Open "post", URL_autorization, False
   .send PostData
End With

Подскажите, пожалуйста, с чем она может быть связана?

Изменено: Arfonit27.11.2019 15:32:24

 

Игорь

Пользователь

Сообщений: 3631
Регистрация: 23.12.2012

#7

27.11.2019 20:47:39

надо не кусок кода показывать, а макрос целиком
как у вас создается объект oHttp?
так?

Код
 oHttp = CreateObject("MSXML2.XMLHTTP")

а надо так:

Код
 oHttp = CreateObject("WinHttp.WinHttpRequest.5.1")
 

Arfonit

Пользователь

Сообщений: 5
Регистрация: 20.11.2019

#8

28.11.2019 09:52:04

Цитата
Игорь написал:
а надо так:Код ? 1oHttp = CreateObject(«WinHttp.WinHttpRequest.5.1»)

Игорь, спасибо за ответ.

Поправил объявление как Вы сказали, однако теперь я получаю другую ошибку: «Время ожидания операции истекло».

Я пробовал использовать метод .SetTimeouts с различными значениями, однако и это не помогло. Ошибка появляется на той же строчке .send PostData.

Подскажите, пожалуйста, в какую сторону копать?

Код выглядит так:

Код
Sub Парсер()

Set oHttp = CreateObject("WinHttp.WinHttpRequest.5.1") 
Set objRegExp = CreateObject("VBScript.RegExp") 

URL = "https://provagon.com/rolling%20stock"
URL_autorization = "https://provagon.com/web/CloseSitePS.nsf?Login"
login = "****"
Password = "****"
Chapter_to_find = "****"
PostData = "username=" & login & "&password=" & Password

With oHttp
   .Open "post", URL_autorization, False
   .send PostData
End With

end sub 

shavka

132 / 15 / 2

Регистрация: 27.11.2013

Сообщений: 509

1

20.01.2018, 15:58. Показов 12880. Ответов 14

Метки нет (Все метки)


Студворк — интернет-сервис помощи студентам

Дали мне тут один кодик симпотный

Visual Basic
1
2
3
4
5
6
7
8
9
Sub GetHTTPResponse()
     Set oXMLHTTP = CreateObject("MSXML2.XMLHTTP")
     With oXMLHTTP
         .Open "GET", "https://www.cyberforum.ru/vba/thread2174329.html", False
        .send
         MsgBox .responseText
     End With
     Set oXMLHTTP = Nothing
End Sub

Но толку от MsgBox мало. Надо бы в лист эксель запихать. Я пытался, как все чайники, вот так

Visual Basic
1
ThisWorkbook.Sheets("Лист2").Range("A1") = oXMLHTTP

не вышло. Более идей нету. Помогите плз.



0



Остап Бонд

Заблокирован

20.01.2018, 16:03

2

Цитата
Сообщение от shavka
Посмотреть сообщение

MsgBox

ThisWorkbook.Sheets(«Лист2»).Range(«A1») = .responseText



1



132 / 15 / 2

Регистрация: 27.11.2013

Сообщений: 509

20.01.2018, 17:05

 [ТС]

3

Остап Бонд, ну надо же! Точку не поставил, и процесс нейдеть.

А он мне все в одну ячейку и запихал. Можно как-нить по столбцам разнести?



0



Остап Бонд

Заблокирован

20.01.2018, 18:08

4

Лучший ответ Сообщение было отмечено shavka как решение

Решение

Цитата
Сообщение от shavka
Посмотреть сообщение

Можно как-нить по столбцам разнести?

По какому принципу?
И может лучше по строкам?

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
Sub GetHTTPResponse()
     Set oXMLHTTP = CreateObject("MSXML2.XMLHTTP")
     With oXMLHTTP
         .Open "GET", "https://www.cyberforum.ru/vba/thread2174329.html", False
        .send
        a = Split(.responseText, vbCrLf)
     End With
     Set oXMLHTTP = Nothing
     For r = 0 To UBound(a)
      Cells(r + 1, 1) = a(r)
     Next
End Sub



1



132 / 15 / 2

Регистрация: 27.11.2013

Сообщений: 509

20.01.2018, 18:28

 [ТС]

5

Остап Бонд, блин круто! Оно и по строкам можно. Эксель же по столбцам умеет разносить. Просто если таблица с цифрами будет, хотелось бы табличный вид и заиметь в листе. Ну вот например отсуда:
http://www.moex.com/ru/derivat… =GOLD-3.18
Разделители запятые

Добавлено через 13 минут
кстати, измена! вот по этой ссылке с Мамбы тоже все в одну ячейку сует.



0



Остап Бонд

Заблокирован

20.01.2018, 18:43

6

Лучший ответ Сообщение было отмечено shavka как решение

Решение

Пробуй —

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Sub GetHTTPResponse()
     Set oXMLHTTP = CreateObject("MSXML2.XMLHTTP")
     With oXMLHTTP
         '.Open "GET", "https://www.cyberforum.ru/vba/thread2174329.html", False
         .Open "GET", "http://www.moex.com/ru/derivatives/contractresults-exp.aspx?day1=20171214&day2=20180315&code=GOLD-3.18", False
        .send
        a = Split(.responseText, vbLf)
     End With
     Set oXMLHTTP = Nothing
     For r = 0 To UBound(a)
      aa = Split(a(r), ",")
      For c = 0 To UBound(aa)
        Cells(r + 1, c + 1) = aa(c)
      Next
     Next
End Sub

Первая строка криво вставилась. Причину вижу — ковыряться лень.



1



shavka

132 / 15 / 2

Регистрация: 27.11.2013

Сообщений: 509

21.01.2018, 22:36

 [ТС]

7

Остап Бонд, первая строчка — хрен бы с ней, не важна. Я так понимаю, там с разделителями надо покопаться. Круто, до чего дошел прогресс! А я правильно понимаю, вот эта строчка

Visual Basic
1
a = Split(.responseText, vbLf)

— это объект oXMLHTTP берется в одномерный массив?



0



Остап Бонд

Заблокирован

21.01.2018, 22:55

8

Не объект oXMLHTTP, а строка, которую этот объект вернул.



0



AlexSmel

35 / 32 / 15

Регистрация: 23.12.2014

Сообщений: 97

21.01.2018, 23:42

9

to Остап Бонд,
Там формат первой строки очень напрашивается на применение «регулярных выражений», которых в Excel-e «из коробки», к сожалению, нет. Ну, только если «цеплять» библиотеку Microsoft VBScript Regular Expressions. Я с ней еще не работал, поэтому мне пока легче «прицепиться» к Word-у, у которого, по-умолчанию есть «подстановочные знаки»:

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
Sub Макрос1()
Dim wdApp As Object
Dim wdDoc As Object
Dim exSht As Object
    Set oXMLHTTP = CreateObject("MSXML2.XMLHTTP")
        With oXMLHTTP
            '.Open "GET", "https://www.cyberforum.ru/vba/thread2174329.html", False
            .Open "GET", "http://www.moex.com/ru/derivatives/contractresults-exp.aspx?day1=20171214&day2=20180315&code=GOLD-3.18", False
            .send
            a = Split(.responseText, vbLf)
        End With
        Set oXMLHTTP = Nothing
        Set wdApp = CreateObject("Word.Application")
        Set wdDoc = wdApp.Documents.Add()
        On Error Resume Next
        Set exSht = Sheets("GOLD-3.18")
        If Err.Number = 0 Then
            With exSht
                .Activate
                .Cells.Clear
            End With
        Else
            Worksheets.Add.Name = "GOLD-3.18"
            Set exSht = Sheets("GOLD-3.18")
            exSht.Move After:=Sheets(ActiveWorkbook.Sheets.Count)
        End If
        For r = 0 To UBound(a, 1)
            wdDoc.Range.Text = a(r)
            With wdDoc.Range.Find
                .Forward = True
                .Wrap = wdFindContinue
                .MatchWildcards = True
                .Text = "(""*),(*"")"
                .Replacement.Text = "1;2"
                .Execute Replace:=2
                .Text = """"
                .Replacement.Text = ""
                .Execute Replace:=2
                .Text = ","
                .Replacement.Text = "---"
                .Execute Replace:=2
                .Text = ";"
                .Replacement.Text = ","
                .Execute Replace:=2
            End With
            a(r) = wdDoc.Range.Text
            aa = Split(a(r), "---")
            For c = 0 To UBound(aa)
                exSht.Cells(r + 1, c + 1).Value = aa(c)
            Next
        Next
        exSht.Columns.AutoFit
        exSht = Nothing
        wdDoc.Close False
        Set wdDoc = Nothing
        wdApp.Quit
        Set wdApp = Nothing
End Sub



1



132 / 15 / 2

Регистрация: 27.11.2013

Сообщений: 509

22.01.2018, 01:23

 [ТС]

10

Остап Бонд, а не подскажите, почему я не могу найти MSXML2.XMLHTTP в справке (F1)? И в браузере объектов по кнопке F2?



0



Казанский

15136 / 6410 / 1730

Регистрация: 24.09.2011

Сообщений: 9,999

22.01.2018, 02:43

11

Цитата
Сообщение от AlexSmel
Посмотреть сообщение

Там формат первой строки очень напрашивается на применение «регулярных выражений»

Вообще-то «Текст по столбцам» отлично справляется

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
Sub Макрос1()
Dim exSht As Object, oXMLHTTP As Object, a$()
  Set oXMLHTTP = CreateObject("MSXML2.XMLHTTP")
  With oXMLHTTP
  '.Open "GET", "https://www.cyberforum.ru/vba/thread2174329.html", False
    .Open "GET", "http://www.moex.com/ru/derivatives/contractresults-exp.aspx?day1=20171214&day2=20180315&code=GOLD-3.18", False
    .send
    a = Split(.responseText, vbLf)
  End With
  Set oXMLHTTP = Nothing
  On Error Resume Next
  Set exSht = Sheets("GOLD-3.18")
  If Err.Number = 0 Then
    With exSht
      .Activate
      .Cells.Clear
    End With
  Else
    Set exSht = Worksheets.Add(After:=Sheets(ActiveWorkbook.Sheets.Count))
    exSht.Name = "GOLD-3.18"
  End If
  With exSht.Cells(1, 1).Resize(UBound(a) + 1)
    .Value = WorksheetFunction.Transpose(a)
    .TextToColumns Destination:=.Range("A1"), DataType:=xlDelimited, _
        TextQualifier:=xlDoubleQuote, ConsecutiveDelimiter:=False, Tab:=False, _
        Semicolon:=False, Comma:=True, Space:=False, Other:=False, FieldInfo:=Array(1, 4) 'первый столбец Дата, ост. по умолчанию
    .Range("B2", .Cells(.Rows.Count, "H")).Replace ".", ".", xlPart 'превратить запись чисел с разделителем точка в числа
  End With
  exSht.Columns.AutoFit
End Sub



2



35 / 32 / 15

Регистрация: 23.12.2014

Сообщений: 97

22.01.2018, 09:16

12

to Казанский,
Чтобы воспользоваться функцией «Текст по столбцам», нужно как минимум, знать о ней. Теперь я знаю . Интересно работают «Символ-разделитель» и Ограничитель строк». Не сразу въехал в параметр FieldInfo (откуда ж я знал, что Data=4, Text=2 и т.п. ) Век живи-век учись… Спасибо!



0



132 / 15 / 2

Регистрация: 27.11.2013

Сообщений: 509

22.01.2018, 12:41

 [ТС]

13

Казанский, а можно как-нить в объект MSXML2.XMLHTT выборочно засунуть информацию из XML? Мне например там нужно всего два столбика, хедер ваще не нужон. Если через АДО, то этот код у меня есть, да и инфы по АДО достаточно. А вот по этому зверю — MSXML2.XMLHTT надергал в инете, полная каша в голове.

Кстати нашел в инете книжку А.А. Казанский — ваша? Умные маркетологи с Литреса дали отрывок для ознакомления, лучше бы содержание написали, в смысле список рассматриваемых тем.



0



Казанский

22.01.2018, 12:57

Не по теме:

Цитата
Сообщение от shavka
Посмотреть сообщение

можно как-нить в объект MSXML2.XMLHTT выборочно засунуть информацию из XML?

Не знаю :pardon:

Цитата
Сообщение от shavka
Посмотреть сообщение

нашел в инете книжку А.А. Казанский — ваша?

Нет



0



132 / 15 / 2

Регистрация: 27.11.2013

Сообщений: 509

22.01.2018, 13:25

 [ТС]

15

Казанский, ну и ладно, не принципиально. А вы не знаете, есть ли разница между Microsoft.XMLHTTP и MSXML2.XMLHTTP?



0



28 Aug Return Stock Data Using Excel VBA

Posted at 12:35h
in Excel VBA
0 Comments

Howdee! Querying data over the web becomes more common every day. Almost every cloud based program has the ability to serve up its data through some sort of API. Sometimes, the data can be extracted to Excel through some sort of reporting interface within the program. However, I’ve found that this functionality is usually difficult to use and/or incredibly slow or doesn’t exist at all. This is where the ability to make an Excel http get request is so valuable.

In my example today I’ll be building a small excel application that will allow the user to search for a company’s ticker and then return the most recent stock data using an http request. To do this, we will use the site http://dev.markitondemand.com/MODApis/Api/v2/doc. It is a free service that provides the ability to search for tickers and company names and then fetch stock data on that entity.

HTTP Basics

Before diving into the technical aspects of an Excel http get request, let’s first explore what http requests are. HTTP stands for “Hypertext Transfer Protocol”. In laymen’s terms, it is a means of communicating between a host and a client.

Let’s assume you type www.facebook.com into a web browser. You, the client, have just initiated an HTTP GET request to Facebook, the host (for thoroughness, it’s worth mentioning that sites like Facebook that contain sensitive information use an HTTPS request to secure the data being transferred). What you’ve sent is called the “Request” and the HTML page that Facebook sends back is the “Response”.

The request is sent using a URL (Uniform Resource Locator). While you might be familiar with URL’s, you might not be familiar with their structure. They consist of these components:

excel http get request

Protocol is usually HTTP but, as I said earlier, HTTPS is used when the connection needs to be secured (personal data, credit card information, etc.). The host is just that, the domain address a host has chosen for you to reach their server. The port is usually not needed to be explicitly typed. The default port is 80 and the URL implicitly sends that if you exclude it. The resource path and the query are the import parts I want to point out.

The resource path is instructions sent to the host that tell the server where to navigate to so that your information can be found. Lastly, the query section is always kicked off with a question mark. This section provides any parameters you want to include as well the option to explicitly list the precise data you want returned.

This is as dep as I’ll go into HTTP since this is enough to get started querying information. However, if you’re planning to develop an application that will make HTTP calls, I recommend reading up on the subject so you can handle several types of responses. Let’s say a user passes a bad request to the program you build; the host will send back an HTTP response but it could be an error 404 response and not include any data. You’ll need to be able to handle that and other issues that could arise. This article on the Mozilla Developer Network is a great place to start.

Excel HTTP Get Request – Creating the Search

Now that we know a little about HTTP, let’s dive into the Excel http request using VBA. To get started open a new Excel file and press alt + F11 to open the VBA editor window. The first thing we need to do is add some library references so we can access the controls we will need to make HTTP calls. Click on “Tools” and then “References” and add a check box to Microsoft Scripting Runtime, Microsoft Internet Controls, and Microsoft WinHTTP Services, version 5.1 as pictured below.

excel http get request

In this application, we want to allow the user the ability to search for a company’s stock ticker. We will then need to pass that data into our code. When my program needs to interact with data on a spreadsheet, I prefer to name the range or cell that it will be interacting with so that, when I’m writing code, it’s evident exactly what data I’m collecting or where I need to write data to. I’ve named a cell “Search_For_Company” and put instructions on the sheet so the user realizes that he/she needs to enter a search term there.

excel http get request

Now, we need to write the code that will accept this input, and then make an http get request to return potential matches. But, before that, let’s consider the returned results. I user might type in “face” when searching for Facebook. That would return dozens of companies so we need somewhere to store those values temporarily. For this, I’ve created a basic user form with a list box to display the values. It looks like this:

excel http get request

Typically I’ll break my code down in to sections to discuss, but I think this makes sense to look at the code in its entirety and then explain what’s happening step by step.

Sub GetCompanyInformation()

Dim hReq As Object, JSON As Dictionary
Dim i As Long
Dim var As Variant
Dim ws As Worksheet

Set ws = Sheet1

'create our URL string and pass the user entered information to it
Dim strUrl As String
    strUrl = "http://dev.markitondemand.com/MODApis/Api/v2/Lookup/json?input=" & ws.[Search_For_Company]

Set hReq = CreateObject("MSXML2.XMLHTTP")
    With hReq
        .Open "GET", strUrl, False
        .Send
    End With

'wrap the response in a JSON root tag "data" to count returned objects
Dim response As String
    response = "{""data"":" & hReq.ResponseText & "}"

Set JSON = JsonConverter.ParseJson(response)

'set array size to accept all returned objects
ReDim var(JSON("data").Count, 1)

i = 1
'loop through returned data and get Symbol & Name
For Each Item In JSON("data")
    var(i, 0) = Item("Symbol")
    var(i, 1) = Item("Name")
    i = i + 1
Next

ufCompaniesReturned.lbCompaniesReturned.List = var

Erase var
Set var = Nothing
Set hReq = Nothing
Set JSON = Nothing

If ufCompaniesReturned.Visible = False Then
    ufCompaniesReturned.Show
End If

End Sub

Let’s skip over the variable declarations as we’ll discuss each as they’re used. The first line simply assigns the “ws” variable to the sheet where I’m working, Sheet1 in this case. Next, I dimension a new string variable (I could have dimensions this variable above with the others but this is just personal preference when I’m creating a variable that represents a URL) and assign the URL I’m using to it. Note here that for the query section of the URL, I’m using a combination of text entered and I’m pulling the value the user typed into the range we named earlier. This is why I like to use that approach in my Excel http get request programs. I can easily see that I’m passing a value from Sheet1 that represents a company to search for.

Next set the Object variable “hReq” equal to a new object in the Microsoft XML Core Services. If you want to read more about what this entails, MSDN has a great write up on it. Suffice it to say this service allows us to send HTTP requests and parse the responses. Now, with that variable we will open a connection and pass it three parameters. We are telling it that we are sending a “GET” request, we pass the URL to use, and lastly, we want to explicitly tell it the call is not asynchronous (also could be said the call is synchronous). This prevents anything further from happening until we get a response from the host. If we left this blank, the default is true. The program could then move on while we are waiting the call and break. There are two more optional parameters in this Open method for username and password, in that order. If that information is required for your request, you’ll need to provide them. They are not required in this example however.

In the next section of code, we create a response variable and store the response from the request as a string. Since this response is returned in JSON, I’m using the VBA-JSON library to parse the JSON. If you’re unfamiliar with this, click here for my blog post on how to use the library. Note that I wrap my response in some additional text. This is a root JSON object that I wrap the data in so I can perform a count on how many objects were returned, which I do in the next step when I’m resizing the array I declared at the beginning of the code.

Lastly we will loop through each object returned by our Excell http get request, and assign the company’s symbol and name to the array. Once the array has been populated, we will pass that array to a listbox, dispose of some resources, and finally check if the form is already visible and, if it isn’t, show it.

excel http get request

Excel HTTP Get Request – Returning the Stock Quote

Now that we’ve successfully written code that will perform our search query, let’s move on to the http get request to return our stock quote. In the form that pops up, our user will select a company for which they want to return a stock quote. Once they click “OK” we will want the result to be returned. To do this, we need to have this process kick off when the event for the button click occurs. To create a sub routine that subscribes to that event, simply double click the “OK” on your user from inside the VBA editor window.

We can certainly embed all the code we want to run inside this event and call it a day. However, I prefer to keep my code separate. I’ve created another module called “Functions” and created a function inside to run my Excel http get request stock quote call when passed the correct parameters. That function looks like this:

Function GetStockData(company As String, companyName As String)
Dim hReq As Object, JSON As Dictionary
Dim sht As Worksheet

Set sht = Sheet1

Dim strUrl As String
    strUrl = "http://dev.markitondemand.com/Api/v2/Quote/json?symbol=" & company

Set hReq = CreateObject("MSXML2.XMLHTTP")
    With hReq
        .Open "GET", strUrl, False
        .Send
    End With

Dim response As String
    response = hReq.ResponseText

Set JSON = JsonConverter.ParseJson(response)
    sht.[Last_Price] = JSON("LastPrice")
    sht.[Change] = JSON("Change")
    sht.[Change_Percent] = JSON("ChangePercent") / 100
    sht.[Quote_Time] = JSON("MSDate")
    sht.[Market_Cap] = JSON("MarketCap") / 1000000
    sht.[Volume] = JSON("Volume")
    sht.[Change_YTD] = JSON("ChangeYTD")
    sht.[Change_YTD_Percent] = JSON("ChangePercentYTD") / 100
    sht.[High] = JSON("High")
    sht.[Low] = JSON("Low")
    sht.[Open] = JSON("Open")
sht.[Search_For_Company].Value = companyName

End Function

As you can see, this code structure is very like the previous code structure so I won’t go through every detail. The first thing you might notice is that this isn’t a subroutine. I’ve made this a function and given it two parameters to receive. I first pass in the “company” parameter which will represent the stock ticker symbol. This is the parameter I pass to the strUrl variable to complete my Excel http get request string. Next, I pass in the company Name parameter which will be the formal name returned from our previous query.

The next difference you might notice is that I don’t wrap the HTTP response like I did previously. Since I know this response will only return one object, I don’t need to count or loop through the response. I can simply parse that response into a dictionary and then access them through the respective keys. Also, I’ve created several more named ranges to write these values to. Again, this is not necessary but I find it helps tremendously with the readability of my code. Lastly, I just assign the formal name I used in the call back to the cell.

To call this function, I used this code in the button click event handler:

Dim i As Long

For i = 0 To ufCompaniesReturned.lbCompaniesReturned.ListCount - 1
    If lbCompaniesReturned.Selected(i) = True Then
        Call GetStockData(lbCompaniesReturned.List(i, 0), lbCompaniesReturned.List(i, 1))
    Else
        'do nothing
    End If
Next i

ufCompaniesReturned.Hide

This code is pretty straight forward. I’m first looping through each item in my list box and checking to see if that item has a selected property of true. If it does, I’m passing the two values in the list box to my GetStockData function. From there, the code is handled by the function in my Functions module. All of this together ends up with this result:

excel http get request

I hope this article showed you the power of being able to make http requests from within an Excel application. You can customize the user experience, pull only the data you need, and it’s very fast. As always, the file I worked with today is available for download if you’re a subscriber to my site. It’s free, easy to sign-up, and I won’t be spamming you with dozens of emails each week. If you have questions on anything I went over, please drop them in the comments section below.

Cheers,

R

This tutorial is for you if you’re an Excel user who would like to learn how to extend your spreadsheets with data from APIs. You might be one of the people who spend most of their workdays in Excel and do calculations and visualizations but still work manually to import or even just copy and paste data from external sources.

If data is available from an API, however, there are various ways in which can consume it directly from Excel, saving you time and preventing errors.

That is, unfortunately, just as long you are using a Windows PC. The integrations presented in this article do not work in Excel for Mac or the web-based version of the Office apps.

BASF provides the Periodic Table of Elements API, which enables you to query the periodic table and retrieve all kinds of information about chemical elements.

We assume you came here from the Introduction to APIs. If not, please check out that document to learn the basics of APIs before continuing.

The Periodic Table of Elements API follows the CRUD/RESTful paradigm but implements only a subset. Specifically, the periodic table is read-only and allows HTTP GET requests exclusively. It is also limited to one resource called «element».

The base URL for the API is https://dev.api.basf.com/chemical/. Every endpoint starts with this URL.

For the elements, there are two endpoints. The first is a collection endpoint that allows you to either retrieve the full periodic table or request a subset of elements through filter parameters. It is called a collection endpoint because it always returns a collection data structure containing multiple items. The second is an individual resource endpoint that allows you to retrieve a single element.

Both endpoints return JSON-formatted responses.

All BASF APIs require authentication. The Periodic Table of Elements API uses an app-only context with an API key. If you haven’t done so, please read the introduction, terminology, and app-only context sections of the Authentication and Authorization guide. You can skip the part on the app and user context and OAuth as it is not required for this API.

To use authentication, you need to create an account and an application. The process gives you a Client ID, which you can then use as your API key. If you do not have an API key, follow the steps outlined in the Get Started guide. Make sure you select the API product BASF Periodic Table while creating your app.

In Excel for Windows, there are three options for getting external data from an API, which we’ll investigate throughout this article.

The first option is the built-in WEBSERVICE() function. Retrieving data from a URL is a single step. However, extracting the information is rather cumbersome as Excel doesn’t understand JSON responses and you have to use string processing functions. Also, as the function only supports the URL as a parameter, this works only with APIs that allow you to provide authentication information as part of the URL. The BASF Periodic Table of Elements API fits the criteria, as it uses a query string for authentication. For other APIs that require custom headers, though, you’re out of luck.

The second option is using VBA, Visual Basic for Applications, to write a Macro in Basic code to consume an API and fill the sheet programmatically. It is the most powerful and flexible option and should work with all kinds of APIs, but it requires you to have some basic programming knowledge.

The third option is the Power Query builder that allows you to gather and combine data from different sources, including APIs. If you have already used the Power Query builder, for example, to access a database directly, this is the sensible way to do it. It’s also a good choice if you do not want to work with code and the WEBSERVICE() option is too limited.

We’ll use an individual resource endpoint with the WEBSERVICE() function as well as the VBA macro, and we’ll demonstrate the collection endpoint with the Power Query builder.

Before we introduce the WEBSERVICE() function, let’s look at functions in Excel in general. They allow you to fill a table cell with computed data. To enter a function into a cell, you start with the equals sign (=), followed by the function name, a left parenthesis [(], your arguments (if needed), and a right parenthesis [)] to end. If there is more than one argument, you separate them with semicolons (;). A common function that you may have used is SUM(), which adds the data from a number of other cells and returns the result. It takes a range of cells as its argument.

The WEBSERVICE() function also takes one argument, a URL. Then, Excel issues an HTTP GET request to fetch whatever is available at that URL, and puts it into the cell as its result. If we want to do an API requests, since the function only allows a single argument, we have to encode the full API request into the URL. As mentioned before, this rules out APIs that require other HTTP methods (such as POST) or custom headers, e.g., for authorization. With the Periodic Table API, however, we put the API key in the URL and only need the GET method.

Open a new Excel workbook, and enter the following line into a cell, replacing the string APIKEY with the previously generated key:

=WEBSERVICE("https://dev.api.basf.com/chemical/elements/He?x-api-key=APIKEY")

Once you hit Enter or click on another cell, you should see a JSON structure describing the Helium element appear in your cell.

As mentioned before, every API endpoint starts with the base URL. For the Periodic Table API, that is https://dev.api.basf.com/chemical/. Then, the path to a resource or collection endpoint follows. In our example, we retrieved a single element, hence, we used a resource endpoint. Typically, the path to a resource starts with the pluralized resource name, followed by a slash (/) and finally an identifier. If you look at the URL above, you can identify elements/He as this path. The question mark (?) separates the parameter section, and you can see the x-api-key parameter that authenticates the request.

We can separate the base URL and the API key from the URL and build the URL dynamically through string concatenation. That is useful if you have multiple requests in the same Excel sheet and, let’s say, you want to share this sheet with another person who then provides a different API key. The other person then only has to enter their API key in one designated cell instead of modifying your API requests.

As next step, we’ll create a sheet that allows users to modify the base URL and API key in one place. We’ll also apply string processing functions to parse a single field from the JSON response. You can follow along these steps. If something is unclear or doesn’t work for you, you can compare your sheet with the screenshots as well as the full Excel workbook that we’ll provide as download further below.

Here we go:

  1. Type «Base URL» in A1 and the base URL https://dev.api.basf.com/chemical/ in B1.
  2. Type «API Key» in A2 and paste your API key from the developer portal in B2.
  3. Type «Element» as a header in A4 and some elements below it. As an example, we’ll put «H» in A5 and «N» in A6.
  4. Type «API URL» as a header in B4. To build the URL, concatenate the following elements: a reference to the field containing the base URL, «elements/», a reference to the field containing the element name, «?x-api-key=», and a reference to the field containing the API key. You need to use absolute references to base URL and API key and a relative reference to the element name. Your function call should look like this: =CONCAT($B$1;»elements/»;A5;»?x-api-key=»;$B$2)
  5. Type «API Response» as a header in C4. Make the webservice call using the URL you built in the previous step by typing =WEBSERVICE(B5) in C5. You should see a JSON API response appear in the cell.
  6. Type «Atomic Mass» as a header in D4. As there is no JSON parser in Excel, we copy a substring from the API response between the atomic_mass field and the subsequent field, covalent_radius. The whole function looks like this: =MID(C5;SEARCH(«atomic_mass»;C5)+13;SEARCH(«covalent_radius»;C5)-SEARCH(«atomic_mass»;C5)-16) You should now see only the atomic mass as a number in the cell.
  7. Select the cells B5 to D5, grab the right bottom corner, and drag them down to the B6 to D6. You should see the API URL, API response and atomic mass for the second element appear.
  8. To get the atomic mass for more elements, add a new element symbol in column A and copy or drag down the three other columns.

Please note that Excel function names are localized along with the Excel user interface. If your Excel installation is in German, replace the names based on this list:

  • CONCAT – TEXTKETTE
  • MID – TEIL
  • SEARCH – SUCHEN

You can get a working Excel workbook in the PeriodicTableWebservice.xlsx file (TODO: add download).

Visual Basic for Applications, or VBA for short, is a powerful programming language that you can use to automate Microsoft Office applications, including Excel. VBA is closely related to, but not fully compatible with, other versions of the Basic language (such as Visual Basic .NET).

If you not worked with VBA before but have programming skills in a different language, you have to learn a new syntax, but should be able to understand the structure of the macro we build in this section.

Our goal is to retrieve various attributes of specific chemical elements (but not the entire periodic table). The sheet layout uses one row per element. The user should enter the element names into the first column of the sheet (A). Then, upon running the macro, it should go through the list of rows and fill the other columns with details. For example, the atomic mass in the second column (B) and the covalent radius in the third column (C).

Open Excel with a new, empty sheet. Then, press the combination Alt and F11 on your keyboard to launch the Visual Basic editor.

On the left side of the editor, you can see the project structure. There’s an entry for your sheet. Double-click on this entry to open the code view where you can enter Basic code that is specific to that sheet.

We start by creating two global string variables, one for the base URL and the API key. It helps us separate them from the code itself so we can swap them if necessary.

Dim baseUrl, apiKey As String

It’s not possible to assign a value to these variables yet. We’ll do that later.

As mentioned under the objective above, we need to retrieve specific elements that the user enters into the sheet, not the full periodic table. For this purpose, we use the API endpoint for specific elements and have to make multiple requests. Hence it is useful to develop an abstraction and put the logic for the API request into a function.

In VBA, you can define functions with the Function keyword. They have parameters with types and a return type. Here is the definition of our getElement() function:

Function getElement(id As String) As Object

Next, we create a script control. That is actually a workaround because there is no native JSON parser available and we don’t want to install a third-party module. The script control can execute JScript, which is a version of JavaScript, and thus understand JSON.

Dim scriptControl As Object
Set scriptControl = CreateObject("MSScriptControl.ScriptControl")
scriptControl.Language = "JScript"

Then, we can make an HTTP request to the API endpoint. VBA makes HTTP requests through the XMLHTTP object. While building the request, we use string concatenation to build the API URL and include the base URL and API key from the variables we defined earlier.

With CreateObject("MSXML2.XMLHTTP")
    .Open "GET", baseUrl + "elements/" + id + "?x-api-key=" + apiKey, False
    .send

Once we have a response, we can parse it with the script control and assign the result to the function name, which is VBA’s way of specifying the returned value for a function:

    Set getElement = scriptControl.Eval("(" + .responsetext + ")")
    .abort

After that, all is left is closing the With-block and the function. The VBA editor might have already generated this code for you automatically.

End With
End Function

Macros are public VBA subroutines. Let’s call ours getPeriodicElementData():

Public Sub getPeriodicElementData()

Inside the subroutine, we first assign some values to our global variables. Add these lines and replace APIKEY with your API key from the developer portal:

baseUrl = [https://dev.api.basf.com/chemical/](https://dev.api.basf.com/chemical/)
apiKey = "APIKEY"

Then, as we want to go through our sheet row by row to get element data, we set up a counter variable:

Dim row As Integer
row = 1

Our algorithm goes through all rows until it stops at an empty row. We can achieve this with a Do-Until-loop:

Do Until IsEmpty(Cells(row, 1))

Inside the loop, we call our getElement() function we created in the previous section. By using a With-block, we can access the attributes of the elements directly and write them in the cells. Our sample code reads two attributes, atomic mass and covalent radius, which go in the row of the current element and the second or third column respectively.

    With getElement(Cells(row, 1))
        Cells(row, 2) = .atomic_mass
        Cells(row, 3) = .covalent_radius
    End With

If you want, you can extend this code with more properties from the element object and put them in additional columns. Tip: Use the WEBSERVICE() function to get the full JSON structure so you can see the available properties.

Afterwards, make sure to increase the row variable, otherwise you have an infinite loop:

    row = row + 1

Finally, we close the loop and the subroutine. The VBA editor might have already generated this code for you automatically.

Loop
End Sub

Before we can run the macro, we should add a couple of element symbols in the first column (A) so that the macro has something to do. As an example, use the elements H, S and O. Use one row for each, so that H is in the first, S in the second and O in the third row.

During development, you can run your macro directly from the VBA editor, using either the play button in the toolbar, the Run menu, or the F5 key on your keyboard.

The macro should run and automatically fill the other columns for your three rows.

To re-run your macro later when you’ve closed the VBA editor, follow these steps:

  1. Open the View ribbon.
  2. Click on Macros.
  3. Select the macro and click Run to execute.

The Power Query builder provides access to a variety of data sources. It even enables the combination of data from multiple sources. In this tutorial, though, we’ll just show you the basics to make an API call and display the results in your Excel sheet. We use the collection endpoint to retrieve the complete periodic table.

To get started, go to the Data ribbon, click the Get Data button, choose From Other Sources, and From Web.

In the popup window, enter the URL for the API. You can configure advanced settings such as HTTP headers for your request, but the BASF Periodic Table API doesn’t need any. You have to provide the full URL to the collection endpoint and add the query parameter for authentication directly into the URL. In the following sample, replace APIKEY with the Client ID of your application

https://dev.api.basf.com/chemical/elements?x-api-key=APIKEY

Once you confirm with OK, the Power Query Builder opens and shows the API response. At first, you just see the container element items. Right-click on it and select Drill Down.

Note the list of applied steps on the right side of the window. It shows you everything you did in the query builder and you can undo any step by clicking the X next to it.

Now you see a list of records and you can click on each to see the different attributes of each element. The next step is converting this list into a table and you do this by clicking the To Table button.

A popup with additional options may appear which you can simply confirm with OK. After that, you see the list as a table but it still has just one column that we need to expand into multiple columns so you can see each attribute of the element in its own column. To do so, click the expand icon (<>) in the column header.

In the popup, select the fields that you like or keep all fields intact. You can uncheck «Use original column name as prefix» as the prefix doesn’t provide any value when you’re just working with one data source.

Once you see the data you want in the query builder, your final step is transferring the table into the Excel sheet. You do this with the Close&Load button.

You’re done! Your excel sheet contains the periodic table of elements now.

Congratulations on making it through the tutorial! We hope it deepened your understanding of APIs and how to consume them with Excel. Feel free to contact developer@basf.com with feedback and questions.

Like this post? Please share to your friends:
  • Excel create object error
  • Excel create list from table
  • Excel create add in
  • Excel create a pie chart
  • Excel countries of the world