Тема 13: Авторизация и Сессии: Как залогиниться на сайт, сохранить Cookies и поддерживать сессию живой?
Новички думают так: "Чтобы спарсить личный кабинет, я буду отправлять логин и пароль в каждом запросе". Это бан. Сервер увидит, что ты "входишь в дверь" 100 раз в секунду. Нормальные люди так не делают.
В вебе работает правило Ночного Клуба:
- Ты показываешь паспорт фейс-контролю (Логин/Пароль).
- Тебе ставят печать на руку (Cookie / Token).
- В баре ты показываешь печать, а не паспорт.
Твоя задача — получить печать один раз и хранить её, пока не смоется.
1. Инструмент: Сессия (Session / Client)
В requests и httpx есть понятие Сессии.
Это объект, который имеет "память". Если сервер прислал Cookies в первом ответе, Сессия запомнит их и сама подставит во второй, третий и десятый запрос.
-
Без сессии (Плохо):
-
С сессией (Хорошо):
2. Главная Ловушка: CSRF Token
Ты отправляешь правильный логин/пароль, но получаешь 403. Почему? Потому что на странице входа был скрытый код (CSRF Token), который сервер сгенерировал лично для тебя.
Алгоритм правильного входа:
- GET запрос на страницу логина.
- Парсим HTML, ищем скрытое поле:
<input type="hidden" name="csrf_token" value="a1b2c3...">. - POST запрос с логином, паролем И ЭТИМ ТОКЕНОМ.
3. Сохранение "Лица" (Persisting Cookies)
Парсер упал. Ты перезапускаешь его. Он снова лезет логиниться. Это подозрительно. Сеньор делает так: Залогинился -> Сохранил куки в файл. При перезапуске -> Загрузил куки из файла.
👨💻 КОД: Боевой Класс Авторизации
Напишем на httpx. Этот код умеет логиниться, обходить CSRF и сохранять сессию.
import httpx
import json
import os
from bs4 import BeautifulSoup
class AuthSession:
def __init__(self, cookies_file="cookies.json"):
self.client = httpx.Client(http2=True)
self.client.headers.update({
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
})
self.cookies_file = cookies_file
def load_cookies(self):
"""Пытаемся загрузить печать из файла"""
if os.path.exists(self.cookies_file):
with open(self.cookies_file, 'r') as f:
cookies = json.load(f)
# Загружаем куки в клиент
for name, value in cookies.items():
self.client.cookies.set(name, value)
return True
return False
def save_cookies(self):
"""Сохраняем печать на диск"""
cookies_dict = {c.name: c.value for c in self.client.cookies}
with open(self.cookies_file, 'w') as f:
json.dump(cookies_dict, f)
def login(self, url, username, password):
# 1. Сначала проверяем, жива ли старая сессия
if self.load_cookies():
# Делаем тестовый запрос в профиль
resp = self.client.get("<https://site.com/profile>")
if resp.status_code == 200 and username in resp.text:
print("✅ Старые куки работают! Логин не нужен.")
return True
else:
print("⚠️ Куки протухли. Логинимся заново...")
# 2. GET запрос за CSRF токеном
login_page = self.client.get(url)
soup = BeautifulSoup(login_page.text, "lxml")
# Ищем скрытый токен (имя поля зависит от сайта: csrf, _token, authenticity_token)
csrf_token = soup.find("input", {"name": "csrf_token"})
token_value = csrf_token["value"] if csrf_token else None
# 3. Формируем данные
payload = {
"username": username,
"password": password,
}
if token_value:
payload["csrf_token"] = token_value
# 4. POST запрос (Входим)
# Важно: используем тот же self.client!
resp = self.client.post(url, data=payload)
if resp.status_code == 200 or resp.status_code == 302:
print("🎉 Успешный вход!")
self.save_cookies() # Сохраняем на будущее
return True
else:
print("❌ Ошибка входа:", resp.status_code)
return False
# Использование
session = AuthSession()
session.login("<https://site.com/login>", "admin", "12345")
# Дальше парсим через session.client
response = session.client.get("<https://site.com/secret-data>")
4. Нюанс: Bearer Token (JWT)
На современных сайтах (SPA) вместо кук используют Token.
Сервер в ответ на логин присылает JSON: {"access_token": "eyJhbG..."}.
Что делать:
- Сохрани этот токен в файл (как строку).
-
При каждом запросе добавляй его в Заголовки, а не в куки:
🧠 Резюме Архитектора:
- Никогда не логинься в цикле.
- Используй
httpx.Client()илиrequests.Session(), чтобы держать стейт. - Всегда проверяй наличие CSRF токена перед отправкой пароля.
- Сохраняй куки/токены в файл. Твой парсер должен уметь "просыпаться" уже залогиненным.