To complete the response of the other users:
For this I have created an «WinHttp.WinHttpRequest.5.1» object.
Send a post request with some data from Excel using VBA:
Dim LoginRequest As Object
Set LoginRequest = CreateObject("WinHttp.WinHttpRequest.5.1")
LoginRequest.Open "POST", "http://...", False
LoginRequest.setRequestHeader "Content-type", "application/x-www-form-urlencoded"
LoginRequest.send ("key1=value1&key2=value2")
Send a get request with token authentication from Excel using VBA:
Dim TCRequestItem As Object
Set TCRequestItem = CreateObject("WinHttp.WinHttpRequest.5.1")
TCRequestItem.Open "GET", "http://...", False
TCRequestItem.setRequestHeader "Content-Type", "application/xml"
TCRequestItem.setRequestHeader "Accept", "application/xml"
TCRequestItem.setRequestHeader "Authorization", "Bearer " & token
TCRequestItem.send
Пользовательские функции 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.
- Remove From My Forums
-
Question
-
How do I add a reference (what magic name/path do I use) for WinHttpRequest from Excel VBA?
I want to access a site that needs credentials.
Another option?
Excel 2010
Answers
-
>>>>How do I add a reference (what magic name/path do I use) for WinHttpRequest from Excel VBA?
Set a reference to Microsoft WinHTTP Services. You can do that by clicking on menu tools~~> references
Here is an example. I just wrote this example. I have not tested it.
Const HTTPREQUEST_SETCREDENTIALS_FOR_SERVER = 0 Private Sub Sample() Dim httpRequest As New WinHttpRequest Dim UName As String, Upass As String httpRequest.Open "GET", "http://BlahBlah.com" UName = "Siddharth Rout" Upass = "Blah Blah" '~~> Here you have to set credentials httpRequest.SetCredentials UName, Upass, _ HTTPREQUEST_SETCREDENTIALS_FOR_SERVER '~~> Here you send the request httpRequest.Send '~~> Here we get this response MsgBox httpRequest.ResponseText End Sub
Sid (A good exercise for the Heart is to bend down and help another up)
Please do not email me your questions. I do not answer questions by email unless I get paid for it If you want, create a thread in Excel forum and email me the link and I will help you if I can.
-
Proposed as answer by
Monday, August 8, 2011 7:32 AM
-
Marked as answer by
Macy Dong
Thursday, August 11, 2011 2:26 AM
-
Proposed as answer by
-
Hello Bob
1) On Windows 7 + Office 2010, I was able to add the reference to Microsoft WinHTTP Services. It didn’t give me any error.
2) Path should be c:windowssystem32winhttp.dll
Sid (A good exercise for the Heart is to bend down and help another up) Please do not email me your questions. I do not answer questions by email unless I get paid for it If you want, create a thread in Excel forum and email me the link and I will help
you if I can.-
Proposed as answer by
Macy Dong
Monday, August 8, 2011 7:32 AM -
Marked as answer by
Macy Dong
Thursday, August 11, 2011 2:26 AM
-
Proposed as answer by
- Интернет
- Логин и пароль
- Интернет-порталы
Приведённый ниже код выполняет авторизацию на Яндексе, отправляя GET и POST запрос
На время POST запроса отключается автоматический редирект, чтобы сохранить Cookies, переданные в ответе сервера
PS: Код предназначен для специалистов!
Я не готов отвечать на вопросы, почему у вас не получилось авторизоваться, и что делать с этим макросом дальше (как получать данные)
Public CookiesStore As Object ' as Dictionary Sub test_Yandex_Authentication() ' пример использования If YM_Auth("MyLogin", "MyPassword") Then Debug.Print "Авторизация выполнена" Debug.Print "Сохранённые куки:", GetCookiesFromStore Else Debug.Print "Ошибка авторизации" End If End Sub
Function YM_Auth(ByVal YM_login$, ByVal YM_password$) As Boolean ' © 2014 EducatedFool ExcelVBA.ru ' функция выполняет авторизацию на Яндексе, принимая в качестве параметров логин и пароль ' возвращает TRUE, если авторизация выполнена ' в глобальном словаре CookiesStore сохраняет все куки, ответственные за авторизацию ' во всех дальнейших запросах надо использовать добавление заголовка COOKIE из этого хранилища ' при помощи строки кода .SetRequestHeader "Cookie", GetCookiesFromStore On Error Resume Next Dim RequestTimeout&, wHTTP As Object, Response$, ResponseHeaders$, URL$ Const StartURL$ = "http://market.yandex.ru/" Const AuthURL$ = "https://passport.yandex.ru/auth" RequestTimeout& = 6 ' таймаут (в секундах) ожидания ответа от сервера Set wHTTP = CreateObject("WinHttp.WinHttpRequest.5.1") Set CookiesStore = CreateObject("Scripting.Dictionary") ' ОБЯЗАТЕЛЬНО НУЖНА ГЛОБАЛЬНАЯ ПЕРЕМЕННАЯ CookiesStore ! With wHTTP ' открываем произвольную страницу Яндекса, чтобы получить ID сессии .Open "GET", StartURL$, True AddStaticHeaders wHTTP ' добавляем заголовки запроса (представляясь браузером Chrome) .Send If .WaitForResponse(RequestTimeout&) Then ' если дождались ответа от сервера SaveCookiesFromResponseHeaders .GetAllResponseHeaders ' запоминаем куки .Open "POST", AuthURL$, True ' выполняем POST запрос для авторизации ' отключаем авторедирект, чтобы получать cookies при каждом редиректе .Option(WinHttpRequestOption_EnableRedirects) = False AddStaticHeaders wHTTP ' добавляем заголовки запроса (представляясь браузером Chrome) .SetRequestHeader "Cookie", GetCookiesFromStore .SetRequestHeader "Host", "passport.yandex.ru" Dim POST() As Byte, PostData$, timestamp$ ' отправка данных учётной записи timestamp$ = (Now - 25569) * 86400000 ' время в формате UNIX PostData$ = "login=" & YM_login$ & "&passwd=" & YM_password$ & _ "×tamp=" & timestamp$ & "&retpath=http://market.yandex.ru/" POST = StrConv(PostData, vbFromUnicode) .Send (POST): DoEvents If .WaitForResponse(RequestTimeout&) Then If .Status Like "30*" Then ' если произошёл редирект, - значит, мы авторизовались успешно SaveCookiesFromResponseHeaders .GetAllResponseHeaders ' запоминаем куки YM_Auth = True End If Else Debug.Print "Request Timeout (" & RequestTimeout & " seconds)", AuthURL$ ' истекло время ожидания End If Else Debug.Print "Request Timeout (" & RequestTimeout & " seconds)", StartURL$ ' истекло время ожидания End If .Option(WinHttpRequestOption_EnableRedirects) = True End With Set wHTTP = Nothing End Function
Sub AddStaticHeaders(ByRef wHTTP As Object) On Error Resume Next With wHTTP '.SetRequestHeader "Host", "market.yandex.ru" .SetRequestHeader "User-Agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.131 Safari/537.36" .SetRequestHeader "Accept-Language", "ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4" .SetRequestHeader "Connection", "keep-alive": .SetRequestHeader "Cache-Control", "no-cache" .SetRequestHeader "Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8" .SetRequestHeader "Content-Type", "application/x-www-form-urlencoded" .SetRequestHeader "Origin", "http://market.yandex.ru" .SetRequestHeader "Referer", "http://market.yandex.ru/" End With End Sub
Function TextBetween(ByVal txt$, ByVal part1$, ByVal part2$, ByVal sep$) As String ' функция ищет в текстовой строке TXT блоки, начинающиеся текстом part1$, и заканчивающиеся текстом part2$ ' возвращает массив найденных значений (объединённых в одну строку через разделитель sep$) On Error Resume Next Dim arr, i, res$ Select Case "" Case part1$ & part2$: TextBetween = txt: Exit Function Case part1$: arr = Split(txt, part2$): arr(UBound(arr)) = "" Case part2$: arr = Split(txt, part1$): arr(0) = "" Case Else: arr = Split(txt, part1$) arr(0) = "" For i = LBound(arr) To UBound(arr) If InStr(1, arr(i), part2$, vbTextCompare) Then arr(i) = Split(arr(i), part2$)(0) Else arr(i) = "" Next i End Select txt = Join(arr, sep$) If sep$ = "" Then TextBetween = txt: Exit Function While InStr(1, txt$, sep$ & sep$, vbBinaryCompare): txt$ = Replace(txt$, sep$ & sep$, sep$): Wend If txt$ Like "*" & sep$ Then txt = Left(txt, Len(txt) - Len(sep$)) If txt$ Like sep$ & "*" Then txt = Mid(txt, Len(sep$) + 1) TextBetween = txt End Function
Function GetRedirectLocation(ByVal ResponseHeaders$, Optional CurrentURL$) As String ' если в заголовках ResponseHeaders$ есть заголовок Location, ' то функция возвращает путь для редиректа On Error Resume Next ResponseHeaders$ = Replace(ResponseHeaders$, "-Location", "") If InStr(1, ResponseHeaders$, "Location: ", vbTextCompare) = 0 Then Exit Function Dim URL$, BaseURL$: URL$ = Split(TextBetween(ResponseHeaders$, "Location: ", vbNewLine, vbNewLine), vbNewLine)(0) If IsURL(URL$) Then GetRedirectLocation = URL$ Else If (URL$ Like "/*") And IsURL(CurrentURL$) Then BaseURL$ = Split(CurrentURL$, "://")(0) & "://" & Split(Split(CurrentURL$, "://")(1), "/")(0) GetRedirectLocation = BaseURL$ & URL$ End If End If If Len(GetRedirectLocation) Then Debug.Print "redirect to " & GetRedirectLocation End Function Function IsURL(ByVal txt$) As Boolean IsURL = IsURL Or (txt$ Like "http://?*.?*") IsURL = IsURL Or (txt$ Like "https://?*.?*") End Function Function SaveCookiesFromResponseHeaders(ByVal txt$) On Error Resume Next Dim cookies$, item, param_name$, param_value$ cookies$ = TextBetween(txt$, "Set-Cookie: ", vbNewLine, "; ") For Each item In Split(cookies$, "; ") param_name$ = "": param_value$ = "" param_name$ = Split(item, "=", 2)(0) param_value$ = Split(item, "=", 2)(1) If Len(param_name$) Then CookiesStore.item(param_name$) = param_value$ Next End Function
Function GetCookiesFromStore() As String On Error Resume Next: Dim key, v$ For Each key In CookiesStore.Keys v$ = CookiesStore(key) GetCookiesFromStore = GetCookiesFromStore & "; " & key & IIf(v$ = "", "", "=" & v$) Next GetCookiesFromStore = Mid(GetCookiesFromStore, 3) End Function
- 28486 просмотров
Не получается применить макрос? Не удаётся изменить код под свои нужды?
Оформите заказ у нас на сайте, не забыв прикрепить примеры файлов, и описать, что и как должно работать.
If You want to check if link is still active, You will just click it and see if site is online. But what should You do if You got 1000 links to check? Or more? In this article I’ll show You how to use WinHttp Request to get your site status.
In the first place I thought that my code should open Internet Explorer or any other Internet browser, then go to the chosen site address and based on content macro will know if it is active, or not. Luckily, few minutes of Google searching later I realized, that there are easier methods of checking website status.
Finally, I’ve chosen WinHttpRequest, because it was giving me all the information I wanted.
Set xmlhttp = CreateObject("WinHttp.WinHttpRequest.5.1")
By information I mean the codes, whole variety of status codes. After some tests with different website links I realized, that I am interested in 2 numbers – 200 and 300.
Why these numbers?
First number – 200 – stands for situation, when your browser displays the file, for instance instruction in .pdf, or when your browser asks to save this file on your computer. Second number – 300 – stands for fully loaded website.
I was not interested in:
– redirection to other location or to homepage,
– error 404 page not found,
– situation when page can’t load at all.
Avoid unexpected issues
First two points are giving status number (301, 302 and 404), but the last one is different history. For this kind of situation I implemented into code:
On Error Resume Next
If Err.Number <> 0 Then
...
Else
...
End If
On Error GoTo 0
This part is responsible to keep the code safe and uninterrupted.
Security Certificate warning
This was the second thing, which I struggled with working on this tool. After research I found out, that one magic line can deal with the problem:
xmlhttp.Option(6) = False
Reset WinHttp object
Also a good thing is to reset object to, let’s call it, clean the memory.
Set xmlhttp = Nothing
I did not notice much difference with or without it in this case, but I consider this as a good approach.
Example sheet
Imagine a simple table with 10 rows of links You want to check in column A. If the link is active code will fill cell as green, if not as red.
If getStatus <> "300" And getStatus <> "200" Then
.Cells(i, 1).Interior.ColorIndex = 3
Else
.Cells(i, 1).Interior.ColorIndex = 4
End If
Code
Option Explicit
Sub winHttpRequest()
Dim xmlhttp As Object
Dim myURL As String
Dim getPageText As String
Dim getStatus As String
Dim lastRow As Long, i As Long
Dim arr As Variant
With ThisWorkbook.Sheets(1)
lastRow = .Cells(Rows.Count, 1).End(xlUp).Row
arr = .Range(.Cells(1, 1), .Cells(lastRow, 1))
For i = 1 To UBound(arr)
myURL = arr(i, 1)
On Error Resume Next
Set xmlhttp = CreateObject("WinHttp.WinHttpRequest.5.1")
xmlhttp.Option(6) = False
xmlhttp.Open "GET", myURL, False
xmlhttp.send
If Err.Number <> 0 Then
'sometimes there is no "asnwer" from server
Else
getStatus = xmlhttp.Status
If getStatus <> "300" And getStatus <> "200" Then
.Cells(i, 1).Interior.ColorIndex = 3
Else
.Cells(i, 1).Interior.ColorIndex = 4
End If
End If
On Error GoTo 0
Set xmlhttp = Nothing
Next i
End With
End Sub
Summary
WinHttp Request is a really good option to get your site status. There are other options, but in case of delivered information I would recommend that method. By using WinHttp You can achieve also other goals, but about that maybe in other 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