pyppeteer使用时常见的bug及解决办法【转载】

背景
最近时不时的会用到pyppeteer,一会儿是本地环境利用pyppeteer写个模拟浏览器的小脚本,一会儿是线上阿里云服务器上需要部署pyppeteer所写的脚本。中途遇到一些问题,最后都是通过goolge解决了。为了以后不再到处google,故写下此博客。

 

问题一
pyppeteer.errors.NetworkError: Protocol error Network.getCookies: Target close 或者
pyppeteer.errors.NetworkError: Protocol Error (Runtime.evaluate): Session closed. Most likely the page has been closed.
后来有人说可以把python第三方库websockets版本7.0改为6.0(反正在7.0版本以下就)就可以了,亲测可用。

pip3.6 uninstall websockets #卸载websockets
pip3.6 install websockets==6.0 #指定安装6.0版本```

 


问题二
chromium浏览器多开页面卡死问题
在浏览器初始化的时候launch里添加 ‘dumpio’:True。跟浏览器进程有关,至于为什么要这样我也不太清楚。

 

问题三
浏览器窗口很大,但是内容很小
上面的问题是需要设置浏览器显示大小,默认就是无法正常显示。

可以看到gmail页面只在左侧显示,右侧都是空白,网站内容并没有完整铺满chromium,底部横向滚动条拖拽还很不方便。

 

browser = await launch({'headless': False,'dumpio':True, 'autoClose':False,'args': ['--no-sandbox', '--window-size=1366,850']})
await page.setViewport({'width':1366,'height':768})

通过上面设置Windows-size和Viewport大小来实现网页完整显示。
但是对于那种向下无限加载的长网页这种情况如果浏览器是可见状态会显示不全,针对这种情况的解决方法就是复制当前网页新开一个标签页粘贴进去就正常了。

 

问题四
运行时,屏幕终端有很多不相关的日志打印
下面是帖子https://segmentfault.com/a/1190000018873537 解决办法
将pyppeteer类和websockets.protlcol类的log设置为WARNING级别,可以避免WARINIG级别下的log输出。此法,可以节省程序打印无用日志的时间和日志占用的巨大空间。

import logging
pyppeteer_level
= logging.WARNING logging.getLogger('pyppeteer').setLevel(pyppeteer_level) logging.getLogger('websockets.protocol').setLevel(pyppeteer_level) pyppeteer_logger = logging.getLogger('pyppeteer') pyppeteer_logger.setLevel(logging.WARNING)

 

问题五
程序首次运行时,会自动下载chromium,但是下载报错,提示ssl错误

[W:pyppeteer.chromium_downloader] start chromium download. Download may take a few minutes. HTTPSConnectionPool(host=‘storage.googleapis.com’, port=443): Max retries exceeded with url: /chromium-browser-snapshots/Win_x64/575458/chrome-win32.zip (Caused by SSLError(SSLError(1, ‘[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:833)’),))
解决办法:打开 /some/path/python3.6/lib/site-packages/pyppeteer/chromium_downloader.py,替换里面DEFAULT_DOWNLOAD_HOST = 'https://storage.googleapis.com’为DEFAULT_DOWNLOAD_HOST = 'http://storage.googleapis.com’即可,具体路径替换成自己的python路径。

 

问题六
pyppeteer.errors.NetworkError: Protocol error Runtime.evaluate: Target close
打开新标签页遇到的,解决办法根据https://github.com/miyakogi/pyppeteer/pull/160/files 这个文件进行更改pyppeteer包里面的connection.py文件即可。


问题七
在 centos系统中,首次运行pyppeteer会自动下载chromium,但是下载运行的过程中会报错:
/some/path/root/node_modules/puppeteer/.local-chromium/linux-543305/chrome-linux/chrome: error while loading shared libraries: libXss.so.1: cannot open shared object file: No such file or directory

 

sudo yum install google-chrome-stable
如果提示没有这个包,那就需要添加google的源来下载,如果没法访问google,那就需要找个镜像了,把下面的url替换成镜像的即可,添加文件/etc/yum.repo.d/google-chrome.repo:

[google-chrome]
name=google-chrome
baseurl=http://dl.google.com/linux/ch...$basearch
enabled=1
gpgcheck=1
gpgkey=https://dl-ssl.google.com/lin...
如果无法下载gpgkey,可以把gpgcheck的值改为0(如果你不介意安全问题),再运行一次yum的安装命令即可。

然后,chromium就可以正常下载了。

 

问题八

 

环境安装

 

  •   由于 Pyppeteer 采用了 Python 的 async 机制,所以其运行要求的 Python 版本为 3.5 及以上
  • pip install -i https://pypi.douban.com/simple pypeteer

 

