В PowerShell версии 3.0 появилась возможность напрямую обращаться и работать с HTML веб-страницам в Интернете. Для этого был разработан специальный командлет Invoke-WebRequest. Данный командлет позволяет реализовать множество сценариев: начиная от возможности скачать/ загрузить файл с/на любого веб-сайта по HTTP/ HTTPS/ FTP, заканчивая возможностями парсинга HTML страниц, мониторинга состояния веб серверов, заполнения и отправкой веб-форм. В целом, новый командлет предоставляет все необходимые методы для навигации по DOM дереву HTML документа. В этой статье мы разберём базовые примеры работы с командлетом PowerShell Invoke-WebRequest.
Использование командлета Invoke-WebRequest
Командлет Invoke-WebRequest (псевдоним wget) может отправлять и получать HTTP, HTTPS и FTP запросы, обрабатывать возвращаемый сервером ответ. Полученный ответ представляет собой набор коллекции форм, ссылок, изображений и других важных элементов HTML документа.
Попробуем выполнить следующую команду:
Invoke-WebRequest -Uri "http://winitpro.ru"
Как вы видите, возвращенный ответ представляет собой не простой HTML код страницы. Вы видите различные свойства web-документа. Командлет Invoke-WebRequest, как и большинство других командлетов PowerShell оперирует объектами. Invoke-WebRequest возвращает объект типа HtmlWebResponseObject. Посмотрим все свойства данного объекта:
$WebResponseObj = Invoke-WebRequest -Uri "http://winitpro.ru"
$WebResponseObj| Get-Member
Чтобы получить сырой HTML код веб страницы, который содержится в данном объекте, выполните:
$WebResponseObj.content
Вы можете вернуть HTML код вместе с HTTP заголовками, которые вернул веб сервер:
$WebResponseObj.rawcontent
Вы можете проверить только код ответа веб-сервера и HTTP заголовки HTML страницы:
$WebResponseObj.Headers
Как вы видите, веб сервер вернул ответ 200, т.е. запрос выполнен успешно и веб сервер доступен и работает корректно.
Получаем список всех HTML ссылок на странице
Обратимся к главной странице нашего сайта и получим список ссылок, имеющихся на ней:$SiteAdress = "http://winitpro.ru"
$HttpContent = Invoke-WebRequest -URI $SiteAdress
$HttpContent.Links | Foreach {$_.href }
Чтобы получить и сам текст ссылки (содержится в элементе InnerText), можно воспользоваться такой конструкцией:
$HttpContent.Links | fl innerText, href
Можно выбрать только ссылки с определенным CSS классом:
$HttpContent.Links | Where-Object {$_.class -eq "page-numbers"} | fl innerText, href
Или определенным текстом в url:
$HttpContent.Links | Where-Object {$_.href -like "*exchange*"} | fl innerText,href
Парсинг HTML страниц с помощью Powershell
Командлет Invoke-WebRequest позволяет довольно быстро и удобно парсить содержимое любых веб-страниц. При обработке HTML страницы из ее содержимого формируются коллекции ссылок (links), веб-форм (forms), изображений (images), скриптов (scripts) и т.д.
С помощью Powershell получим содержимое главной страницы нашего сайта:
$Img = Invoke-WebRequest "https://winitpro.ru/"
Затем выведем список всех изображений на данной странице:
$Img.Images
Сформируем коллекцию из полных url путей к используемым изображениям:
$images = $Img.Images | select src
Инициализируем новый экземпляр класса WebClient:
$wc = New-Object System.Net.WebClient
И скачаем все изображения со страницы (с оригинальными именами) в каталог c:\tools\:
$images | foreach { $wc.DownloadFile( $_.src, ("c:\tools\"+[io.path]::GetFileName($_.src) ) ) }
В качестве интересного примера использования командлета Invoke-WebRequest можно привести способ узнать внешнего IP адреса компьютера из PowerShell.
Как скачать файл по HTTP с помощью PowerShell
Invoke-WebRequest может работать как аналог Wget или cURL для Windows, позволяя скачать с веб-страницы или ftp сайта нужный файл или файлы. Допустим, нам нужно с помощью PowerShell скачать по HTTP некий файл (в нашем примере дистрибутив Mozilla Firefox). Выполним такую команду:
Invoke-WebRequest "https://download.mozilla.org/?product=firefox-32.0.3-SSL&os=win&lang=ru" -outfile “c:\tools\firefox setup 32.0.3.exe”
В результате выполнения командлета с указанного URL адреса будет скачан файл и сохранен в каталоге c:\tools\ под именем firefox setup 32.0.3.exe. Если нужно скачать файл с FTP сайта, просто замените http: // на ftp: //.
Таким образом вы с легкостью можете на определенной веб-странице найти все ссылки, попадающие под конкретные критерии (класс ссылки, разрешение в имени файла, url адрес), и скачать файлы по полученным ссылкам. Например, имеется некий сайт с кучей ссылок на PDF документы. Ваша задача скачать все эти файлы на ваш компьютер. Костяк PowerShell скрипта для массовой скачки файлов может выглядеть так:
$OutDir="C:\Downloads\docs\PDF"
$SiteAdress = "https://www.site.ru/free-pdf-books/"
$HttpContent = Invoke-WebRequest -URI $SiteAdress
$HttpContent.Links | Where-Object {$_.href -like "*.pdf"} | %{Invoke-WebRequest -Uri $_.href -OutFile ($OutDir + $(Get-Random 100000)+".pdf")}
В результате выполнения скрипта в целевом каталоге будут загружены все pdf файлы со страницы. Каждый файл сохраняется под произвольным именем.
Заполнение и отправка веб-форм на Powershell
Многие веб-сервисы для работы требуют ввода различных данных в HTML формы. С помощью Invoke-WebRequest можно получить доступ к любой HTML-форме, заполнить необходимые поля и передать заполненную форму обратно на сервер. В этом примере мы покажем, как с помощью Powershell авторизоваться в почтовом ящике популярного российского сервиса mail.ru через его стандартную веб форму.
С помощью следующей конструкции сохраним информацию о куках (Cookies) подключения в отдельной сессионной переменной:
$mailru = Invoke-WebRequest https://e.mail.ru/login -SessionVariable session
Следующей командой отобразим список заполняемых полей в HTML форме авторизации (форма называется LoginExternal):
$mailru.Forms["LoginExternal"].Fields
Присвоим нужные значения всем полям:
$mailru.Forms["LoginExternal"].Fields["Login"] = "testmail@mail.ru"
$mailru.Forms["LoginExternal"].Fields["Password"] = "Str0NgP$$w0rd"
И т.д….
Чтобы передать заполненную форму на веб сервер, вызовем атрибут HTML-формы action.
$Log = Invoke-WebRequest -method POST -URI ("https://e.mail.ru/login" + $mailru.Forms["LoginExternal"].Action) -Body $mailru.Forms["LoginExternal"].Fields -WebSession $session
Недостатки командлета Invoke-WebRequest
Одним из существенных недостатком командлета Invoke-WebRequest является довольно низкая скорость работы. При загрузке файла HTTP поток целиком буферизируется в память, и только после окончания полной загрузки сохраняется на диск. Таким образом, при закачке больших файлов можно столкнутся с нехваткой памяти.
Другая проблема – командлет Invoke-WebRequest тесно связан с Internet Explorer. Например, в редакциях Windows Server Core, в которых IE не установлен, командлет Invoke-WebRequest использовать нельзя.
Если на HTTP сайте используется самоподписанный сертификат, то командлет Invoke-WebRequest отказывается получать данные с него. Чтобы игнорировать некорректный SSL сертификат, используйте следующий код:
Игнорировать SSL сертификат можно так:add-type @"
using System.Net;
using System.Security.Cryptography.X509Certificates;
public class TrustAllCertsPolicy : ICertificatePolicy {
public bool CheckValidationResult(
ServicePoint srvPoint, X509Certificate certificate,
WebRequest request, int certificateProblem) {
return true;
}
}
"@
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
$result = Invoke-WebRequest -Uri "https://site.ru"
Скажите как зайти на сайт с самоподписанным сертификатом
Игнорировать SSL сертификат можно так:
add-type @"
using System.Net;
using System.Security.Cryptography.X509Certificates;
public class TrustAllCertsPolicy : ICertificatePolicy {
public bool CheckValidationResult(
ServicePoint srvPoint, X509Certificate certificate,
WebRequest request, int certificateProblem) {
return true;
}
}
"@
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
$result = Invoke-WebRequest -Uri "https://site.ru"
Очень вам признателен) Все отлично отрабатывает
Можно ли через Powershell выполнять переход по объектам на странице
и их измененять, если они не являются линками?
Я хочу подключаться к Vsheild и добавлять изменения в объект библиотеки (см.скриншот по ссылке http://hostingkartinok.com/show-image.php?id=e456b42cdb1810768766f6eeeb22cf36) Пока функции PowerCli Этого не позволяют. Приходится искать сторонние методы.
вообще это реально или нет?
Если я правильно понял, нужно изменить какую-то форму на странице и сохранить изменения? Если да — пример работы есть выше в разделе «Заполнение и отправка веб-форм на Powershell»
Дело в том что уже на авторизованной странице нет ни форм, ни ссылок для перехода на следующую страницу. Есть объекты слева как видно на картинке. Как осуществить выбор того или иного объекта?
Похоже страница выполнена на Java. Боюсь вам помочь не смогу — здесь лучше проконсультироваться с Web программистами… Они лучше понимают как можно выполнять навигацию по такому документу
Добрый день.
Подскажите, на основе Вашего примера, как можно пропарсить страничку вроде https://chocolatey.org/packages/flashplayeractivex
в поисках ссылки на дистрибутив
$url = ‘http://download.macromedia.com/get/flashplayer/current/licensing/win/install_flash_player_17_active_x.msi’ ,
которая находится под примерами вызова команд
Files > Show > \chocolateyInstall.ps1 Show >
Т.е. как получить вожделенную ссылку на дистрибутив с веб-страницы?
А если нет таких форм?
Например, вот сайт:
_http://www.stn.by/ips_renovation_login.php
Задача туда зайти и получить ссылку после входа.
как работать с sFTP — кто-нибудь пробовал?
например, тот же curl, это позволяет….
На Windows 7 для Invoke-WebRequest сначала придется поставить WMF 3.0 или выше.
А как можно перед скачиванием файла узнать его размер, дату создания и пр.? Нужно для того, чтобы не скачивать большой файл (1,2Гб) каждый раз повторно, а ждать когда он изменится (название файла не меняется).
Попробуйте получить размер файла так:
$url = "site.ru/bigfile.iso"
(Invoke-WebRequest $url -Method Head).Headers.'Content-Length'
Спасибо, работает!
народ кто может подсказать как открыть
«http://api.weatherstack.com/current?access_key=637af1c4660c987dcf5825c34aae2513&query=London»
в PowerShell?
При запуске команды Invoke-WebRequest у меня в консоли PowerShell появляется ошибка
Invoke-WebRequest : Запрос был прерван: Не удалось создать защищенный канал SSL/TLS.
Причем только у некоторых сайтов. Что делать?
Похоже вы пытаетесь подключится к сайту с новым SSL сертификатом, попробуте принудительно указать тип протокола TLS, например:
Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Invoke-WebRequest -Uri https://www.java.com
Спасибо, помогло!
Попробуйте Invoke-WebRequest -Uri https://api.telegram.org
Если найдете решение буду вам очень признателен.
Судя по ошибке, которая появляется в PowerShell и тому, что этот сайт не открывается, это не веб страница. Invoke-WebRequest тут бессилен, смотрите в сторого API Telegram
Нашел решение, может кто-нибудь так же как и я будет гуглить несколько дней и наткнется….
Накатываете обновление KB2992611.
В коде, если это powershell добавляете :
[Net.ServicePointManager]::SecurityProtocol =
[Net.SecurityProtocolType]::Tls13 -bor `
[Net.SecurityProtocolType]::Tls12 -bor `
[Net.SecurityProtocolType]::Tls11 -bor `
[Net.SecurityProtocolType]::Tls
Отлично, что разобрались и оставили решение 🙂
Как в командной строке получить с сервера информацию о погоде используя API : weatherstack.com (бывший apixu.com)?
Точнее как получить я понимаю, не понимаю как полученный результат упорядочить.
(Invoke-webrequest «ссылка на API сайта» -usebasicparsing).content — что добавить?
Судя по описанию на этом сервисе вам нужно получить некий токен доступа, а потом обращаться через него. На выходе API отдает json файл, который нужно распарсить в powershell.
$req = Invoke-RestMethod ‘http://api.weatherstack.com/current?access_key=xxxxxxxxx&query=Moscow’
$req.Request
О, скиллбокс! Сам ищу ответ…
Подскажите пожалуйста команду для скачки списка URL из файла (ну например urls.txt) с условием, чтобы файл на сервере был не меньше 100кб например.
Проверьте, что вас сервис, где лежит файл отдает его размер:
$Info = Invoke-WebRequest -Uri 'http://...' -Method Head
$Info.Headers['Content-Length'] / 1KB