Playwright не может получить файлы cookie, недоступные для JS, библиотекa Camoufox
Файлы cookie для аутентификации присутствуют в браузере (как показано в dev tools), но Playwright не фиксирует/копирует их должным образом. Это обычная проблема с тем, как Playwarch обрабатывает файлы cookie?
Проблема
В dev tools можно увидеть файлы cookie для аутентификации
Но в сохраненных файлах cookie мы получаем только: GAESA, _dd_s (файлы cookie без авторизации) Файлы cookie Cloudflare (cf_clearance, __cf_bm)
Есть какой-нибудь выход?
Основная / фоновая проблема заключается в том, что Playstation не подключается к уже открытому/запущенному браузеру под определенным портом, а скорее открывает новый браузер, таким образом, пропуская существующий контекст, файлы cookie:
for i, (port, path, name) in enumerate(zip(config["ports"], config["paths"], config["names"])):
# Create server thread
server_thread = threading.Thread(target=run_server, args=(port, path))
servers.append(server_thread)
# Create browser automation thread
browser_url = f"ws://localhost:{port}/{path}"
browser_thread = threading.Thread(
target=automate_browser,
args=(browser_url, name)
)
browser_automations.append(browser_thread)
Обновление
Python/Playwright открывает Camoufox браузер (похоже внутри некого сервера) на определённом порту — ✅
for i, (port, path, name) in enumerate(zip(config["ports"], config["paths"], config["names"])): # Create server thread server_thread = threading.Thread(target=run_server, args=(port, path)) servers.append(server_thread) # Create browser automation thread browser_url = f"ws://localhost:{port}/{path}" browser_thread = threading.Thread( target=automate_browser, args=(browser_url, name) ) browser_automations.append(browser_thread) # Start all servers with delays print(f"Starting {len(servers)} servers...") for i, server in enumerate(servers): print(f"Starting server {i+1} on port {config['ports'][i]}...") server.start() time.sleep(config["server_settings"]["start_delay"]) print("All servers started. Starting browser automation...") # Start all browser automations with delays for i, browser_automation in enumerate(browser_automations): browser_automation.start() if i < len(browser_automations) - 1: # Don't sleep after the last one time.sleep(config["server_settings"]["browser_delay"])
Выходит что browser_url будет такой: ws://localhost:2525/browser2525, где 2525 - некий порт для последующего подключения.
Вручную логинюсь в google и Midjourney (на основе google логина) — ✅
Этот Camoufox браузер должен оставаться работающим долгое время чтобы другие скрипты могли к нему подключаться и работать с ним.Другим скриптом пытаюсь подключиться к открытому браузеру — ❌
async def connect_to_session(self, port): if not await self.check_camoufox_availability(port): raise Exception(f"Camoufox WebSocket port {port} not accessible") ws_url = f"ws://localhost:{port}/browser{port}" browser = await self.playwright.firefox.connect(ws_url)
ws_url (Web Socket URL) идентична browser_url в коде пункта 1
Но при выполнении кода Playwright не подключается к существующему открытому браузеру а запускает новый, соответственно БЕЗ контекта, пустой... ❌
Обновление 2
Camoufox: запускает как сервер так и браузер.
Разница заключается в принципе работы Camoufox по сравнению с обычным Firefox.
Ключевое отличие
Обычный Firefox:
- Прямой запуск: playwright.firefox.launch() → Окно браузера появляется сразу.
- Сервер не требуется: Playwright напрямую управляет процессом браузера.
- Простота: один процесс, одно соединение.
Camoufox:
- Серверная архитектура: launch_server() → Создает сервер WebSocket → Браузер подключается к нему.
- Два процесса:
- Серверный процесс (прослушивает порт XXXXX)
- Процесс браузера (подключается к серверу)
- WebSocket-связь: все команды проходят через сервер
? Почему Camoufox нуждается в сервере:
- Функции защиты от обнаружения: сервер обрабатывает ротацию прокси, маскировку отпечатков пальцев и т. д.
- Удаленное управление: несколько клиентов могут подключаться к одному и тому же экземпляру браузера
- Скрытый режим: сервер управляет возможностями браузера по скрытию
- Управление прокси: сервер обрабатывает сложные конфигурации прокси
? Поток:
launch_server() → Сервер WebSocket (порт XXXXX) → Процесс браузера
↑
Playwright подключается сюда
? Вот почему:
- launch_server() блокирует — он запускает сервер на неопределенный срок.
- Нам нужны потоки — чтобы сервер не блокировал основной поток.
- Появляется окно браузера — когда процесс браузера подключается к серверу.
- Браузер быстро закрывается — если процесс сервера завершается или не запускается.
Camoufox is a stealthy, customized Firefox browser designed specifically for web scraping and bot detection evasion.
Ответы (1 шт):
Для своих задач я сильно не мудрил, просто использую пользовательские профили - user_data_dir.
Первый скрипт у меня ничего особого не делает, просто запускает браузер с указанием директории профиля:
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
context = p.chromium.launch_persistent_context(
user_data_dir="./my-user-data",
headless=False,
args=[
"--disable-blink-features=AutomationControlled",
"--start-maximized",
],
)
page = context.new_page()
print("Открываем Google... авторизуйся и можешь завершать скрипт.")
page.goto("https://www.google.com/")
input("Проверь поведение и нажми Enter...")
context.close()
Я вручную захожу на нужные сайты (Google, Yandex и т.д.), прохожу авторизацию - все куки, токены, сессии и т.д. автоматически сохраняются в папку ./my-user-data. Так можно наделать сколько угодно профилей ./my-user-data1..n и потом ловко жонглировать сессиями уже в боевом скрипте.
Второй (боевой) скрипт запускает новый экземпляр браузера с нужным user_data_dir и соответственно содержит всю логику управления браузером:
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
context = p.chromium.launch_persistent_context(
user_data_dir="./my-user-data",
headless=False,
args=["--disable-blink-features=AutomationControlled", "--start-maximized"],
)
page = context.new_page()
print("Открываем Google...")
page.goto(f"https://www.google.com/")
# Твоя логика управления браузером.
input("Проверь поведение и нажми Enter...")
context.close()
И соответственно все авторизации остаются. Не надо бороться с капчами и т.д. Единственный минус что сессии на некоторых ресурсах протухают и нужно заново авторизовываться. Но для этого я просто запускаю первый скрипт, подставляю нужную папку в user_data_dir= и так же вручную перелогиниваюсь.
P.S. Но при новом открытии браузера будет задержка нежели при подключении к уже открытому...@Igor Savinkin
Я использую пул потоков для запуска множества браузеров, и мне нормально?.
Да, есть небольшая задержка, но зато я гарантированно получаю полную сессию и при этом сильно не ломаю себе мозг в плане реализации.
Для масштабируемости и надёжности - это оптимальный компромисс в моём случае.
Но здесь Вы запускаете chromium. А мы хотели бы сделать подобное с Camoufox. @Igor Savinkin - а в чём проблема? Принцип +- тот же ?♀️
from camoufox.sync_api import Camoufox
with Camoufox(
persistent_context=True, user_data_dir="./my-user-data-camoufox", headless=False
) as context:
page = context.new_page()
print("Открываем Google... авторизуйся и можешь завершать скрипт.")
page.goto("https://www.google.com/")
input("Проверь поведение и нажми Enter...")