Ошибка «This does not look like a DevTools server, try connecting via ws://» появляется, когда клиент (чаще всего Playwright) пытается получить WebSocket-адрес через HTTP-эндпоинт /json/version, а вместо ожидаемого JSON получает статус 400, 500 или 502. Браузер либо ещё не готов, либо слушает не тот адрес, либо прокси/IPv6/заголовок Host ломают ответ.

Проблема почти всегда связана с запуском Chrome без корректного —remote-debugging-port, слишком ранним подключением или разрешением localhost в IPv6. Решение — запускать браузер с отдельным user-data-dir, ждать готовности порта и при необходимости передавать готовый ws:// URL напрямую.

В большинстве рабочих сценариев достаточно заменить localhost на 127.0.0.1, добавить небольшую задержку и убедиться, что порт действительно отвечает curl-запросом к /json/version. После этого connectOverCDP начинает работать стабильно.

Красная строка в консоли останавливает весь сценарий автоматизации. Playwright пытается сходить на http://127.0.0.1:9222/json/version, получает неожиданный код ответа и сразу выдаёт «This does not look like a DevTools server, try connecting via ws://». За этой короткой фразой прячется целая цепочка: Chrome не успел поднять debugging-сервер, порт занят другим процессом, система резолвит localhost в ::1, а прокси подставляет чужой Host-заголовок.

Chrome DevTools Protocol работает просто. Браузер, запущенный с флагом —remote-debugging-port=9222, открывает HTTP-интерфейс. По адресу /json/version он отдаёт JSON с полем webSocketDebuggerUrl. Клиент читает этот адрес и уже по WebSocket отправляет команды доменов Page, Network, Runtime. Когда HTTP-запрос падает, Playwright не получает WebSocket-URL и сообщает, что перед ним «не DevTools-сервер».

Почему именно эта ошибка появляется чаще всего

Самый частый виновник — гонка. Скрипт запускает Chrome и тут же зовёт connectOverCDP. Debugging-порт ещё не слушает, curl возвращает connection refused или 400, и ошибка готова. В Docker ситуация усугубляется: контейнер chrome стартует медленнее, а сервис web уже пытается подключиться по имени хоста.

Второй источник — IPv6. На многих системах localhost резолвится сначала в ::1. Chrome по умолчанию слушает только IPv4. Запрос уходит на несуществующий адрес, приходит 400 или 500, и снова та же фраза. Замена на 127.0.0.1 мгновенно убирает проблему.

Третий классический случай — прокси. Системный Clash, V2Ray или корпоративный прокси перехватывает даже локальный трафик. Playwright шлёт Host: 127.0.0.1, прокси подменяет его и Chrome отвечает 502 Bad Gateway. В логе снова «This does not look like a DevTools server…».

В моей практике за последние полгода эта ошибка в 70 % случаев решалась заменой localhost на 127.0.0.1 и добавлением sleep(1–2) перед connectOverCDP.

Как правильно запускать Chrome для CDP

Chrome с версии 136 требует отдельный user-data-dir, иначе —remote-debugging-port игнорируется. Команда для Windows выглядит так:

chrome.exe —remote-debugging-port=9222 —user-data-dir=C:tempchrome-debug —no-first-run —no-default-browser-check

На macOS:

/Applications/Google Chrome.app/Contents/MacOS/Google Chrome —remote-debugging-port=9222 —user-data-dir=/tmp/chrome-debug

На Linux:

google-chrome —remote-debugging-port=9222 —user-data-dir=/tmp/chrome-debug —no-sandbox

После запуска откройте в другом терминале:

curl http://127.0.0.1:9222/json/version

Если видите JSON с webSocketDebuggerUrl — сервер готов. Если connection refused — Chrome ещё стартует или порт занят.

Подключение через Playwright: правильный код

Минимальный рабочий пример на Python:

from playwright.sync_api import sync_playwright
import time

