Иногда при выполнении скрипта приходится опираться на значения с web сайтов. В PowerShell с версии 3.0 для этого имеется замечательный командлет Invoke-WebRequest.
Рассмотрим подробнее скрипт:
!!!В строчке $trash = $li.innerhtml -match " \ ( ( . * ? ) \ ) "
убрать пробелы внутри ковычек » \ ( ( . * ? ) \ ) «.!!!
1 2 3 4 |
$ie = Invoke-WebRequest -Uri 'http://coolcode.ru' -Method POST -ContentType "text/plain; charset=utf-8" $li=$ie.AllElements |where {($_.tagName -eq "LI") -and ($_.innerhtml -like "*Администрирование*")} $trash = $li.innerhtml -match " \ ( (.*?) \ ) " $Matches[1] |
Этот скрипт выполняет следующие действие: на сайте «http://coolcode.ru» мы находим рубрику «Администрирование» и смотрим сколько в данной рубрике статей.
В начале мы создаём объект, со страницей сайта:
1 |
$ie = Invoke-WebRequest -Uri 'http://coolcode.ru' -Method Get -ContentType "text/plain; charset=utf-8" |
Здесь используется самая главный командлет Invoke-WebRequest
В данном примере мы используем только необходимые параметры:
-Uri <String>
Командлет Invoke-WebRequest поддерживает следущие протоколы: HTTP, HTTPS, FTP, и FILE. В данном параметре необходимо указать url к странице, в нашем случае это http://coolcode.ru’.
-Method <WebRequestMethod>
Определяет метод используемый для веб-запроса. Допустимые значения: Default, Delete, Get, Head, Merge, Options, Patch, Post, Put и Trace.
Пробежимся в крации по ним:
Head Получение заголовка, без тела. В основном используется для получения матаданных.
Get Применяется для получения содержимого указанного ресурса.
Options Применяется для определения возможностей веб-сервера или параметров соединения.
Post Используется для передачи данных на сервер.
Put Загрузка содержимого на указанный uri.
Patch Тоже самое, что и Put но только применяется на фрагмент ресурса
Delete Удаляет указанный ресурс.
Тrace Возвращает полученный запрос, с информацией о добавлении и изменении запроса промежуточными серверами.
Merge …
В своём примере я использую значение POST. Хоть мне надо всего лишь получить данные из тела страницы и в первой редакции этой статьи я использовал метод GET, но с методом GET как то через раз отрабатывал параметр -contentType.
-ContentType <String>
Задаёт тип содержимого в веб-запросе. по умолчанию «application/x-www-form-urlencoded». Я использую данный метод, для получения данных в правильной кодировке :-ContentType «text/plain; charset=utf-8». У меня почему то этот параметр через раз работал с «-Method GET», после изменения на «-Method POST» всё работает корректно.
У командлета Invoke-WebRequest существуют так же ещё много интересных параметров, которые могут быть вам интересны:
-Body<Object>
Данный параметр задаёт тело запроса, и используется для заполнения полей на сайте. (этот параметр рассмотрим в другой статье)
-Certificate<X509Certificate>
Задаёт сертификат, для реализации безопасности в веб-запросе. Что бы найти сертификат воспользуйтесь командлетом Get-PfxCertificate или используйте Get-ChieldItem на диске Cert:. Если сертификат не действительный или не имеет достаточных полномочий, команда не выполнится.
-CertificateThumbprint<String>
Задаёт учётную запись пользователя, который имеет право на отправку запроса на цифровой сертификат открытого ключа (X509).
-Credential<PSCredential>
Задаёт учётную запись пользователя, который имеет разрешение на отправку запроса. По умолчанию используется текущий пользователь.
-DisableKeepAlive
Устанавливает значение постоянного HTTP соединения в HTTP-заголовке в значение False. По умолчанию постоянное HTTP соединение включено.
-Headers<IDictionary>
Устанавливает заголовок веб-запроса. Можно указать хэш-таблицу или словарь.
-InFile<String>
Получение содержимого веб-запроса из файла.
Определяет, сколько раз Windows PowerShell может совершить попыток для соединение с заданным URI, прежде чем возникнет ошибка подключения. По умолчанию значение 5. Значение 0 блокирует все попытки.
-OutFile<String>
Сохраняет тело ответа в указанный файл.
-PassThru
Возвращает результаты в консоль, в дополнении к записи результатов в файл. Используется вместе с параметром -OutFile
-Proxy<Uri>
Задаёт прокси сервер для выполнения запроса.
-ProxyCredential<PSCredential>
Параметры учётной записи для прокси. Например «User01» или «Domain01\User01».
-ProxyUseDefaultCredentials
Для соединением с прокси использовать учётные данные текущего пользователя.
-SessionVariable<String>
Создаёт сеанс веб-запроса в и сохраняет его в значение указанной переменной. Переменную необходимо вводить без знака доллара «$». При указании переменной сеанса, Invoke-WebRequest создаёт объект сеанса веб-запроса и присваивает его переменной с указанным именем. Вы сможете использовать данную переменную, как только закончится выполнение запроса. Данный объект не является постоянным соединением. Он содержит информацию о связи запроса, кукисы, учётные данные, максимальные значения количества соединений и строки агента пользователя. Этот объект можно использовать для обмена состояниями данных, между веб-запросами.
-TimeoutSec<Int32>
Данный параметр задаёт время, в течении которого запрос может находится в ожидании. Время указывается в секундах. Значение по умолчанию 0, что укзывает на неопределённый тайм-аут(сколько угодно долгий).
-TransferEncoding<String>
Определяет значение зжатия для заголовка HTTP. Допустимы значения Chunked, Compress, Deflate, GZip и Identity.
-UseBasicParsing
Использование объекта ответа для HTML без синтаксического анализа DOM.
-UseDefaultCredentials
Использование учётных данных текущего пользователя, для отправки веб-запроса.
-UserAgent<String>
Использовать строку для аутентификации сайтом агента. По умолчанию используется «Mozilla/5.0 (Windows NT; Windows NT 6.1; en-US) WindowsPowerShell/3.0».
-WebSession<WebRequestSession>
Назначает сеанс веб-запроса. Переменная указывается со знаком доллора($).
Что бы изменить значение параметров в сеансе веб, используйте параметры командлета, например UserAgent или Credential. Параметры командлета имеют больший приоритет, чем значчения в сессии веб-запроса.
В полученной переменной будет содержаться информация о
После исполнения команды
1 |
$ie = Invoke-WebRequest -Uri 'http://coolcode.ru' -Method Get -ContentType "text/plain; charset=utf-8" |
У будет объект, содержащий данные страницы http://coolcode.ru, но это не просто текст, а как и всё в PowerShell это объект. И у него есть очень интересные свойства:
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 |
PS C:\Windows\system32> $ie|Get-Member TypeName: Microsoft.PowerShell.Commands.HtmlWebResponseObject Name MemberType Definition ---- ---------- ---------- Equals Method bool Equals(System.Object obj) GetHashCode Method int GetHashCode() GetType Method type GetType() ToString Method string ToString() AllElements Property Microsoft.PowerShell.Commands.WebCmdletElementCollection AllElements {get;} BaseResponse Property System.Net.WebResponse BaseResponse {get;set;} Content Property string Content {get;} Forms Property Microsoft.PowerShell.Commands.FormObjectCollection Forms {get;} Headers Property System.Collections.Generic.Dictionary[string,string] Headers {get;} Images Property Microsoft.PowerShell.Commands.WebCmdletElementCollection Images {get;} InputFields Property Microsoft.PowerShell.Commands.WebCmdletElementCollection InputFields {get;} Links Property Microsoft.PowerShell.Commands.WebCmdletElementCollection Links {get;} ParsedHtml Property mshtml.IHTMLDocument2 ParsedHtml {get;} RawContent Property string RawContent {get;} RawContentLength Property long RawContentLength {get;} RawContentStream Property System.IO.MemoryStream RawContentStream {get;} Scripts Property Microsoft.PowerShell.Commands.WebCmdletElementCollection Scripts {get;} StatusCode Property int StatusCode {get;} StatusDescription Property string StatusDescription {get;} |
Рассмотрим их:
AllElements — Возвращает массив свойств всех элементов.
Forms — Возвращает массив свойств всех форм.
Images — Возвращает массив всех свойств изображений.
InputFields — Возвращает массив всех свойств полей воода.
Links — Возвращает массив свойств ссылок.
ParsedHtml — Возвращает странцу ввиде дерева объектов.
Scripts — Возвращает массив свойств всех скриптов.
Content — Возвращает содержимое страницы.
И переходим к следующей строчке скрипта:
1 |
$li=$ie.AllElements |where {($_.tagName -eq "LI") -and ($_.innerhtml -like "*Администрирование*")} |
1 |
$li=$ie.AllElements |
В моём случае я использую свойство AllElements объекта $ie . И у меня получится массив элементов страницы … каждый элемент будет являтся объектов со следующими свойствами:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
$ie.AllElements |Get-Member TypeName: System.Management.Automation.PSCustomObject Name MemberType Definition ---- ---------- ---------- Equals Method bool Equals(System.Object obj) GetHashCode Method int GetHashCode() GetType Method type GetType() ToString Method string ToString() innerHTML NoteProperty innerHTML=null innerText NoteProperty innerText=null outerHTML NoteProperty outerHTML=null outerText NoteProperty outerText=null tagName NoteProperty System.String tagName=! |
Рассмотрим его свойства:
tagName — имя элемента (div,li,p,a…)
innerHTML — HTML код внутри тэга.
innerText — Отображаемый код из тега.
outerHTML — Код всего тэга.
outerText — текс который отображается из этого тэга.
В нашем примере я использую свойства tagName и innerHTML которые должны равнятся соответствующим значениям:
1 |
where {($_.tagName -eq "LI") -and ($_.innerhtml -like "*Администрирование*")} |
как я узнал каким значениям должны ровняться данные параметры?
Я посмотрел код страницы. В Chrome и Firefox например, можно выделить интересующий вас участок и нажав правую кнопку выбрать в выпадающем списке кнопку звучащую примерно, как «Просмотреть код».
Но вернёмся к скрипту. После отработки строчки:
1 |
$li=$ie.AllElements |where {($_.tagName -eq "LI") -and ($_.innerhtml -like "*Администрирование*")} |
в переменной $li у нас будет содержаться код тэга li с кодом внутри содержащим слово «Администрирование».
Теперь из него осталось достать нужную нам информацию… а конкретно значение в скобках. Я предлагаю воспользоваться регулярным выражением:
!!!В строчке $trash = $li.innerhtml -match " \ ( ( . * ? ) \ ) "
убрать пробелы внутри ковычек » \ ( ( . * ? ) \ ) «.!!!
1 2 |
$trash = $li.innerhtml -match " \ ( ( . * ? ) \ ) " $Matches[1] |
Нужное нам значение получено.
Добрый день!
Снова немного столкнулся с парсингом html и вернулся сюда, а тут бах и сюрприз PowerShell !!!
За что Вам огромнейшее спасибо.
Но есть вопросик.
Я использую PowerShell 5.0.10586.117 (запускал из ISE) и у меня данный код отработал, но сначала вылезло сообщение «Предупреждение системы безопасности Windows», я сменил название рубрики с Администрирование на Скрипты, но число всё равно выводил 16.
Закрыл ISE и проверил заново, в итоге получаю тоже «Предупреждение системы безопасности Windows», а за тем:
Vector smash protection is enabled.
Cannot index into a null array.
At E:\Scripts\PowerShell\Parser.ps1:4 char:1
+ $Matches[1]
+ ~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : NullArray
Как не странно, но всё правильно.
в обоих случаях мы находим следующий li:
То есть «скрипты» это под категория раздела «администрирования»… а я вывожу первое значение с цифорками из раздела.
Про ошибку…. всё дело в кодировке.
У меня какой то косячный сайт (WordPress из коробки :), PowerShell раз в несколько десятков раз отображает кодировку правильно, и очень вероятно, в первый раз тоже она окажется правильной. %)
после чего массив $Matches заполняется и при повторном запуске не изменяется.
При этом браузеры отрабатывают корректно.
Попытался конвертировать вывод, но ничего не получилось… попытался поиграться с -ContentType вообще 0 реакции.
убил 3 часа… идей нет …
Хотя нет, идеи есть… Изменил метод с GET на POST. Вроде начал отрабатывать -ContentType. по крайней мере у меня кодировка стабильно корректная :).
Некоторый сайты, требуют обязательного параметра -UseBasicParsing, например:
$r = Invoke-WebRequest "http://ivolgann.com" -Method Post -UseBasicParsing -ContentType "text/plain; charset=utf-8"
$r.links
Антон, приветствую, хотел поинтересоваться, есть ли возможность впихнуть в GUI тело на Powershell js скрипт, который использует сайт?
Есть внутриорганизационный справочник, содержащий телефонную базу, доступ к этой базе с сайта осуществляется через js скрипт, набирая первые цифры внутреннего номера пользователь получает список с информацией о номере, переходя открывается новая страница браузера содержащуюю эту информацию в расширенном виде. Хотел внедрить такое же решение в guiшку на powershell добавить textbox который так же будет переваривать эту функцию как сайт? может .. можно не внедряя js в ps скрипт, осуществлять реализацию этой функции через инфу, которую можно получить со страницы сайта.
Есть страница внутри компании, доступ по УЗ из АД, если выполняю в линукс обынчный curl то хотя бы получаю, что доступ запрещен, пытаюсь выполнить
Invoke-WebRequest -Uri «http://xxx.cor.net/docadmin/default.aspx» -TimeoutSec 5 -UseDefaultCredentials
то в ответ ничего не получаю, что может быть?
такая проблема с парой сайтов, есть другие, но с ними работает все нормально!