首先 pip install pyppeteer , 这时候我们先看一下 websockets 这个库的版本,因为必须保证这个库是 7.0 的版本。8.0 和 6.0 虽然可以使用,但是在访问多个网页会出现一些无法解决的异常。现在安装 pyppeteer,websockets 的版本默认是 8.0,我们需要先pip uninstall websockets卸载 8.0,然后pip install websockets==7.0。然后我们按照 https://github.com/miyakogi/pyppeteer/pull/160/files 这个网页修改 pyppeteer 的源码(如果是 anaconda,则路径是 anaconda 安装路径\Lib\site-packages\pyppeteer\connection.py 这个文件)。这样准备工作就完成了,这样操作之后就可以避免很多异常。

 

需要这么费劲的折腾,是因为 pyppeteer 这个库已经很久没有做大的更新了,虽然有点小的改动,但是基本的 bug 还是没有解决。所以如果有 js 基础,最好还是使用 JavaScript 的 puppeteer 这个工具,这个是谷歌出品的,一直在更新维护,基本没有 bug。

补充:有时候会出现明明网页加载完成了,但是还是会出现超时的情况。不知道是什么 bug,解决方法也很简单,只要捕获这个异常,然后该做啥做啥。

以下有的方法前面带 coroutine 这个关键字,有点没有,这是因为带这个参数的方法都是异步方法,这种方法必须被 async 关键字修饰,调用的时候也必须 await 关键字修饰。不过我们既然使用浏览器爬虫了,肯定已经不在乎效率了,异步等于在等网站封,所以只需要遵守某些规则即可(不懂的请百度 asyncio 的使用),实际上还是同步运行。另外,虽然 page.on()这个方法是存在的,但是官方文档中并未给出详细的说明,甚至我查看 pyppeteer 的源码也未找到这个函数,不知道是怎么回事。但是参考 puppeteer 的文档也是可以用的,不过报错居多,我也就没有深究了。

 

pyppeteer第一次运行时,会自动下载chromium浏览器,时间可能会有些长。不过,我第一次运行时,直接报错:

 

ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1056)

尝试多种方法无果,无奈只能手动下载,但手动下载的方法网上资料也几乎没有,让我来做这个先行者吧。

 

上面代码运行虽然报错,但是控制台前两行却提供了很有用的信息:

 

[W:pyppeteer.chromium_downloader] start chromium download.
Download may take a few minutes.

 

可以看到,下载功能是由pyppeteer.chromium_downloader模块完成的,那么我们进入这个模块查看源码。

 

在这个模块源码中,我们可以看到downloadURLs、chromiumExecutable等变量,很明显指的就是下载链接和chromium的可执行文件路径。我们重点关注一下可执行文件路径

 

chromiumExecutable:
chromiumExecutable = {
'linux': DOWNLOADS_FOLDER / REVISION / 'chrome-linux' / 'chrome',
'mac': (DOWNLOADS_FOLDER / REVISION / 'chrome-mac' / 'Chromium.app' /
'Contents' / 'MacOS' / 'Chromium'),
'win32': DOWNLOADS_FOLDER / REVISION / 'chrome-win32' / 'chrome.exe',
'win64': DOWNLOADS_FOLDER / REVISION / 'chrome-win32' / 'chrome.exe',
}

 

可见,无论在哪个平台下,chromiumExecutable都是由是4个部分组成,其中 DOWNLOADS_FOLDER 和 REVISION是定义好的变量:

 

DOWNLOADS_FOLDER = Path(__pyppeteer_home__) / 'local-chromium'

 

进一步查看可以发现:

 

__pyppeteer_home__ = os.environ.get('PYPPETEER_HOME', AppDirs('pyppeteer').user_data_dir)
REVISION = os.environ.get('PYPPETEER_CHROMIUM_REVISION', __chromium_revision__)

 

所以,DOWNLOADS_FOLDER 和 REVISION都是读取对应环境变量设置好的值,如果没有设置,就使用默认值。我们来输出一下,看看默认值:

 

import pyppeteer.chromium_downloader
print('默认版本是:{}'.format(pyppeteer.__chromium_revision__))
print('可执行文件默认路径:{}'.format(pyppeteer.chromium_downloader.chromiumExecutable.get('win64')))
print('win64平台下载链接为:{}'.format(pyppeteer.chromium_downloader.downloadURLs.get('win64')))

 

输出结果如下:

 

默认版本是:575458
可执行文件默认路径:C:\Users\Administrator\AppData\Local\pyppeteer\pyppeteer\local-chromium\575458\chrome-win32\chrome.exe
win64平台下载链接为:https://storage.googleapis.com/chromium-browser-snapshots/Win_x64/575458/chrome-win32.zip

 

 在使用上面代码的时候,你可以将win64换成你的平台就好了,有了上面的下载链接,这个时候就可以先开始下载着chromium浏览器(有些慢),然后继续往下看。

 

