| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > Java: Общие вопросы > Работа с веб страницами с помощью HttpClient |
| Автор: Platon 14.6.2008, 17:15 | ||||||||||||||||||||||||
| Здравствуйте, уважаемые. Решил оформить еще 1 фак для сообщества винградовцев. Это некий вводный туториал (tutorial), мануал (manual) или учебное пособие по работе с HttpClient. HttpClient позволяет скачать страницы с интернета с возможностью управлять Cookie и отправлять заголовки на сервер. Преамбула. Недавно, буквально позавчера, мне пришлось столкнуться с проблемой выкачки страницы с сайта. Благо, я слышал о таком магическом инструменте как http://hc.apache.org/httpclient-3.x/ (Apache как всегда рулит!!!) Его идея была ясна, и не хотелось рыться во всех этих документах, туториалах, примерах. Более того, как и все программисты я хочу всё и сразу и чтоб готовенькое. Начал рыться по винграду. Спасибо LSD по его ответам на форуме я сдвинулся с места. Но не хватало многих мелочей, которые таки заставили меня обратиться к официальным докам, туториалам и примерам. Чтоб уберечь нежные гениальные умы будущих поколений, я решил объединить все эти мелочи в одном месте. И так поехали. Основная часть. Выгружаю сразу код, в котором содержится весь материал.
Засекаем секундомеры! HttpClient можно расценивать как браузер, который не отображает страницу, а только содержит состояние, в котором работает пользователь. Это и все куки, которые устанавливаются в начале сеанса и которыми обменивается с сервером, это и данные авторизации (http://hc.apache.org/httpclient-3.x/authentication.html)
Для меня это были очень важные строчки, с ними я набил много шишек. Первая строчка устанавливает кодировку, в которой будут отправляться строки запроса методом GET и тело запроса методом POST Вторая строчка важна для работы с «выпечкой» Самая подходящая политика для работы с «печенюшками» большинства сайтов это именно CookiePolicy.BROWSER_COMPATIBILITY. Теперь перейдем к самим «печенькам». Браузер всегда находится в каком-то состоянии.
К примеру, пользователь может быть авторизован и при его желании сессия может быть сохранена в cookies. У нас это name и password, гипотетически позволяет работать от имени заранее заведенного аккаунта.
С инициализациией браузера разобрались, пробуем загрузить странички. 1. Методом GET
Всё интуитивно должно быть понятно. О различиях методов GET и POST читать в другом месте. Заострю лишь внимание на двух моментах: 1. Формируемый адрес обладает интересным URLEncoder.encode("Доктор Хаус", SITE_CHARSET) Не то, что бы интересен тут персонаж телесериала, хотя это тоже ^_^, сколько то, что он написан по-русски, а мы знаем, как буржуи дискредитируют нелатиницу, да еще и с проблелом. Все пробелы в адресных строках заменяются на +, а нелатиница заменяется спецстроками типа %FF в результате эта обертка URLEncoder'а поможет нам избавиться от головной боли с переводом в страшный текст: «%C4%EE%EA%F2%EE%F0+%D5%E0%F3%F1» Заметим также, что SITE_CHARSET вносит здесь свою лепту. Строчка выше — это кириллический текст в кодировке windows-1251, в кодировке utf-8 это будет выглядеть так: «%D0%94%D0%BE%D0%BA%D1%82%D0%BE%D1%80+%D0%A5%D0%B0%D1%83%D1%81» Вторая строчка. Я не уверен, что она тут, вообще, действует, так что ее можно проигнорировать. Идем дальше. Пора бы запустить наш запрос.
1-я строчка. Запускаем метод из определенного состояния: на сервер отсылаются все cookies объекта HttpClient, относящиеся к сайту. 2-я строчка. result содержит статус страницы (Мы помним самые известные 200 — страница загружена, 404 — страница не сужествует, 302 — сервер произвел переадресацию) 4-я строчка. выводим извлеченную страничку. getResponseBodyAsString(), от куда же метод знает в какой кодировке страничка? Можно подумать, что мы установили ее с помощью getMethod.getParams().setContentCharset(SITE_CHARSET); Ничего подобного :( Из ответа от сервера, ему передается заголовок Content-Type откуда извлекается кодировка. Если сервер не передаст нам этого заголовка — дело плохо. Об альтернативных способах получения странички чуть позже. 2. Методом POST
Знакомый шаблон? Да. Единственное существенное различие — это метод отправки данных POST. Теперь так лихо все параметры в адресную строку не засунуть. Расстраиваться не стоит у Apache всегда есть чем подсластить программисту жизнь. postMethod.addParameter("name", "Доктор Хаус"); хитрый метод addParameter разберется абсолютно со всеми проблемами сам, нет необходимости в перекодировании кириллического текста. НО, теперь нам важна строчка postMethod.getParams().setContentCharset(SITE_CHARSET);, тело запроса будет кодироваться в установленной кодировке. Здорово! Теперь бонус: Я писал о возможных проблемах метода HttpMethod.getResponseBodyAsString, если сервер не передаст кодировку, в которой написана страница. Альтернативой может послужить самостоятельная обработка сырых байтов переданных данных byte[] HttpMethod.getResponseBody(). Или же для больших документов можно обрабатывать страницу на лету с помощью метода HttpMethod.getResponseBodyAsStream(), если это, конечно, технически возможно. Например, со страницы может передаваться гигантских размеров xml структура, ее можно обрабатывать «на ходу» с помощью http://forum.vingrad.ru/faq/topic-158003.html Или как в нашем случае, не хранить данные, а сразу выдавать их в stdout. Еще 1 важный аспект работы с HttpClient Если в рамках одного экземпляра HttpClient вы работаете последовательно с несколькими объектами HttpMethod К примеру,
В этом кусочке кода обратите внимание на 4 строчку, releaseConnection позволяет закрыть соединение.
Это важный шаг в сторону того, чтобы всё шло так, как оно должно быть. Мы должны сказать HttpClient что мы закончили с соединением и оно может быть переиспользовано. Без таких шагов текущий HttpClient будет ждать неопределенное время, пока соединение освободится, для того, чтобы оно могло быть переиспользовано. А вообще, при работе с HttpClient стоит взять за правило конструкцию
О таймауте Работая с библиотекой, сразу не замечаешь критических моментов, таких как например бесконечное ожидание отклика от сервера. Да и такое бывает, но к счастью в HttpClient предусмотрена и такая функция. Смотрим:
Новшества тут 2-я строчка, которая устанавливает таймаут ожидания ответа, и 4-я строчка, в которой в переменной result хранится информация, о том, что HttpClient не дождался ответа с сервера По умолчанию HttpClient может ждать вечность, так что это нужно учесть. Есть также более тонкая настройка таймаутов для каждого запроса индивидуально, это делается аналогично 2-й строчке, только объект над которым будет совершаться действие - HttpMethod method.getParams().setSoTimeout(TIMEOUT_IN_MILLISECONDS) О SSL Приятно был удивлен, что и с SSL HttpClient благополучно разбирается самостоятельно!!! Т.е. нам не надо искать какие-то сертификаты, что-то шурудить, наворачивать. Согласно http://hc.apache.org/httpclient-3.x/sslguide.html мы можем работать с протоколом SSL также как с обычным незащищенным ^_^ Даже комментировать в коде нечего, один и тот же шаблон.
Послесловие Если бы кто-то до меня написал бы эту тему, я был бы очень рад. Но видимо прошло время потребления, пришло время производства! Принимайте, рецензируйте, пользуйтесь. Да, спонсор статьи мой блог о Java http://platon007.blogspot.com |
| Автор: Platon 17.6.2008, 15:11 |
| Совсем забыл затронуть тему загрузки файлов на сервер. На форуме есть http://forum.vingrad.ru/index.php?showtopic=201291&view=findpost&p=1446520 |
| Автор: Alenka_ 19.6.2008, 22:48 | ||
По поводу того, в какой кодировке сервер присылает ответ-
http://rfc.net/rfc2616.html То есть есть соглашение, что сервер должен использовать кодировку ISO-8859-1, когда не указывает ее в заголовках. Но все ли придерживаются этого соглашения?.. |
| Автор: Shaggie 20.6.2008, 07:28 |
| Platon, спасибо!!! Я давненько (признаться, не напрягаясь) искал аналог перлового LWP на Java, и HttpClient в этой роли выглядит как самое то! |
| Автор: Platon 21.7.2008, 13:36 |
| Странно, что никто меня не подправил. Обновил статью. Добавил информацию по поводу HttpMethod#releaseConnection() |
| Автор: Platon 2.8.2008, 08:08 |
| Обновил статью, добавил информацию о таймаутах. |
| Автор: sith 6.8.2008, 22:40 |
| ... думаю что можешь обновить статью в плане работы с SSL... там все просто... но все же для полной картины... |
| Автор: unkis 7.8.2008, 00:31 |
| Было бы действительно неплохо написать про SSL |
| Автор: Platon 8.8.2008, 20:39 |
| Эх-эх-эх, я в обычной жизни то с SSL тут не работал, а вы мне предлагаете написать о SSL, ок попробую, разберусь заодно с SSL |
| Автор: Platon 29.8.2008, 14:28 |
| Обновил статью опять о releaseConnection() |
| Автор: priboltik 4.3.2009, 11:18 | ||||
| а почему не написали о том, что делать, если классы не создаются?? например у меня при выполнении даже следующего кода:
выкидывало исключение:
пока не подключил библиотеку commons-logging:http://commons.apache.org/logging/ |
| Автор: Nymph666 21.2.2013, 08:19 | ||||||||||
Сейчас как раз занимаюсь тем, что пытаюсь получить ответ от Google-поиска через метод Get. Но столкнулась со следующей ошибкой: если напрямую выводить в форму на страницу getMethod.getResponseBodyAsString(), то выдается warning, что Размер стринга слишком большой и рекомендуется использовать getMethod.getResponseBodyAsStream(). Пробую делать это с помощью стрима: Сначала получаю нужный адрес:
Затем обрабатываю результат (Document) следующей функцией, которая как раз должна нам возвращать html-код:
Затем загоняю этот результат в переменную private HTML googleHtml; И вывожу ее с помощью panel от GWT:
Но! Вылезает ошибка The markup in the document preceding the root element must be well-formed. И черт поймет что не так в этом документе. Возможно кто-то тоже использовал Stream. |