Предположим, вам необходимо получить с веб-страницы определенные данные, но, чтобы добраться до них, нужно заполнить некую форму и нажать кнопку «Готово». Как это сделать в автоматическом режиме? Не беспокойтесь, задача решается с помощью кода PowerShell.

В своих предыдущих материалах о PowerShell я, должен сознаться, оставил без внимания такую важную составляющую, как формы. Я показал вам, как анализировать экранные данные и пользоваться форматами JSON и XML, но получить доступ к огромным пластам размещенных в веб-среде данных можно лишь с помощью следующей процедуры: вы заполняете форму, нажимаете кнопку и обрабатываете появляющиеся на экране выходные данные. Надо полагать, что владельцы некоторых веб-сайтов были бы недовольны, если бы я показал вам, как автоматизировать процесс опроса публикуемых на этих сайтах форм. Поэтому я создал самую простую в мире страницу на базе формы. Вы можете найти ее в Интернете по адресу: http://www.minasi.com/addit.htm.

На этой странице представлены два поля: addend1 и addend2. Заполните их целыми числами, потом нажмите кнопку SUBMIT! — и ваши усилия будут вознаграждены сообщением вроде следующего:

Sum= 16

Имейте в виду, работа этой страницы заканчивается сбоем, если вы не вводите в ней целые числа.

Обратите внимание на то, что на данной странице используется не один, а два указателя URL. Исходная форма публикуется по адресу: http://www.minasi.com/addit.htm, но после нажатия кнопки SUBMIT! вы получаете ответ на странице, которую адресная строка идентифицирует как http://www.minasi.com/addit-worker.asp. Скоро вы поймете, насколько это важно.

Кроме того, вам известно: чтобы попасть на страницу, отображающую сумму двух предложенных целых чисел, вам нужно нажать кнопку SUBMIT!. Но как же сделать это средствами PowerShell? Должен признаться, что вопрос «как же нажать на кнопку?» донимал меня в течение нескольких часов, но в конечном итоге я сделал то, что делаю всегда, когда сталкиваюсь с вопросами функционирования внутренних механизмов сети: я запустил Microsoft Network Monitor. Проанализировав поток трафика, я заключил, что мне нужно собрать только несколько фрагментов данных.

  • Указатель URL, использованный системой при ответе на нажатие кнопки. В данном случае это был http://www.minasi.com/addit-worker.asp.
  • Тело запроса, а именно addend1=3&addend2=9&B1=SUBMIT%21.
  • Тип метода POST (а не GET, который используется несколько чаще).

Читатели, которые уже какое-то время следят за приводимыми мною (и почерпнутыми в среде Web) примерами, располагают инструментами, позволяющими автоматизировать данную процедуру. Но давайте отвлечемся на секунду и посмотрим, как собирается команда Invoke-WebRequest.

Прежде всего, вам требуется универсальный код ресурса Uniform Resource Identifier (URI). Когда я только начинал заниматься универсальным кодом на базе формы, я никак не мог его получить: мои первые попытки были сосредоточены на странице «форм», www.minasi.com/addit.htm, а не на «результирующей» странице www.minasi.com/addit-worker.asp. Так что помните: в большинстве случаев целевым URI для вас будет страница результатов, а не страница форм. Итак, мое первое предложение PowerShell определяет код URI:

$URI = 'http://www.minasi.com/addit-worker.asp'

Далее, обратите внимание на тело:

addend1=3&addend2=9&B1=SUBMIT%21

Это всего лишь одна из строк пары «имя-значение», которые включаются в код URI, как вы видели в процессе знакомства с моим первым обращением к веб-службам RESTful. Но в данном случае строка включается в тело, поскольку запрос RESTful относился к простому методу типа GET, а здесь мы имеем дело с методом POST. Напомню, что часто предпочтение отдается методу POST, поскольку когда сообщение передается по протоколу SSL, дотошные сетевые анализаторы не видят, что именно находится в теле HTTP; в то же время коды URI видимы в тексте SSL. Строка разбивается на три пары «имя-значение»:

Addend1 = 3
Addent2 = 9
B1 - SUBMIT%21

и поскольку шестнадцатеричный символ 21 — это «!», то наша кнопка — SUBMIT! Ее можно сохранить в следующей переменной, $Body:

$Body ='addend1=3&addend2=9&B1=SUBMIT%21'

Теперь вы можете построить всю команду:

$page = Invoke-WebRequest $URI -body $Body -method POST

После ее запуска вспомните, что вы можете получить код состояния данной команды из $Page.StatusCode, и мы обычно рассчитываем, что это будет 200. Чтобы увидеть текст, который показывался бы в браузере, просто отобразите содержимое этой страницы:

$page.content

Он выглядит следующим образом:

Sum= 12

Все работает, но давайте попытаемся найти более приемлемый вариант. А так ли уж нам нужна переменная B1=? Если бы на странице было размещено более одной кнопки (возможно, одна из них именовалась бы не SUBMIT!, а Add, а вторая — Multiply), тогда упомянутая переменная была бы важна для нас или, точнее говоря, она была бы важна для Addit-Worker.ASP. Но в данном случае мы можем вообще убрать B1 из включенной в тело строки «имя-значение».

Так что же, задание выполнено? Не совсем. Нам предстоит еще обработать содержимое; в данном случае речь идет о простой формуле Sum = 12, и мы должны извлечь из нее число 12. Но это уже довольно простая операция, осуществляемая посредством ввода с помощью регулярного выражения. Мы уже выполняли подобные операции. Это делается так:

$page.content -replace "Sum= (\d+).*",’$1’

Теперь мы разобрались с нашей первой формой, но это еще не все. Нам предстоит, например, познакомиться с превосходным анализатором Fiddler и методами работы с важными компонентами большинства форм — с файлами-метками, или cookie. Займемся этим в следующий раз.