对于版本,没什么好说的,是用默认的就好了。但是,对于chromium的可执行文件路径,默认是在C盘,对于有C盘洁癖的我,咋看咋不舒服,那就改了吧。从上面的分析中我们可以知道,C:\Users\Administrator\AppData\Local\pyppeteer\pyppeteer这一部分读取的是环境变量或者默认值,所以,我们可以通过配置环境变量改这一部分(或者也可以直接改源码,读取环境变量那一行,直接设为固定值),通过os.environ添加PYPPETEER_HOME这一变量值,例如我想把我的chromium放在D盘的Program Files文件夹下:

 

import os
os.environ['PYPPETEER_HOME'] = 'D:\Program Files'
import pyppeteer.chromium_downloader
print('默认版本是:{}'.format(pyppeteer.__chromium_revision__))
print('可执行文件默认路径:{}'.format(pyppeteer.chromium_downloader.chromiumExecutable.get('win64')))
print('win64平台下载链接为:{}'.format(pyppeteer.chromium_downloader.downloadURLs.get('win64')))

 

输出如下:

 

默认版本是:575458
可执行文件默认路径:D:\Program Files\local-chromium\575458\chrome-win32\chrome.exe
win64平台下载链接为:https://storage.googleapis.com/chromium-browser-snapshots/Win_x64/575458/chrome-win32.zip

 

 特别提醒:上面设置环境变量的那一行,必须在导入pyppeteer这一行千米,否则设置无效。

 

上面这种方法你需要在每次使用pypeeteer之前通过这行代码设置一下,实在麻烦,所以,我还是更愿意直接在windows系统里面添加这个变量:

 

 

虽然我们把环境变量设置为D:\Program Files,但是层层文件夹之后,才到真正的可执行文件chrome.exe,下载好的压缩包解压后,所有文件都在名为chrome-win的文件夹中,所以,我们需要在D:\Program Files创建local-chromium\575458这两个文件夹(575458是上面的版本号,记得修改为你的版本号),然后将解压得到的chrome-win文件夹,重命名为chrome-win32,然后直接拷贝进去就好,整个安装过程就完成了。

 

 

 

 

下载安装

使用 pip3 install pyppeteer 命令就能完成 pyppeteer 库的安装,至于 chromium 浏览器,只需要一条 pyppeteer-install 命令就会自动下载对应的最新版本 chromium 浏览器到 pyppeteer 的默认位置。

window 下 安装完 pyppeteer ,会在 python 安装目录下的 Scripts 目录下 有 pyppeteer-install.exe 和 pyppeteer-install-script.py 两个文件,执行 任意一个都可以安装 chromium 浏览器到 pyppeteer 的默认位置。

运行 pyppeteer-install.exe :

如果不运行 pyppeteer-install 命令,在第一次使用 pyppeteer 的时候也会自动下载并安装 chromium 浏览器,效果是一样的。总的来说,pyppeteer 比起 selenium 省去了 driver 配置的环节。

 

当然,出于某种原因,也可能会出现chromium自动安装无法顺利完成的情况,这时可以考虑手动安装:首先,从下列网址中找到自己系统的对应版本,下载chromium压缩包;

'linux': 'https://storage.googleapis.com/chromium-browser-snapshots/Linux_x64/575458/chrome-linux.zip'
'mac': 'https://storage.googleapis.com/chromium-browser-snapshots/Mac/575458/chrome-mac.zip'
'win32': 'https://storage.googleapis.com/chromium-browser-snapshots/Win/575458/chrome-win32.zip'
'win64': 'https://storage.googleapis.com/chromium-browser-snapshots/Win_x64/575458/chrome-win32.zip'
View Code

然后,将压缩包放到pyppeteer的指定目录下解压缩,windows系统的默认目录。

其他系统下的默认目录可以参照下面:

Windows: C:\Users\<username>\AppData\Local\pyppeteer
OS X: /Users/<username>/Library/Application Support/pyppeteer
Linux: /home/<username>/.local/share/pyppeteer
        or in $XDG_DATA_HOME/pyppeteer if $XDG_DATA_HOME is defined.

 

 

 

 

参考 一:https://www.sanfenzui.com/pyppeteer-bug-collection.html
参考二:https://segmentfault.com/a/1190000018873537


原文链接:https://blog.csdn.net/Mr__lqy/article/details/102626025

posted @ 2019-12-11 17:40  PythonGirl  阅读(3771)  评论(0编辑  收藏  举报