Lucifaer's Blog.

如何解决Pyppeteer的Target closed错误

Word count: 699 / Reading time: 3 min
2018/12/14 Share

最近写自己的Sniper遇到的一个问题,很有意思。

如果你之前用过Chrome Headless的话,你一定知道Chrome亲儿子Puppeteer——Chrome官方提供的Nodejs的API。比较难受的是官方并没有提供Python的API项目来让我等以Python为生的人享受良好的使用体验。所以如果有尝试过利用Python来写Chrome Headless项目的,一定会知道Pyppeteer这个第三方库。这篇文不说这个库怎么用(请看Puppeteer的文档),而是说在使用Pyppeteer进行页面交互时经常会出现的Protocol error Target.activateTarget: Target closed.错误的解决方案。

什么时候会出现这个错误?

简单来说,就是在利用Pyppeteer操作Chrome Headless执行js进行页面内容提取或交互时会出现这个错误。具体一点说,就是你在执行类似page.screenshot()page.evaluate()这类操作的时候可能会出现这个问题,尤其是在你处理的页面过长,比如需要你执行惰性加载的页面过长时就会出现这个错误。

出现问题的原因?

无论Pyppeteer还是Puppeteer他们都是通过WebSocket来与Chrome Headless进行通讯的,也就是说整个连接的流程应该是:

1
Internals>Headless Blink>Network>WebSockets

在本地,Chrome Headless相当于一个WebSocket服务器,而PyppeteerPuppeteer是用底层的WebSocket客户端与Chrome Headless进行通信,从而执行各种操作的。

WebSocket检查连接是否超时是通过ping连接是否超时来确定的,首先客户端向服务端发送ping请求,服务端处理请求并给客户端一个pong的响应,如果服务端无法处理ping请求,即不会向客户端发送pong响应,客户端就会断开和服务端的连接,而这就是出现这个问题的关键。

Chrom Headless在今年报了一个bug,简单来说就是Chrome Headless的WebSocket服务器无法处理ping请求,也就是处理ping时不会返回pong,这就导致客户端一定会在20s左右的时间断开与Chrome Headless的连接,所以会显示连接目标已经关闭的这个错误。

解决方案

目前还没有一个特别好的解决方案,比较好的解决方案是降低WebSocket评定连接断开的优先级,也就是让客户端不发送ping请求,这样至少会把断开的时间从20s延长至15分钟。

Pyppeteer的解决方案,在github已经有人提出,但是patch并未合并到主分支上,所以需要自己本地改一下。#159

pyppeteer/pyppeteer/connection.py的43行:

1
2
self._ws = websockets.client.connect(
self._url, max_size=None, loop=self._loop)

Reference

CATALOG
  1. 1. 什么时候会出现这个错误?
  2. 2. 出现问题的原因?
  3. 3. 解决方案
  4. 4. Reference