Время прочтения: 5 мин.

Любой, кто когда-либо пытался парсить сайты на python начинал с простого запроса «get» библиотеки «requests». Запрос «get» выгружает html код страницы, который можно обрабатывать под свои нужды.

Но иногда данные доступны только после авторизации на ресурсе. В этом посте я покажу, как можно подключаться, используя логин-пароль и библиотеку «requests».

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

Возьмем сайт https://ivi.ru/ и попытаемся залогиниться.

Для авторизации требуется ввести email и пароль. В библиотеке requests есть метод «POST», с помощью которого реализуются отправки данных на сервер. Общий вид использования метода: «requests.post(url, headers, data)». «url» ссылка на ресурс, «headers» заголовки запроса, «data» данные запроса, которые мы будем передавать.

Импорт, авторизация и исходные параметры

Устанавливаем библиотеку:

pip install requests

Прежде всего, нужно узнать, откуда брать данные «headers» и «data». Для этого запустим инструмент разработчика. Переходим во вкладку СЕТЬ и обновляем страницу. Здесь видим все активности сети.

На главной странице сайта входим в профиль. Открывается форма авторизации, вводим логин-пароль и нажимаем кнопку ВОЙТИ. Ищем нашу ссылку.

Чтобы быстрее находить нужную строку в отображении полей нужно добавить поле «Method» и по нему отсортировать столбец. Данные на авторизацию отправляются в «POST» запросах.

Находим строку v5/

Смотрим информацию по этой строке

Во вкладке «headers» находим «General» в нем возьмем «url», в «Request Headers» нас интересует только «User-Agent», который пропишем в «headers», в «Form Data» данные для запроса «data».

import requests
url = 'https://api.ivi.ru/mobileapi/user/login/ivi/v5/'
headers = {
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 11_2_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36'
}
data = {
    'email': 'test@yandex.ru',
    'password': 'testTEST123',
    'device': 'OS X Chrome v.89.0.4389.90 3a7a0',
    'app_version': '870'
}

Создаем сессию, она будет держать наше соединение с сайтом, и мы сможем с ним работать.

session = requests.Session()
session.headers.update(headers)
response =  session.post(url, data=data)

Смотрим статус ответа

response
<Response [200]>

Ответ 200 означает успешный ответ от сервера.

Посмотрим, что возвратил наш запрос

response.json()
{'result': {'id': 1852143028,
  'gender': 0,
  'birthday': None,
  'session': 'ea85a1001852143028_1634027028-388944532m_RoMwwuIDe_NMcbmefXmw',
  'expiration': '2021-10-12T08:23:48Z',
  'firstname': None,
  'lastname': None,
  'subscribed': True,
  'origin_app_version': 870,
  'actual_app_version': 870,
  'payment_credentials': {},
  'email': 'test@yandex.ru',
  'email_real': 1,
  'msisdn': '',
  'confirmed': 1,
  'storageless': False,
  'is_debug': False,
  'children': [],
  'basic': '0.0000',
  'bonus': '0.0000'}}

Здесь важная строка «session», которая указывает на наш номер сессии. Дальше в примере будет видно, что, если бы мы не создали сессию, изменить данные нам бы не удалось.

Попробуем поменять данные профиля. Нажимаем на кнопку редактировать и меняем имя.

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

Записываем «url» и копируем «data». Необходимо обратить внимание на строку «session», где нужно передать наш номер сессии. Номер берем из ответа сервера.

url_change_nick = 'https://api.ivi.ru/mobileapi/user/info/v5/'
session_id = response.json()['result']['session']
data = {
'nick': 'test-test',
'kind': 'adult',
'lang': 'ru',
'tz': '+03:00',
'app_version': '870',
'session': session_id
}
response =  session.post(url_change_nick, data=data)

Чтобы удостовериться в работе нашего кода обновляем страницу в браузере.

Наш код успешно сработал.

Использование учетных данных WINDOWS

Также бывают редкие случаи, когда нужно использовать логин-пароль от учетной записи Windows. Для этого можно использовать библиотеку «requests-negotiate-sspi». Она становится особенно полезной, когда часто меняется пароль от учетной записи.

Устанавливаем и импортируем библиотеку, нам нужен метод «HttpNegotiateAuth»

pip install requests_negotiate_sspi
from requests_negotiate_sspi import HttpNegotiateAuth

Повторяем все, что делали выше: прописываем «headers», заполняем «data» и поднимаем сессию. Попробуем получить дату и время сервера.

Вначале сделаем запрос без передачи данных авторизации

xml_request = '''<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <GetServerDateTime xmlns="http://Server/" />
  </soap:Body>
</soap:Envelope>'''

headers = {
    'Host': host_name,
    'Content-Type': 'text/xml; charset=utf-8',
    'Content-Length': str(len(xml_request))
}

session.headers = headers
response = session.post('http://' + host_name + '/ServerService.asmx?WSDL', data=xml_request)
response
<Response [401]>

Посмотрим текст ответа

response.text
<title>401 - Unauthorized: Access is denied due to invalid credentials.</title>

Как мы видим ошибка авторизации.

Повторяем запрос с использованием «HttpNegotiateAuth»

response = session.post('http://' + host_name + '/ServerService.asmx?WSDL', auth=HttpNegotiateAuth(), data=xml_request)
response.text
<curDateTime>44298.576980902777</curDateTime>

Ответ на запрос даты и времени сервера получен успешно.

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