Парсинг и формы авторизации

Одним из первых вопросов, который возникает, когда вы начинаете двигаться дальше базового уровня скрапинга веб-сайтов, является: «Как получить доступ к информации за экраном входа?» Веб все больше и больше переходит к интерактивности, социальным сетям и контенту, создаваемому пользователями. Формы и входы являются неотъемлемой частью таких типов сайтов и практически невозможны к обходу. К счастью, с ними также относительно легко справиться.

До этого момента большая часть наших взаимодействий с веб-серверами в наших примерах скраперов состояла в использовании HTTP GET для запроса информации. Эта глава фокусируется на методе POST, который отправляет информацию на веб-сервер для хранения и анализа.

Формы в основном предоставляют пользователям способ отправить запрос POST, который веб-сервер может понять и использовать. Как и ссылочные теги на веб-сайте помогают пользователям форматировать GET-запросы, HTML-формы помогают им форматировать POST-запросы. Конечно, с небольшим количеством кода можно создать эти запросы сами и отправить их с помощью скрапера.

Библиотека Python Requests

Хотя возможно осуществлять навигацию веб-формы, используя только базовые библиотеки Python, иногда немного синтаксического сахара делает жизнь намного приятнее. Когда вы начинаете делать больше, чем простой GET-запрос с urllib, полезно обратиться к сторонним библиотекам Python.

Библиотека Requests отлично справляется с обработкой сложных HTTP-запросов, куки, заголовков и многого другого.

Вот что создатель Requests, Кеннет Райтц, говорит о базовых инструментах Python:

Стандартный модуль urllib2 в Python предоставляет большую часть возможностей HTTP, которые вам нужны, но его API полностью сломан. Он был создан для другого времени и другого веба. Для выполнения самых простых задач требуется огромное количество работы (даже переопределение методов).

Вещи не должны быть такими. Не в Python.

Как и любая библиотека Python, библиотеку Requests можно установить с помощью любого менеджера сторонних библиотек Python, такого как pip, или загрузить и установить исходный файл.

Отправка простой формы

Большинство веб-форм состоят из нескольких HTML-полей, кнопки отправки и страницы действия, где фактически обрабатывается форма. Поля HTML обычно состоят из текста, но могут также содержать загрузку файлов или другой нетекстовый контент. Большинство популярных веб-сайтов блокируют доступ к своим формам входа в файле robots.txt (в главе 18 обсуждается законность скрапинга таких форм), поэтому, чтобы играть на безопасном, я создал ряд различных типов форм и входов на pythonscraping.com, с которыми вы можете запустить свои веб-скреперы. http://pythonscraping.com/pages/files/form.html — это место нахождения самой базовой из этих форм. Вся форма выглядит следующим образом:

<form method="post" action="processing.php">
Имя: <input type="text" name="firstname"><br>
Фамилия: <input type="text" name="lastname"><br>
<input type="submit" value="Отправить">
</form>

Есть пара вещей, на которые стоит обратить внимание: во-первых, имена двух входных полей — имя и фамилия. Это важно. Имена этих полей определяют имена переменных параметров, которые будут отправлены на сервер при отправке формы. Если вы хотите имитировать действие, которое выполнит форма при POST-отправке ваших собственных данных, вам нужно убедиться, что ваши имена переменных соответствуют.

Во-вторых, следует отметить, что действие формы находится в processing.php (абсолютный путь — http://pythonscraping.com/files/processing.php). Любые POST-запросы к форме должны быть сделаны на этой странице, а не на странице, на которой сама форма находится. Помните: цель HTML-форм — только помочь посетителям веб-сайта форматировать правильные запросы для отправки на страницу, которая выполняет реальное действие. Если вы не занимаетесь исследованием форматирования запроса самостоятельно, вам не нужно заморачиваться слишком с этой страницей.

Отправка формы с использованием библиотеки Requests может быть выполнена за четыре строки, включая импорт и инструкцию для печати содержимого (да, это настолько просто):

import requests
params = {'firstname': 'Ryan', 'lastname': 'Mitchell'}
r = requests.post("http://pythonscraping.com/pages/processing.php", data=params)
print(r.text)

После отправки формы скрипт должен вернуть содержимое страницы: Привет, Ryan Mitchell! Этот скрипт можно применить к многим простым формам, встречающимся в интернете. Например, форма подписки на рассылку O’Reilly Media выглядит так:

<form action="http://post.oreilly.com/client/o/oreilly/forms/
quicksignup.cgi" id="example_form2" method="POST">
<input name="client_token" type="hidden" value="oreilly" />
<input name="subscribe" type="hidden" value="optin" />
<input name="success_url" type="hidden" value="http://oreilly.com/store/
newsletter-thankyou.html" />
<input name="error_url" type="hidden" value="http://oreilly.com/store/
newsletter-signup-error.html" />
<input name="topic_or_dod" type="hidden" value="1" />
<input name="source" type="hidden" value="orm-home-t1-dotd" />
<fieldset>
<input class="email_address long" maxlength="200" name=
"email_addr" size="25" type="text" value=
"Enter your email here" />
<button alt="Join" class="skinny" name="submit" onclick=
"return addClickTracking('orm','ebook','rightrail','dod'
);" value="submit">Join</button>
</fieldset>
</form>