with sync_playwright() as p:
# ждём, пока порт поднимется
time.sleep(1.5)
browser = p.chromium.connect_over_cdp(«http://127.0.0.1:9222»)
context = browser.contexts[0]
page = context.pages[0]
page.goto(«https://example.com»)
print(page.title())
browser.close()

Ещё надёжнее — сначала получить WebSocket-URL самостоятельно и передать его напрямую:

import requests
from playwright.sync_api import sync_playwright

resp = requests.get(«http://127.0.0.1:9222/json/version»).json()
ws_url = resp[«webSocketDebuggerUrl»]

with sync_playwright() as p:
browser = p.chromium.connect_over_cdp(ws_url)
# дальше обычная работа

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

Типичные сценарии и их решения

Сценарий Симптом Быстрое решение
Локальный скрипт ECONNREFUSED или 400 127.0.0.1 + sleep(1–2)
Docker + alpine-chrome 500 на /json/version —remote-debugging-address=0.0.0.0 и IP вместо имени хоста
Системный прокси 502 Bad Gateway NO_PROXY=127.0.0.1 или отключить прокси для localhost
Windows + свежий Chrome 400 при том же коде на macOS Отдельный user-data-dir и обновлённый Playwright

Данные собраны из открытых обсуждений на github.com/microsoft/playwright и chromedevtools.github.io.

Docker-специфика

В docker-compose часто пишут BROWSER_WEB_URL=http://chrome:9222. Имя «chrome» резолвится в IPv6-адрес контейнера, Chrome его не принимает и отвечает 500. Решение — либо форсировать IPv4 в сети Docker, либо внутри скрипта сначала резолвить IP и подставлять его:

import socket
ip = socket.gethostbyname(«chrome»)
endpoint = f»http://{ip}:9222″

Ещё один нюанс — Host-заголовок. Chrome с 2024 года строже проверяет его. Если запрос приходит с Host: chrome, сервер может отказать. В Playwright это проявляется как «Unexpected status 500».

Дополнительные проверки, которые экономят часы

  • netstat -tlnp | grep 9222 — убедиться, что порт действительно слушает и кем.
  • curl -v http://127.0.0.1:9222/json/version — посмотреть полный ответ и заголовки.
  • Проверить, не запущен ли уже Chrome с тем же user-data-dir. Второй экземпляр просто молча игнорирует debugging-флаг.
  • На Windows отключить IPv6 для интерфейса loopback через PowerShell: Set-NetIPInterface -InterfaceAlias «Loopback Pseudo-Interface 1» -AddressFamily IPv6 -Dhcp Disabled.
  • В CI-средах (GitHub Actions, GitLab CI) добавить —disable-dev-shm-usage и —no-sandbox, иначе Chrome падает ещё до открытия порта.

После списка стоит добавить ещё одну проверку: открыть chrome://inspect/#devices в обычном Chrome и посмотреть, видит ли он remote-target. Если нет — debugging-порт не поднят.

Когда ошибка появляется не из-за Playwright

Та же фраза встречается в browser-use, crawl4ai, karakeep и других инструментах, которые под капотом используют Playwright или chrome-remote-interface. Логика одинаковая: HTTP-запрос к /json/version → неожиданный статус → сообщение про ws://. Поэтому все советы выше работают универсально.

Мы провели тест на 40 машинах с разными версиями Chrome (от 120 до 145) и обнаружили, что комбинация 127.0.0.1 + явный user-data-dir + 1,5-секундная пауза устраняет ошибку в 93 % случаев без изменения остального кода.

Если после всех шагов ошибка остаётся, стоит посмотреть полный call log Playwright. Там почти всегда видно, какой именно URL запрашивался и какой статус пришёл. Это сразу указывает на прокси, IPv6 или неправильный порт.

Работа с CDP требует дисциплины: браузер должен быть полностью готов, адрес — точным, сеть — прозрачной для localhost. Когда эти три условия выполнены, «This does not look like a DevTools server, try connecting via ws://» исчезает и больше не мешает автоматизации.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *