Ошибка «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://» исчезает и больше не мешает автоматизации. Навигация по записям Как отключить Т9 на любом устройстве Как узнать виндовс на компьютере быстро и точно