[771]如何正确移除 Pyppeteer 中的window.navigator.webdriver

由于Selenium启动的Chrome中,有几十个特征可以被识别,所以在爬虫界已经没有以前那么受欢迎了。模拟浏览器的新秀Puppeteer异军突起,逐渐受到了爬虫界的关注。Puppeteer需要使用JavaScript来控制,如果你是用Python,那么就需要使用Pyppeteer.

如果你使用模拟浏览器爬淘宝,你会发现,无论怎么修改参数,Selenium总是可以立刻被识别。但是如果你使用了本文的方法,用Pyppeteer抓取淘宝,你就会发现另外一个广阔的天地。

今天,我们来讲讲如何在Pyppeteer中隐藏 window.navigator.webdriver

首先,我们使用下面的代码,通过Pyppeteer打开浏览器窗口:

import asyncio
from pyppeteer import launch

async def main():
    browser = await launch(executablePath='/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
                           headless=False)
    page = await browser.newPage()
    await page.goto('http://exercise.kingname.info')
    input('测试完成以后回到这里按下回车...')
    await browser.close()
asyncio.get_event_loop().run_until_complete(main())

代码运行以后,会打开Chrome浏览器,并访问 http://exercise.kingname.info/(这是我写的爬虫练习网站,大家可以用这个网站练习爬虫开发,里面有几道题挺难_)

在这个浏览器中,我们打开开发者工具,查询 window.navigator.webdriver会发现它的值为 true。如下图所示:

[771]如何正确移除 Pyppeteer 中的window.navigator.webdriver_第1张图片

网上的代码,无外乎注入JavaScript,在网页自带的JavaScript加载之前,提前运行一段JavaScript,修改查询 window.navigator.webdriver的接口。

这种方式每开一个新页面都要执行一次,繁琐,愚蠢!

那么正确的办法是什么呢?

我写这篇文章的时候(2019-08-15),Pyppeteer的最新版本为0.0.25,如下图所示:

[771]如何正确移除 Pyppeteer 中的window.navigator.webdriver_第2张图片

此时,你可以在PyCharm中,按住Command键(Windows、Linux用户按住Ctrl键),鼠标左键点击 frompyppeteerimportlaunch中的 launch,自动跳转到Pyppeteer源代码中的 launcher.py文件。

[771]如何正确移除 Pyppeteer 中的window.navigator.webdriver_第3张图片

把代码往上翻,在第60行左右,找到如下图方框框住的代码:

[771]如何正确移除 Pyppeteer 中的window.navigator.webdriver_第4张图片

--enable-automation这一行注释掉。此时PyCharm会提示你是否修改源代码,选择OK。如下图所示。

[771]如何正确移除 Pyppeteer 中的window.navigator.webdriver_第5张图片

修改完成以后的代码如下图所示:

[771]如何正确移除 Pyppeteer 中的window.navigator.webdriver_第6张图片

以上就是你需要做的全部修改。

重新运行刚才的代码,你会发现, window.navigator.webdriver已经是 undefined了。如下图所示。

[771]如何正确移除 Pyppeteer 中的window.navigator.webdriver_第7张图片

在Pyppeteer即将发布的0.0.26版本的功能里面,我看到了如下图方框框住的一项:

[771]如何正确移除 Pyppeteer 中的window.navigator.webdriver_第8张图片

所以,等0.0.26版本发布以后,我们就可以直接通过传递参数来禁用 --enable-automation了,不再需要修改源代码了。

然而时过境迁,随着 Chrome 版本升级,这一方法也宣告失效。

今天的方法非常简单,不需要修改源代码。

大家阅读 Selenium 版的文章,应该看到我们的原理是通过 CDP 执行一段 JavaScript 代码。这段代码中有一个关键词叫做addScriptToEvaluateOnNewDocument。表示添加一段脚本,在打开新文档时执行。

我们记住这个关键词EvaluateOnNewDocument。现在大家打开 Pyppeteer 的官方 API[1],搜索evaluateOnNewDocument可以看到原来 Pyppeteer 也是支持这个功能的。

这样一来文件就非常简单了,我们在 Pyppeteer 里面直接调用它,并传递 JavaScript 代码就好了:

import asyncio
from pyppeteer import launch

async def main():
    browser = await launch(executablePath='/Applications/Google Chrome.app/Contents/MacOS/Google Chrome', headless=False)
    page = await browser.newPage()
    await page.evaluateOnNewDocument('''() => {
        Object.defineProperty(navigator, 'webdriver', {
        get: () => undefined
        })
        }
    ''')
    await page.goto('http://exercise.kingname.info')
    input('检查完毕后按下回车键关闭窗口...')
    await browser.close()

asyncio.run(main())

代码的运行效果如下图所示:

[771]如何正确移除 Pyppeteer 中的window.navigator.webdriver_第9张图片

完美解决问题。并且只要你不开新的选项卡或者新的窗口,只在当前窗口打开新的网址或者刷新页面,这个 js 代码都是自动生效的,不需要重复执行。

其中关键的代码就是:

await page.evaluateOnNewDocument('''() => {
        Object.defineProperty(navigator, 'webdriver', {
        get: () => undefined
        })
        }
    ''')

让 Pyppeteer 在每个新页面加载的时候,所有网站自带的 js 执行之前,执行参数中的这段JavaScript 函数。

来源:https://mp.weixin.qq.com/s?__biz=MzI2MzEwNTY3OQ==&mid=2648977634&idx=1&sn=c5509d44b4527017a1d9fd9d690e6d60&scene=21#wechat_redirect
https://mp.weixin.qq.com/s/jN0cEFoAzE36p7fSgIQ2XQ

参考资料
[1]Pyppeteer 的官方 API: https://miyakogi.github.io/pyppeteer/reference.html#pyppeteer.page.Page.evaluateOnNewDocument

你可能感兴趣的:(爬虫)