不装 selenium:用 CDP 直接从本机 Chrome 取指定域 Cookie
写每日任务脚本时最麻烦的往往不是接口,而是登录态。把账号密码写进脚本既不安全,又随时可能被风控拦。更稳的做法是复用已经在跑的 Chrome:它已经完成过滑块、验证码,Cookie 是全的。我们要做的只是把这些 Cookie 按目标域取出来。
一、开调试端口,但不要暴露到公网
chrome.exe --remote-debugging-port=9333 ^
--user-data-dir=C:\your_profile --no-first-run端口只用 127.0.0.1 访问,不要为了省事写成 0.0.0.0——CDP 端口一旦被别的进程连上,等于把浏览器完全交出去。用 GET http://127.0.0.1:9333/json/version 探活即可判断是否可用。
二、必须连到 page,不能连 browser
这是第一个坑:/json/version 里给的是 browser 级 websocket,在它上面调 Page.navigate 常常静默不生效,调 Runtime.evaluate 又报找不到上下文。要操作页面,得从 /json 里挑 type == 'page' 的条目,连它的 webSocketDebuggerUrl。
def page_ws(substr=""):
for t in requests.get(CDP + "/json", timeout=8).json():
if t.get("type") == "page" and substr in t.get("url", ""):
return create_connection(t["webSocketDebuggerUrl"],
timeout=120, suppress_origin=True)
raise RuntimeError("no page tab")suppress_origin=True 不能省。新版 Chrome 会校验 Origin 头,不带这个参数握手阶段就被 403 掉,报错还只写在响应体里,很容易以为是端口没开。
三、取 Cookie:Storage.getCookies 比 Network 全
Network.getCookies 默认只给当前页面能用到的 Cookie,httpOnly、跨子域的会漏。Storage.getCookies 返回浏览器仓库里的全部条目,包含 domain、path、httpOnly、secure、expirationDate,后面按 host 筛选就靠它。
def cookie_rows(ws):
return cdp_call(ws, "Storage.getCookies").get("cookies") or []
def jar_for(rows, host):
best = {}
for c in rows:
d = (c.get("domain") or "").lstrip(".")
if not (host == d or host.endswith("." + d)):
continue
depth = d.count(".")
cur = best.get(c["name"])
if cur is None or depth < cur[0]:
best[c["name"]] = (depth, c["value"])
return {k: v[1] for k, v in best.items()}合并逻辑的关键是「同名取域名更宽的那份」:.example.com 这种根域 Cookie 才是服务端做会话校验时真正读到的那一条,子域上的同名条目多半是前端埋点写的。拍平(后写覆盖先写)会随机踩到错的那条,表现就是接口报 CSRF 或判定未登录。
四、执行 JS 记得 awaitPromise
def ev(ws, expr, wait=True):
ws.settimeout(60)
r = cdp_call(ws, "Runtime.evaluate",
{"expression": expr, "returnByValue": True, "awaitPromise": wait})
return (r.get("result") or {}).get("value")returnByValue 拿到的是可 JSON 化的值,否则返回的是 RemoteObject 引用,打印出来只有一堆 objectId。awaitPromise 配合表达式写成 (async () => {...})() 才能等到 fetch 完成。
另一个细节是超时:如果之前调过 drain()(把缓冲区里的事件读干净),socket 超时可能被留在 0.05 秒,下一次调用直接抛 WebSocketTimeoutException。每次正式调用前显式 settimeout(60) 比较稳。
小结
CDP 裸连的好处很实际:没有 webdriver 特征、不用装驱动、单文件几十行,拿到的 Cookie 与浏览器完全一致。要注意的只有四点——连 page 不是 browser、握手加 suppress_origin、按 host 和域名宽度筛 Cookie、给 socket 显式超时。
- 点赞
- 收藏
- 关注作者
评论(0)