Хотя на первый взгляд форма может показаться сложной, помните, что в большинстве случаев (исключения мы рассмотрим позже) вам нужно искать только две вещи:

  •  Имя поля (или полей), которые вы хотите отправить вместе с данными (в этом случае имя — email_addr)
  • Атрибут действия самой формы; то есть страница, на которую будет отправлен запрос (в этом случае http://post.oreilly.com/client/o/oreilly/forms/quicksignup.cgi)

Просто добавьте необходимую информацию и запустите код:

import requests
params = {'email_addr': 'ryan.e.mitchell@gmail.com'}
r = requests.post("http://post.oreilly.com/client/o/oreilly/forms/quicksignup.cgi",
data=params)
print(r.text)

В этом случае веб-сайт возвращает другую форму для заполнения, прежде чем вы сможете попасть в рассылку O’Reilly, но тот же самый концепт может быть применен и к этой форме. Однако я прошу вас использовать свои возможности для добра и не спамить издателя недействительными подписками, если вы хотите попробовать это дома.

Радиокнопки, чекбоксы и  другие элементы ввода

Очевидно, что не все веб-формы представляют собой набор текстовых полей, за которыми следует кнопка отправки. Стандартный HTML содержит широкий спектр возможных элементов ввода формы: переключатели (radio buttons), флажки (checkboxes) и поля выбора (select boxes), чтобы назвать только некоторые. HTML5 добавляет ползунки (range input fields), электронные почты, даты и многое другое. С помощью настраиваемых JavaScript-полей возможности бесконечны, с выбором цвета, календарями и чем угодно, что придумают разработчики следующим шагом.

Независимо от кажущейся сложности любого типа поля формы вам нужно беспокоиться только о двух вещах: имени элемента и его значении. Имя элемента можно легко определить, посмотрев на исходный код и находя атрибут name. Значение иногда может быть сложнее, поскольку оно может быть заполнено JavaScript непосредственно перед отправкой формы. Например, выбор цвета, как пример довольно экзотического поля формы, вероятно, будет иметь значение что-то вроде #F03030.

Если вы не уверены в формате значения поля ввода, вы можете использовать различные инструменты для отслеживания GET и POST запросов, которые ваш браузер отправляет туда и обратно. Лучший и, возможно, наиболее очевидный способ отслеживать GET-запросы, как уже упоминалось, — это посмотреть на URL сайта. Если URL выглядит примерно так:

http://domainname.com?thing1=foo&thing2=bar

вы знаете, что это соответствует форме такого типа

<form method="GET" action="someProcessor.php">
<input type="someCrazyInputType" name="thing1" value="foo" />
<input type="anotherCrazyInputType" name="thing2" value="bar" />
<input type="submit" value="Submit" />
</form>

которая соответствует объекту параметров Python

{'thing1':'foo', 'thing2':'bar'}

Если у вас возникли проблемы с формой, которая выглядит сложно, и вы хотите увидеть, какие параметры ваш браузер отправляет на сервер, самый простой способ — использовать инспектор или инструмент разработчика вашего браузера, чтобы просмотреть их

Инструмент разработчика Chrome можно открыть через меню, выбрав Просмотр → Разработчик → Инструменты разработчика. Он предоставляет список всех запросов, которые ваш браузер создает при взаимодействии с текущим веб-сайтом, и может быть хорошим способом подробно просмотреть состав этих запросов.

Отправка файлов и изображений

Хотя загрузка файлов распространена в интернете, загрузка файлов не является часто используемой функцией в веб-скрапинге. Однако возможно, что вам захочется написать тест для своего собственного сайта, который включает загрузку файла. В любом случае, полезно знать, как это сделать.

На странице http://pythonscraping/files/form2.html есть форма для загрузки файлов. Разметка формы на странице выглядит следующим образом:

<form action="processing2.php" method="post" enctype="multipart/form-data">
Submit a jpg, png, or gif: <input type="file" name="uploadFile"><br>
<input type="submit" value="Upload File">
</form>

За исключением того, что тег <input> имеет атрибут type со значением file , это в целом выглядит так же, как и текстовые формы, использованные в предыдущих примерах. К счастью, способ использования форм с библиотекой Python Requests также похож:

import requests
files = {'uploadFile': open('files/python.png', 'rb')}
r = requests.post('http://pythonscraping.com/pages/processing2.php', files=files)
print(r.text)

Обратите внимание, что вместо обычной строки значение, отправляемое в поле формы (с именем uploadFile ), теперь является объектом файла Python, возвращаемым функцией open. В этом примере вы отправляете файл изображения, хранящийся на вашем локальном компьютере, по пути ../files/Python-logo.png, относительно того места, откуда запускается сценарий Python. Да, это действительно так просто!

До сих пор мы в основном говорили о формах, которые позволяют вам отправлять информацию на сайт или просматривать необходимую информацию на странице сразу после заполнения формы. В чем разница между этим и формой входа, которая позволяет вам находиться в постоянном состоянии «входа в систему» на протяжении вашего посещения сайта?

Большинство современных веб-сайтов используют куки для отслеживания того, кто вошел в систему, а кто нет. После того, как сайт проверяет ваши учетные данные для входа в систему, он сохраняет их в куки вашего браузера, которые обычно содержат токен, сгенерированный сервером, время ожидания и информацию о отслеживании. Затем сайт использует этот куки как своего рода доказательство аутентификации, которое показывается на каждой странице, которую вы посещаете во время пребывания на сайте. До широкого распространения куки в середине 90-х годов прошлого века, сохранение пользователей в системе и отслеживание их было огромной проблемой для веб-сайтов.

Хотя куки являются отличным решением для веб-разработчиков, они могут вызывать проблемы для веб-скрейперов. Вы можете отправлять форму входа целый день, но если вы не отслеживаете куки, которые форма отправляет вам после этого, следующая страница, которую вы посетите, будет действовать так, как будто вы никогда не входили в систему.

Я создал простую форму входа на странице http://pythonscraping.com/pages/cookies/login.html (имя пользователя может быть любым, но пароль должен быть «password»). Эта форма обрабатывается на странице http://pythonscraping.com/pages/cookies/welcome.php, которая содержит ссылку на основную страницу, http://pythonscraping.com/pages/cookies/profile.php. Если вы попытаетесь получить доступ к странице приветствия или странице профиля без предварительного входа в систему, вы получите сообщение об ошибке и инструкции по входу в систему перед продолжением. На странице профиля проверяются куки вашего браузера, чтобы убедиться, что их куки были установлены на странице входа.

Отслеживать куки легко с помощью библиотеки Requests:

import requests
params = {'username': 'Ryan', 'password': 'password'}
r = requests.post('http://pythonscraping.com/pages/cookies/welcome.php', params)
print('Куки установлены:')
print(r.cookies.get_dict())
print('Переходим на страницу профиля...')
r = requests.get('http://pythonscraping.com/pages/cookies/profile.php', cookies=r.cookies)
print(r.text)

Здесь вы отправляете параметры входа на страницу приветствия, которая действует как обработчик для формы входа. Вы получаете куки из результатов последнего запроса, печатаете результат для проверки, а затем отправляете их на страницу профиля, установив аргумент cookies.

Это хорошо работает для простых ситуаций, но что, если вы имеете дело с более сложным сайтом, который часто изменяет куки без предупреждения, или если вы вообще не хотите думать о куки? Функция сеанса Requests session отлично подходит в этом случае:

import requests
session = requests.Session()
params = {'username': 'username', 'password': 'password'}
s = session.post('http://pythonscraping.com/pages/cookies/welcome.php', params)
print('Куки установлены:')
print(s.cookies.get_dict())
print('Переходим на страницу профиля...')
s = session.get('http://pythonscraping.com/pages/cookies/profile.php')
print(s.text)

В этом случае объект сеанса (полученный вызовом requests.Session() ) отслеживает информацию о сеансе, такую как куки, заголовки и даже информацию о протоколах, которые вы могли бы использовать поверх HTTP, такие как HTTPAdapters.

Библиотека Requests — фантастическая библиотека, вторая, возможно, только после Selenium (рассмотренной далее) по полноте того, что она обрабатывает без необходимости, чтобы программисты думали об этом или писали код самостоятельно. Хотя может быть соблазн просто откинуться и позволить библиотеке делать всю работу, очень важно всегда знать, как выглядят куки и что они управляют, когда вы пишете веб-скрейперы. Это может сэкономить много часов мучительного отладки или выяснения причин поведения сайта.

Базовая аутентификация HTTP

Перед появлением куки одним из популярных способов обработки входа была базовая аутентификация доступа HTTP. Встречается это время от времени, особенно на сайтах с высоким уровнем безопасности или корпоративных сайтах, а также в некоторых API. На странице по адресу http://pythonscraping.com/pages/auth/login.php, используется этот тип аутентификации (рисунок).

Аутентификация HTTP

Как обычно в этих примерах, вы можете войти с любым именем пользователя, но пароль должен быть «password».

В пакете Requests есть модуль auth, специально предназначенный для обработки аутентификации HTTP:

import requests
from requests.auth import HTTPBasicAuth

auth = HTTPBasicAuth('ryan', 'password')
r = requests.post(url='http://pythonscraping.com/pages/auth/login.php', auth=auth)
print(r.text)

Хотя это похоже на обычный запрос POST, в качестве аргумента auth в запросе передается объект HTTPBasicAuth. Результатом будет страница, защищенная именем пользователя и паролем (или страница с сообщением об отказе в доступе, если запрос не удался).

Другие проблемы форм

Веб-формы являются горячей точкой входа для вредоносных ботов. Вы не хотите, чтобы боты создавали учетные записи пользователей, занимали ценное время обработки сервера или отправляли спам-комментарии на блоге. Поэтому в современные веб-сайты часто внедряются функции безопасности, которые могут не быть сразу очевидными.

Для помощи с CAPTCHA посмотрите на раздел работы с каптчей, где рассматривается обработка изображений и распознавание текста на Python.

Если вы столкнулись с непонятной ошибкой или сервер отклоняет вашу отправку формы по неизвестной причине, обратитесь к к следующим разделам, где рассматриваются медовые ловушки, скрытые поля и другие меры безопасности, которые применяются веб-сайтами для защиты своих форм.

Индивидуальное и групповое обучение «Аналитик данных»
Если вы хотите стать экспертом в аналитике, могу помочь. Запишитесь на мой курс «Аналитик данных» и начните свой путь в мир ИТ уже сегодня!

Контакты
Для получения дополнительной информации и записи на курсы свяжитесь со мной:

Телеграм: https://t.me/Vvkomlev
Email: victor.komlev@mail.ru

Объясняю сложное простыми словами. Даже если вы никогда не работали с ИТ и далеки от программирования, теперь у вас точно все получится! Проверено десятками примеров моих учеников.

Гибкий график обучения. Я предлагаю занятия в мини-группах и индивидуально, что позволяет каждому заниматься в удобном темпе. Вы можете совмещать обучение с работой или учебой.

Практическая направленность. 80%: практики, 20% теории. У меня множество авторских заданий, которые фокусируются на практике. Вы не просто изучаете теорию, а сразу применяете знания в реальных проектах и задачах.

Разнообразие учебных материалов: Теория представлена в виде текстовых уроков с примерами и видео, что делает обучение максимально эффективным и удобным.

Понимаю, что обучение информационным технологиям может быть сложным, особенно для новичков. Моя цель – сделать этот процесс максимально простым и увлекательным. У меня персонализированный подход к каждому ученику. Максимальный фокус внимания на ваши потребности и уровень подготовки.

Понравилась статья? Поделиться с друзьями:
Школа Виктора Комлева
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!:

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.