Ниже приводится описание решения задачи, над которой я несколько дней ломал голову. В поисках решения я облазил все форумы, но докапываться до истины пришлось самому. В надежде, что нижепреведенный текст поможет кому-нибудь, выкладываю описание проблемы и ее решение.
Ключевые слова: HTTP POST METHOD ASPX __EVENTTARGET __EVENTARGUMENT __VIEWSTATE UUENCODE 
(именно эти слова я шептал гуглю прося у него совета и подсказки)
Условие: На сайте НБУ по адресу http://www.bank.gov.ua/Fin_ryn/OF_KURS/Currency/FindByDate.aspx лежит таблица курсов валют. Эта табличка обновляется ежедневно, но на ней представлены не все валюты, а только самые востребованные. Прочие валюты, которые обновляются ежемесячно, лежат в другой таблице. На нее можно перейти, щелкнув по радиокнопке "Група валют що змінюється щомісячно". Собственного url-адреса эта страница не имеет, единственный способ на нее попасть - щелчок мышью по кнопке.
Задача: Написать программу, которая бы автоматически загружала курсы всех валют с сайта в базу данных.
Решение: С ежедневными валютами проблем не возникло. С помощью HTTP GET получаем таблицу, сверяем дату, быстро пробегаем парсером и заносим в базу данных. Неожиданные проблемы возникли с получением ежемесячных валют.
Шаг первый.
Изучение исходного кода странички показало, что щелчок по радиокнопке присваивает переменной __EVENTTARGET значение Gr2 и страничка вызывает методом HTTP POST саму себя. Вроде бы ничего сложного. В исходном коде меняем GET на POST, в качестве параметра передаем __EVENTTARGET=Gr2. Но вместо ежемесячной таблицы мы получаем опять ежедневную. Тратим два дня на поиски несуществующих ошибок, перебираем все возможные способы передачи параметров.
Шаг второй.
Убеждаемся что программа работает, натравив ее на другие сайты интернета. Наша программа успешно справляется с автоматическим поиском в гугле и регистрацией на форумах. Но сервер НБУ по-прежнему выдает только ежедневные валюты. Читаем документацию по технологии ASPNet. В процессе изучения форумов, выясняем, что все запросы к aspx должны таскать за собой параметр __VIEWSTATE, который нигде не используется, но без него сервер запрос не обрабатывает. Добавляем в запрос этот параметр. Но в ответ опять получаем ежедневные валюты. Тратим еще два дня на поиски несуществующих ошибок, перебираем все возможные способы формирования параметра __VIEWSTATE.
Шаг третий.
Устанавливаем программу HTTPAnalyzer, чтобы понять, чем запрос формируемый нашей программой отличается от запроса, отсылаемого браузером в момент нажатия кнопки. Выясняется, что размер параметра __VIEWSTATE в запросе браузера больше, чем размер параметра, что передает наша программа, и собственно больше оригинального, который нам возвращает сервер банка. Исследуя это явление, узнаем, что перед отсылкой параметр необходимо закодировать алгоритмом UUEncode. Тратим два дня на поиски удобной реализации этого алгоритма.
Шаг четвертый.
Отчаявшись приспособить найденное в интернете плюем на все и сравнивая запрос нашей программы с эталоном, самостоятельно пишем упрощенный вариант UUEncode. Но увы. Привычно наблюдаем ежедневные валюты в ответе сервера. Показываем экрану кукиш и неделю не подходим к компьютеру.
Шаг пятый.
Опять запускаем HTTPAnalyzer и сравнивая запрос нашей программы с запросом Оперы получаем, шифруем и передаем прочие неиспользуемые параметры asp-формы. Добиваемся идеального совпадения запроса нашей программы с эталонными запросами Оперы и Файрфокса. Но Опера и ФФ получают, что и требуется, ежемесячные валюты, а наша программа - опять ежедневные.
Еще шаг.
Через два дня внимательно изучая логи HTTP запросов и ответов, видим что браузеры кроме самого запроса передают еще и хитрые куки (cookies) ASP-сессии. Учим и нашу программу работать с куками.
И ТОЛЬКО ТЕПЕРЬ получаем необходимую нам таблицу. Хлопки шампанского, апплодисменты. Акробаты кланяются, лошади тяжело дышат.
После боя.
Проверяем, работала бы программа, если бы мы сразу догадались про куки. А вот и не работала бы. Все попытки обойтись без одного из вышеописанных шагов не приводят к желаемому результату. Спасибо и на этом.
Заранее предупреждаю любого, кто хочет блеснуть эрудицией и предложить здесь более простой способ решения проблемы. Я еще не перевел дыхание и не затупил когти. И готов загнать любого смельчака на вершину самого высокого кактуса.
И еще: Нет, я не программист.
Спасибо за внимание.
No comments:
Post a Comment