Pyppeteer踩坑记录
[toc]
简介
pyperteer是puppeteer的Python实现,相比于selenium具有异步加载、速度快、具备有界面/无界面模式、伪装性更强不易被识别为机器人同时可以伪装手机平板等终端。官方文档链接
本来chrome就问题多多,puppeteer也是各种坑,加上pyppeteer是前两者的python版本,也就是产生了只要前两个有一个有bug,那么pyppeteer就会原封不动的继承下来,本来这没什么,但是现在遇到的问题就是pyppeteer这个项目从18年9月份之后就没更新过了,前两者都在不断的更新迭代,而pyppeteer一直不更新,导致很多bug根本没人修复。
launch常用配置
语法 | 值 | 描述 |
---|---|---|
ignoreHTTPSErrors | bool | 是否忽略 HTTPS 错误 |
headless | bool | 是否在无头模式下运行浏览器 |
executablePath | str | 运行 Chromium 或 Chrome 可执行文件的路径,而不是默认捆绑的 Chromium |
slowMo | float | 按指定的毫秒数减慢 pyppeteer 操作 |
args | list | 传递给浏览器进程的附加参数 |
dumpio | bool | 是否管道浏览器进程 stdout 和 stderr 进入 process.stdout 和 process.stderr。默认为 False |
userDataDir | str | 用户数据目录的路径 |
env | dict | 指定浏览器可见的环境变量。默认与 python 进程相同 |
devtools | bool | 是否为每个选项卡自动打开 DevTools 面板。如果是此选项 True,headless 则将设置该选项 False |
logLevel | str | 用于打印日志的日志级别。默认值与根记录器相同 |
loop | asyncio.AbstractEventLoop | 事件循环(实验) |
各种坑
1、浏览器窗口很大,内容显示很小
配置启动参数:
args=['--window-size=1280,720'],
defaultViewport={"width": 1280,"height": 720}
2、chromium浏览器多开页面卡死问题
配置启动参数:
dumpio=True
3、当使用pyppeteer一段时间之后,在.dev_profile文件夹里会产生大量的文件
设置autoClose=True,让它自动关闭的同时清理缓存文件或者手动执行await browser.close()
以上方法在某些时候会删除文件失败,我的解决方法是在每次启动前清空这个文件夹,代码如下
p = os.path.join(pyppeteer.__pyppeteer_home__, ".dev_profile")
shutil.rmtree(p, ignore_errors=True)
4、pyppeteer打印大量日志的问题
配置启动参数:
logLevel='ERROR'
5、程序运行自动下载chromium报错或者下载很慢
可以设置环境变量使用淘宝加速镜像
os.environ["PYPPETEER_DOWNLOAD_HOST"]="https://npm.taobao.org/mirrors"
或者设置参数executablePath指定已安装的chrome或者chromium路径
6、无法关闭(Chrome 正受到自动测试软件的控制)这个控制条
这个问题在旧版本的chrome中可以设置'--disable-infobars'启动参数解决,但是较新版的chrome已经去掉了这个功能,但可以设置参数ignoreDefaultArgs=['--enable-automation']来去掉,不过这有副作用。
7、page.click模拟点击网页跳转导致报错
可以通过以下方式调用click
await asyncio.gather(
page.waitForNavigation(),
page.click(selector),
)
8、page.goto超时之后偶尔失去响应
这是一个bug,Puppeteer最新版本中同样存在,解决方法是在捕获超时错误后执行以下代码
await page._client.send("Page.stopLoading")
9、网站超时不报错,进程假死
这类网站很奇怪,连用curl命令也不触发超时错误,查阅大量资料之后,想到一个解决方案,代码如下:
res = await asyncio.wait_for(page.goto(url, {
'waitUntil': ['load','networkidle0'],
"timeout": timeout
}), timeout / 1000 + 1)
10、屏蔽dialog弹窗,否则有弹窗的网站会导致进程会卡住
async def close_dialog(dialog):
await dialog.dismiss()
page.on("dialog", lambda x: asyncio.ensure_future(close_dialog(x)))
11、在docker容器中直接启动chrome报错
配置启动参数:
args=['--no-sandbox']
12、使用新版本chrome时经常卡住
配置启动参数:
args=['--disable-features=TranslateUI']
13、存在反调试的网站会导致浏览器直接卡死
一般情况过反调试
await page.evaluateOnNewDocument("()=>{Object.defineProperties(navigator,{webdriver:{get:()=>false}});")
过sojsonv6反调试
await page.evaluateOnNewDocument('()=>{Object.defineProperties(navigator,{webdriver:{get:()=>false}});var func=function(){};window["console"]["log"]=func;window["console"]["warn"]=func;window["console"]["debug"]=func;window["console"]["info"]=func;window["console"]["error"]=func;window["console"]["exception"]=func;window["console"]["trace"]=func;}')
14、部分网站会自动打开一个新的页面,数量多了之后会导致浏览器崩溃
每次访问网页之后都用await browser.pages()获取所有page,检测一下数量是否正常,如果异常可以遍历关闭page,也可以关闭浏览器,然后重启一个chrome实例。
15、长时间运行可能遇到有些网站在获取标题时超时,导致假死
捕获超时错误时第一件事就先发送停止命令await page._client.send("Page.stopLoading"),这个时候有些网站可能还是没停止加载,不过不会导致假死,然后不设延迟获取标题即可
网友评论