[633]pyppeteer驱动浏览器

2023-11-16

当使用selenium去某宝或其他网站进行爬虫或者模拟登陆时,会出现滑动验证码,并且无论是用ActionChains滑还是手动滑,都会很委婉的告诉你“哎呀网络错误,请刷新”等等。why?

爬虫都会碰到某些网站刚刚打开页面就被判定为:非人类行为,因为很多网站有对selenium的js监测机制。

经过科学上网,查阅众多资料,发现selenium有一些特征值, 例如下面:

window.navigator.webdriver
window.navigator.languages
window.navigator.plugins.length

1.“navigator.plugins.length”此参数可以检测selenium的headless模式,headless模式下为0,所以可以添加假的值来规避检测;
2.“navigator.languages”确保将此参数设置为chrome的默认值[“en-US”,“en”,“es”]

美团,大众,淘宝这些大站点都有这种技术能力。。对window.navigator.webdriver的检测机制。

正常情况下 window.navigator.webdriver的值为undefined。

而当我们使用selenium 的时候-window.navigator.webdriver的值为True。 如下图

手动安装
通过pip使用豆瓣源加速安装pyppeteer:

pip install -i https://pypi.douban.com/simple pypeteer
or
pip install pypeteer

按照官方手册,先来感受一下:

# -*- coding:utf-8 -*-
import asyncio
from pyppeteer import launch

async def main():
    browser = await launch(headless=False)
    page = await browser.newPage()
    await page.goto('http://www.baidu.com/')
    await asyncio.sleep(10)
    await browser.close()

asyncio.get_event_loop().run_until_complete(main())

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模块完成的,那么我们进入这个模块查看源码。

在这个模块源码中,我们可以看到downloadURLschromiumExecutable等变量,很明显指的就是下载链接和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_FOLDERREVISION是定义好的变量:

DOWNLOADS_FOLDER = Path.home() / '.pyppeteer' / 'local-chromium'

进一步查看可以发现:

from pathlib import Path
Path.home()
Out[3]: WindowsPath('C:/Users/WYXCz')
from pyppeteer import __chromimum_revision__ as REVISION

#__chromimum_revision__ = '543305'

REVISION = ‘543305’

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

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

输出结果如下:

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

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

3、主要操作

3.1 打开浏览器

打开浏览器是通过pyppeteer.launcher.launch(options: dict = None, **kwargs) 方法,运行该函数后,会得到一个pyppeteer.browser.Browser实例,也就是说浏览器对象实例。launch方法是必须使用的方法,所以,详细学学它的参数,你也直接阅读官方文档,因为我也是直接翻译的:

  • launcher.launch 这是实现浏览器的打开,里面有许多参数
  • ignoreHTTPSErrors (bool): 是否HTTPS错误,默认是 False.
  • headless (bool): 是否以无头模式(无界面模式)执行,默认为True,为True时是不会弹出可视界面的,所以,上面代码运行时设置headless=False。注意,下面还有个devtools参数,表示是否出现打开调试窗口,如果devtools设置为True,headless就算设置为False也会弹出可视界面。
  • executablePath (str): Chromium或Chrome浏览器的可执行文件路径,如果设置,则使用设置的这个路径,不使用默认设置.
  • slowMo (int|float): 设置这个参数可以延迟pyppeteer的操作,单位是毫秒.
  • args (List[str]): 要传递给浏览器进程的一些其他参数.
  • ignoreDefaultArgs (bool): 如果有些参数你不想使用默认值,那么,通过这个参数设置,不过,孩子,最好别用,有危险(电脑会爆炸).
  • handleSIGINT (bool): 是否响应 SIGINT 信号,是否允许通过快捷键Ctrl+C来终止浏览器进程,默认值为True,也就是允许.
  • handleSIGTERM (bool): 是否响应 SIGTERM 信号,也就是说kill命令关闭浏览器,,默认值为True,也就是允许.
  • handleSIGHUP (bool): 是否响应 SIGHUP 信号,即挂起信号,默认值为True,也就是允许.
  • dumpio (bool): 是要将浏览器进程的输出传递给process.stdout 和 process.stderr 对象,默认为False不传递。
  • userDataDir (str): 用户数据文件目录.
  • env (dict): 以字典的形式传递给浏览器环境变量.
  • devtools (bool): 是否打开调试窗口,上面介绍headless参数是说过,默认值为False不打开.
  • logLevel (int|str): 日志级别,默认和 root logger 对象的级别相同.
  • autoClose (bool): 当所有操作都执行完后,是否自动关闭浏览器,默认True,自动关闭.
  • loop (asyncio.AbstractEventLoop): 时间循环。
  • appMode (bool): Deprecated.

一般来说我们只是会设置headless,devtools,和传入一些必要的args

newPage()方法,相当于我们在浏览器里点开了新建选项卡
goto(),里面传入我们想要的url,即可前往指定的网页

选择器

Page类选择器相关方法有5个,并且这五个都有别名,分别是:

J()别名querySelector()
JJ()别名querySelectorAll()
JJeval()别名querySelectorAllEval()
Jeval()别名querySelectorEval()
Jx()别名xpath()

page.pdf(options)
  • options 具备以下属性的参数对象:

    • path 保存PDF文件的路径. 如果path 是一个相对路径,则它是相对于current working directory. 如果没有提供此值项值, 将不会保存PDF。
    • scale 网页缩放的值。默认为 1.
    • displayHeaderFooter Display header and footer. Defaults to false.
    • headerTemplate HTML template for the print header. Should be valid HTML markup with following classes used to inject printing values into them:
    • date formatted print date
    • title 文档标题
    • url 文档url
    • pageNumber 当前页码
    • totalPages 总页数
    • footerTemplate HTML template for the print footer. Should use the same format as the headerTemplate.
    • printBackground Print background graphics. Defaults to false.
    • landscape Paper orientation. Defaults to false.
    • pageRanges Paper ranges to print, e.g., ‘1-5, 8, 11-13’. Defaults to the empty string, which means print all pages.
    • format Paper format. If set, takes priority over width or height options. Defaults to ‘Letter’.
    • width Paper width, accepts values labeled with units.
    • height Paper height, accepts values labeled with units.
    • margin Paper margins, defaults to none.
    • top Top margin, accepts values labeled with units.
    • right Right margin, accepts values labeled with units.
    • bottom Bottom margin, accepts values labeled with units.
    • left Left margin, accepts values labeled with units.
  • returns: <Promise> Promise which resolves with PDF buffer.

NOTE 生成pdf的操作只有Chrome浏览器才有效。

page.pdf()print的 css media生成pdf,如果想生成一个 screenmedia的PDF,请在使用 page.pdf()之前调用page.emulateMedia(‘screen’)方法。

// Generates a PDF with 'screen' media type.
await page.emulateMedia('screen');
await page.pdf({path: 'page.pdf'});

width, height, 和 margin属性接受的值应该明确带上相应的单位,否则将会被默认为 px单位。

一些例子:

  • page.pdf({width: 100}) - 宽度为100px
  • page.pdf({width: '100px'}) - 宽度为100px
  • page.pdf({width: '10cm'}) - 宽度为 10厘米

所有可选的单位:

  • px - pixel
  • in - inch
  • cm - centimeter
  • mm - millimeter

format 属性的可选值:

  • Letter: 8.5in x 11in
  • Legal: 8.5in x 14in
  • Tabloid: 11in x 17in
  • Ledger: 17in x 11in
  • A0: 33.1in x 46.8in
  • A1: 23.4in x 33.1in
  • A2: 16.5in x 23.4in
  • A3: 11.7in x 16.5in
  • A4: 8.27in x 11.7in
  • A5: 5.83in x 8.27in
  • A6: 4.13in x 5.83in
3.2 调整窗口大小

如果你运行了上面的代码,你会发现,打开的页面只在窗口左上角一小块显示,看着很别扭,这是因为pyppeteer默认窗口大小是800*600,所以,调整一下吧。调整窗口大小通过方法实现,看下面代码,最大化窗口:

# -*- coding:utf-8 -*-
import asyncio
from pyppeteer import launch,chromium_downloader


def screen_size():
    '使用tkinter获取屏幕大小'
    import tkinter
    tk = tkinter.Tk()
    width = tk.winfo_screenwidth()
    height = tk.winfo_screenheight()
    tk.quit()
    return width, height

async def main():
    browser = await launch(headless=False)
    page = await browser.newPage()
    width, height = screen_size()
    # 最大化窗口
    await page.setViewport({
        'width': width,
        'height': height
    })
    await page.goto('http://www.baidu.com/')
    await asyncio.sleep(10)
    await browser.close()

asyncio.get_event_loop().run_until_complete(main())

3.3 设置userAgent
常规操作,不多说,上代码:

# -*- coding:utf-8 -*-
import asyncio
from pyppeteer import launch,chromium_downloader


def screen_size():
    '使用tkinter获取屏幕大小'
    import tkinter
    tk = tkinter.Tk()
    width = tk.winfo_screenwidth()
    height = tk.winfo_screenheight()
    tk.quit()
    return width, height

async def main():
    width, height = screen_size()
    '''
    利用launch方法传入args设定窗口大小,而后面那个disable-infobars则是去除那个浏览器的“chrome当前正在受自动化测试软件控制”这个选项卡
    '''
    browser = await launch(headless=False, args=[f'--window-size={width},{height}','--disable-infobars'])
    page = await browser.newPage()
    #设置请求头userAgent
    await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36')
    # 最大化窗口
    await page.setViewport({
        'width': width,
        'height': height
    })
    await page.goto('http://www.baidu.com/')
    await asyncio.sleep(10)
    await browser.close()

asyncio.get_event_loop().run_until_complete(main())
3.4 执行js脚本

有时候,为了达成某些目的(例如屏蔽网站原有js),我们不可避免得需要执行一些js脚本。执行js脚本通过evaluate方法。如下所示,我们通过js来修改window.navigator.webdriver属性的值,由此绕过网站对webdriver的检测:

import asyncio
from pyppeteer import launch


async def main():
    js1 = '''() =>{
        Object.defineProperties(navigator,{
            webdriver:{
                get: () => false
                }
        })
    }'''
    js2 = '''() => {
        alert (
        window.navigator.webdriver
        )
    }'''
    browser = await launch({'headless':False,'args':['–no-sandbox'],})
    page = await browser.newPage()
    await page.goto('https://h5.ele.me/login/')
    await page.evaluate(js1)
    await page.evaluate(js2)

asyncio.get_event_loop().run_until_complete(main())

在上面代码中,通过page.evalute方法执行了两段js脚本,第一段脚本将webdriver的属性值设为false,第二段代码在此读取 webdriver属性值,输出为false。

3.5 模拟操作

pyppeteer提供了Keyboard和Mouse两个类来实现模拟操作,前者是用来实现键盘模拟,后者实现鼠标模拟(还有其他触屏之类的就不说了)。

主要来说说输入和点击:

import asyncio
from pyppeteer import launch

async def main():
    browser = await launch(headless=False, args=['–disable-infobars'])
    page = await browser.newPage()
    await page.goto('https://h5.ele.me/login/')
    await page.type('form section input','12345678999') # 模拟键盘输入手机号
    await page.click('form section button') # 模拟鼠标点击获取验证码
    await asyncio.sleep(200)
    await browser.close()

asyncio.get_event_loop().run_until_complete(main())

上面的模拟操作中,无论是模拟键盘输入还是鼠标点击定位都是通过css选择器,似乎pyppeteer的type和click直接模拟操作定位都只能通过css选择器(或者是我在官方文档中没找到方法),当然,要间接通过xpath先定位,然后再模拟操作也是可以的。下一小节中模拟登陆外卖平台就是用这种方法,不过,这种方法要麻烦一些,不推荐。

3.6 某电商平台模拟登陆

我曾经用selenium + chrome 实现了模拟登陆这个电商平台,但是实在是有些麻烦,绕过对webdriver的检测不难,但是,通过webdriver对浏览器的每一步操作都会留下特殊的痕迹,会被平台识别,这个必须通过重新编译chrome的webdriver才能实现,麻烦得让人想哭。不说了,都是泪,下面直接上用pyppeteer实现的代码:

import asyncio
from pyppeteer import launch

def screen_size():
    #使用tkinter获取屏幕大小
    import tkinter
    tk = tkinter.Tk()
    width = tk.winfo_screenwidth()
    height = tk.winfo_screenheight()
    tk.quit()
    return width, height

async def main():
    js1 = '''() =>{
            Object.defineProperties(navigator,{
                webdriver:{
                    get: () => false
                    }
            })
        }'''
    js2 = '''() => {
        alert (
        window.navigator.webdriver
        )
    }'''
    browser = await launch({'headless':False, 'args':['--no-sandbox'],})
    page = await browser.newPage()
    width, height = screen_size()
    # 最大化窗口
    await page.setViewport({
        "width": width,
        "height": height
    })
    await page.goto('https://h5.ele.me/login/')
    await page.evaluate(js1)
    await page.evaluate(js2)
    input_sjh = await page.xpath('//form/section[1]/input[1]')
    click_yzm = await page.xpath('//form/section[1]/button[1]')
    input_yzm = await page.xpath('//form/section[2]/input[1]')
    but = await page.xpath('//form/section[2]/input[1]')
    print(input_sjh)
    await input_sjh[0].type('*****手机号********')
    await click_yzm[0].click()
    ya = input('请输入验证码:')
    await input_yzm[0].type(str(ya))
    await but[0].click()
    await asyncio.sleep(3)
    await page.goto('https://www.ele.me/home/')
    await asyncio.sleep(100)
    await browser.close()

asyncio.get_event_loop().run_until_complete(main())

登录时,由于等待时间过长(我猜的)导致出现以下错误:

pyppeteer.errors.NetworkError: Protocol Error (Runtime.callFunctionOn): Session closed. Most likely the page has been closed.

在github上找到了解决方法,似乎只能改源码,找到pyppeteer包下的connection.py模块,在其43行和44行改为下面这样:

self._ws = websockets.client.connect(self._url, max_size=None, loop=self._loop)
self._url, max_size=None, loop=self._loop, ping_interval=None, ping_timeout=None)

再次运行就没问题了。可以成功绕过官方对webdriver的检测,登录成功,诸位可以自己尝试一下。

4 总结

当使用selenium+webdriver写爬虫被检测到时,pyppeteer是你得不二选择,几乎所有能在人工操作浏览器进行的操作通过pyppeteer都能实现,且能完美避开官方对webdriver的检测。pyppeteer涉及的使用方法还很多,本文只介绍了常用方法的很小很小一部分,需要一说的是,pyppeteer的中文资料真的很少,多看看官方文档吧。

  • 基本操作总结
# -*- coding:utf-8 -*-
import asyncio
from pyppeteer import launch,chromium_downloader


def screen_size():
    '使用tkinter获取屏幕大小'
    import tkinter
    tk = tkinter.Tk()
    width = tk.winfo_screenwidth()
    height = tk.winfo_screenheight()
    tk.quit()
    return width, height

async def main():
    width, height = screen_size()
    '''
    利用launch方法传入args设定窗口大小,而后面那个disable-infobars则是去除那个浏览器的“chrome当前正在受自动化测试软件控制”这个选项卡
    '''
    browser = await launch(headless=False, args=[f'--window-size={width},{height}','--disable-infobars'])
    page = await browser.newPage()
    # 是否启用JS,enabled设为False,则无渲染效果
    await page.setJavaScriptEnabled(enabled=True)
    #设置请求头userAgent
    await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36')
    # 最大化窗口
    await page.setViewport({
        'width': width,
        'height': height
    })
    ## 超时间见 1000 毫秒
    res=await page.goto('http://www.baidu.com/',options={'timeout': 1000})
    resp_headers = res.headers  # 响应头
    resp_status = res.status  # 响应状态
    #页面截图
    await page.screenshot({'path': 'example.png'})
    # 滚动到页面底部
    await page.evaluate('window.scrollBy(0, document.body.scrollHeight)')
    # 打印页面cookies
    print(await page.cookies())
    # 获取所有 html 内容
    print(await page.content())
    # 在网页上执行js 脚本
    dimensions = await page.evaluate(pageFunction='''() => {
                return {
                    width: document.documentElement.clientWidth,  // 页面宽度
                    height: document.documentElement.clientHeight,  // 页面高度
                    deviceScaleFactor: window.devicePixelRatio,  // 像素比 1.0000000149011612
                }
            }''', force_expr=False)  # force_expr=False  执行的是函数
    print(dimensions)
    #  只获取文本  执行 js 脚本  force_expr  为 True 则执行的是表达式
    content = await page.evaluate(pageFunction='document.body.textContent', force_expr=True)
    print(content)
    # 打印当前页标题
    print(await page.title())
    # 抓取新闻内容  可以使用 xpath 表达式
    """
    # Pyppeteer 三种解析方式
    Page.querySelector()  # 选择器
    Page.querySelectorAll()
    Page.xpath()  # xpath  表达式
    # 简写方式为:
    Page.J(), Page.JJ(), and Page.Jx()
    """
    element = await page.querySelector(".feed-infinite-wrapper > ul>li")  # 只抓取一个
    print(element)
    # 获取所有文本内容  执行 js
    content = await page.evaluate('(element) => element.textContent', element)
    print(content)
    # elements = await page.xpath('//div[@class="title-box"]/a')
    elements = await page.querySelectorAll(".title-box a")
    for item in elements:
        print(await item.getProperty('textContent'))
        # <pyppeteer.execution_context.JSHandle object at 0x000002220E7FE518>
        # 获取文本
        title_str = await (await item.getProperty('textContent')).jsonValue()
        # 获取链接
        title_link = await (await item.getProperty('href')).jsonValue()
        print(title_str,title_link)
    await page.click("#J_SubmitStatic")
    # 使用page.pdf之前需要调用page.emulateMedia('screen')
    await page.emulateMedia('screen')
    await page.pdf({'path': 'page.pdf', 'width': '100px', 'format': 'A4'})  # 打印宽度设置为100像素
    await page.pdf({'width': '10cm'})  # 打印宽度设置为100厘米
    await asyncio.sleep(10)
    await browser.close()#关闭浏览器对象

asyncio.get_event_loop().run_until_complete(main())
  • 模拟登陆淘宝
# -*- coding:utf-8 -*-
import asyncio
import time, random
from pyppeteer.launcher import launch  # 控制模拟浏览器用
from retrying import retry  # 设置重试次数用的


async def main(username, pwd, url):  # 定义main协程函数,
    # 以下使用await 可以针对耗时的操作进行挂起
    # 启动pyppeteer 属于内存中实现交互的模拟器
    browser = await launch({'headless': False, 'args': ['--no-sandbox'], })
    page = await browser.newPage()  # 启动个新的浏览器页面
    await page.setUserAgent(
        'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36')

    await page.goto(url)  # 访问登录页面
    # 替换淘宝在检测浏览时采集的一些参数。就是在浏览器运行的时候,始终让window.navigator.webdriver=false
    # navigator是windiw对象的一个属性,同时修改plugins,languages,navigator 且让
    # 以下为插入中间js,将淘宝会为了检测浏览器而调用的js修改其结果。
    await page.evaluate('''() =>{ Object.defineProperties(navigator,{ webdriver:{ get: () => false } }) }''')
    await page.evaluate('''() =>{ window.navigator.chrome = { runtime: {},  }; }''')
    await page.evaluate('''() =>{ Object.defineProperty(navigator, 'languages', { get: () => ['en-US', 'en'] }); }''')
    await page.evaluate('''() =>{ Object.defineProperty(navigator, 'plugins', { get: () => [1, 2, 3, 4, 5,6], }); }''')

    # 使用type选定页面元素,并修改其数值,用于输入账号密码,修改的速度仿人类操作,因为有个输入速度的检测机制
    # 因为 pyppeteer 框架需要转换为js操作,而js和python的类型定义不同,所以写法与参数要用字典,类型导入
    await page.type('.J_UserName', username, {'delay': input_time_random() - 50})
    await page.type('#J_StandardPwd input', pwd, {'delay': input_time_random()})

    # await page.screenshot({'path': './headless-test-result.png'})    # 截图测试
    time.sleep(2)
    # 检测页面是否有滑块。原理是检测页面元素。
    slider = await page.Jeval('#nocaptcha', 'node => node.style')  # 是否有滑块
    if slider:
        print('当前页面出现滑块')
        # await page.screenshot({'path': './headless-login-slide.png'}) # 截图测试
        flag, page = await mouse_slide(page=page)  # js拉动滑块过去。
        if flag:
            await page.keyboard.press('Enter')  # 确保内容输入完毕,少数页面会自动完成按钮点击
            print("print enter", flag)
            # 如果无法通过回车键完成点击,就调用js模拟点击登录按钮。
            await page.evaluate('''document.getElementById("J_SubmitStatic").click()''')
            time.sleep(2)
            # cookies_list = await page.cookies()
            # print(cookies_list)
            await get_cookie(page)  # 导出cookie 完成登陆后就可以拿着cookie玩各种各样的事情了。
    else:
        await page.keyboard.press('Enter')
        print("print enter")
        await page.evaluate('''document.getElementById("J_SubmitStatic").click()''')
        await page.waitFor(20)
        await page.waitForNavigation()
        try:
            global error  # 检测是否是账号密码错误
            print("error_1:", error)
            error = await page.Jeval('.error', 'node => node.textContent')
            print("error_2:", error)
        except Exception as e:
            error = None
        finally:
            if error:
                print('确保账户安全重新入输入')
                # 程序退出。
                loop.close()
            else:
                print(page.url)
                await get_cookie(page)
                time.sleep(100)

# 获取登录后cookie
async def get_cookie(page):
    # res = await page.content()
    cookies_list = await page.cookies()
    cookies = ''
    for cookie in cookies_list:
        str_cookie = '{0}={1};'
        str_cookie = str_cookie.format(cookie.get('name'), cookie.get('value'))
        cookies += str_cookie
    print(cookies)
    return cookies

def retry_if_result_none(result):
    return result is None

@retry(retry_on_result=retry_if_result_none, )
async def mouse_slide(page=None):
    await asyncio.sleep(2)
    try:
        # 鼠标移动到滑块,按下,滑动到头(然后延时处理),松开按键
        await page.hover('#nc_1_n1z')  # 不同场景的验证码模块能名字不同。
        await page.mouse.down()
        await page.mouse.move(2000, 0, {'delay': random.randint(1000, 2000)})
        await page.mouse.up()
    except Exception as e:
        print(e, ':验证失败')
        return None, page
    else:
        await asyncio.sleep(2)
        # 判断是否通过
        slider_again = await page.Jeval('.nc-lang-cnt', 'node => node.textContent')
        if slider_again != '验证通过':
            return None, page
        else:
            # await page.screenshot({'path': './headless-slide-result.png'}) # 截图测试
            print('验证通过')
            return 1, page

def input_time_random():
    return random.randint(100, 151)


if __name__ == '__main__':
    username = 'xxxxxxxx'  # 淘宝用户名
    pwd = 'xxxxxxxxx'  # 密码
    url = 'https://login.taobao.com/member/login.jhtml?style=mini&css_style=b2b&from=b2b&full_redirect=true&redirect_url=https://login.1688.com/member/jump.htm?target=https://login.1688.com/member/marketSigninJump.htm?Done=http://login.1688.com/member/taobaoSellerLoginDispatch.htm&reg= http://member.1688.com/member/join/enterprise_join.htm?lead=http://login.1688.com/member/taobaoSellerLoginDispatch.htm&leadUrl=http://login.1688.com/member/'
    # 协程,开启个无限循环的程序流程,把一些函数注册到事件循环上。当满足事件发生的时候,调用相应的协程函数。
    loop = asyncio.get_event_loop()
    # 将协程注册到事件循环,并启动事件循环
    loop.run_until_complete(main(username, pwd, url))


pyppeteer OSError: Unable to remove Temporary User Data

运行pyppeteer时不时会报这个错误,虽然不影响到程序得运行,但是会影响到程序进程得关闭,这个错误是代表kill chrome 进程时失败。

然后再查看进程 发现程序关闭了,chrome进程依然在

解决办法 :

不要设置'args': ['--no-sandbox']

我的问题是这样解决的,

browser = await launch({'headless': False,'userDataDir':r'D:\temp'})

如果设置了userDataDir,有人说,不要设置–no-sandbox这个参数,但是并不能解决这个问题,今天看了pyppeteer的文档,想起来这个问题,原来我项目的临时数据目录是存在了c盘,但是当删除它的时候,应该是遇到了权限问题,没有权限没法删除啊,所以,如有遇到类似错误的朋友,自己在一个有权限删除的路径下,创建一个存储临时数据的目录,记住这个路径要有权限删除的哈。

也有可能是忘记关闭页面导致的错误,

await page.waitFor(30)
await page.close()

pyppeteer地址:https://github.com/miyakogi/pyppeteer

参考:https://blog.csdn.net/qq_42196922/article/details/85337709
https://blog.csdn.net/chenmh12/article/details/91296647
https://blog.csdn.net/weixin_44106928/article/details/89381209
https://blog.csdn.net/jiduochou963/article/details/88200217
https://zhuanlan.zhihu.com/p/63634783
http://www.pianshen.com/article/342820072/
https://www.cnblogs.com/zhang-zi-yi/p/10820813.html
https://www.jianshu.com/p/e52a287e0299
https://blog.csdn.net/deeplies/article/details/80861761#pagepdfoptions


https://blog.csdn.net/weixin_44143067/article/details/89678931
https://blog.csdn.net/qq_29570381/article/details/89737134
https://segmentfault.com/a/1190000018873537?utm_source=tag-newest

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

[633]pyppeteer驱动浏览器 的相关文章

  • IDEA查询项目中未被使用的代码

    IDEA查询项目中未被使用的代码 IDEA内置的很多功能非常强大 通过analyze分析功能 可以实现根据自己需求来检索未使用的内容 步骤如下 在弹出的输入框中 输入undeclared 然后选择下拉框中箭头指向内容 双击 下图中的选择方式
  • XML中的转义

    在XML中 有一些符号作为XML 的标记符号 一些特定情况下 属性值必须带有这些特殊符号 下面主要是讲解一些常用的特殊符号的处理 例一 双引号的使用 双引号作为XML 属性值的开始结束符号 因此无法在值中直接使用 处理方式可以分为两种 a
  • 时间序列分析全集-python3

    文章目录 1 导言 1 1 基本定义 1 2 预测评估指标 2 移动 平滑 评估 2 1 滑动窗口估计 2 1 1 moving average 2 1 2 weighted average 2 2 指数平滑 2 2 1 exponenti
  • U盘安装CentOS7

    官网找到CentOS7的ISO镜像 CentOS 7 x86 64 DVD 2207 02 iso 大小4 42G 准备一个8G的U盘 格式化 然后通过UltraISO工具将ISO镜像写入到U盘 接着开机启动U盘 华硕是按esc键 选择in
  • pip install 快速下载和安装包的方法

    一个 快速下载和安装包的方法 转载自他人 见下面链接 输入指令 pip default timeout 100 install 库名称 i http pypi douban com simple trusted host pypi doub
  • 在geany中使用中文注释

    geany中使用中文注释如果不加以特别说明会报错误 像这样 只需在首行指定编码格式 就可以愉快使用中文注释了 coding utf 8 coding utf 8 magicians alice david altman for magici
  • 通俗易懂的RNN

    目录 一 什么是RNN 二 为什么要发明RNN 三 RNN的基础知识 1 循环核介绍 2 循环核按时间步展开 3 记忆体 4 循环计算层 5 TF描述循环计算层 二 RNN的补充知识 1 RNN梯度消失的原因 一 什么是RNN RNN Re
  • 字符大全

    icon a m1 爱心符号 心形符号 扑克符号 1 m2 笑脸符号 2 gt c m3 商标符号 版权符号大全 3
  • Android TextView加载带有多张图片的HTML,并且解决图片造成的OOM

    版权声明 本文为博主原创文章 未经博主允许不得转载 转载请注明本文出自 renxhui 的博客 http blog csdn net qq 34760508 article details 70146189 请尊重他人的辛勤劳动成果 谢谢
  • 区块链能否开启人工智能金融2.0时代?

    随着人们对区块链技术地不断探索挖掘 区块链在金融领域的应用也是越来越多 其对传统金融机构的影响也越来越深 人们越来越期望能够利用区块链开启人工智能金融2 0时代 这将对银行业的再造与重构产生颠覆性的结果 随着全球区块链技术峰会的频繁举办 这
  • 获取任意月份天数

    获取月份天数 import java text ParseException import java text SimpleDateFormat import java util Calendar public class demo2 pu
  • 下载安装VMware,centos7,创建虚拟机一条龙

    1 vmware下载安装 1 阿里云盘下载 VMware workstation full 16 exe https www aliyundrive com s zxRkiiJnzmN 提取码 91mh 2 安装 双击exe 修改安装位置到
  • Stable diffusion模型种类说明

    1 基础模型 pruned是完整版模型 emaonly是剪枝版模型 如果想要训练自己的模型 需要下载完整的大模型 1 SD系列 sd v1 4 sd v1 5 sd v2之类的 都是stable diffusion自带的大模型 效果会比较差

随机推荐

  • 刷脸支付服务商红利市场不容错过

    相比当下流行的扫码支付 刷脸支付更便捷 资金流动更安全 且还有马云 马化腾多次亲自站台宣传 想不火都难 目前 与刷脸相关的网络热度词包括刷脸支付 手机扫码 消费者 人工智能 花钱等等 通过这些关联词也说明了一个问题 刷脸支付在落地方面取得了
  • MYSQL给选中结果添加赋予行号row number

    SELECT r r 1 rank a from SELECT from mytable WHERE 1 a SELECT r 0 b
  • IDEA通过git回滚到某个提交节点或某个版本

    1 项目右键后 点击 Git Show History 这里会显示有历史提交的版本记录 这里我们假设要回滚到 提交 版本中 2 选中 提交 右键Copy Revision Number 3 回到项目 右键 Git Repository Re
  • [carla入门教程]-6 小项目:基于carla-ros-bridge构建一个小型比赛赛道

    本专栏教程将记录从安装carla到调用carla的pythonAPI进行车辆操控并采集数据的全流程 带领大家从安装carla开始 到最终能够熟练使用carla仿真环境进行传感器数据采集和车辆控制 第六节 基于carla ros bridge
  • QCC300x笔记(5) -- 外部Flash的读写操作

    哈喽大家好 这是该系列博文的第五篇 篇 lt lt 系列博文索引 快速通道 gt 1 QCC300X 外部Flash的读写 QCC300x是使用外部Flash片子 使用外部flash的好处就是成本下来了 大家都知道 CSR的片子一直是很贵的
  • extundelete工具恢复rm -rf 删除的目录(ext4、ext3)

    extundelete工具恢复rm rf 删除的目录 ext4 ext3grep工具只能用于恢复ext3文件系统下删除的文件 对于ext4文件系统 可以使用extundelete工具 使用的方法类似ext3grep ext3grep 仅对
  • AttributeError: ‘_SingleProcessDataLoaderIter‘ object has no attribute ‘next‘

    由于pytorch版本不同 函数用法不同 改为 即可解决
  • 抽象类和接口的区别,以及使用场景?

    抽象类 接口 抽象类和接口区别 Java 8中关于接口的改进 接口中的默认方法 抽象类和接口使用场景 抽象类是对一种事物的抽象 即对类抽象 而接口是对行为的抽象 抽象类是对整个类整体进行抽象 包括属性 行为 但是接口却是对类局部 行为 进行
  • java: 找不到符号 符号:类xxx位置: 程序包com.xxx.xxx.xxx.xxx

    1 问题 项目里有这个包但编译时报找不到这个包的错误 2 解决办法 在报错的项目里打开命令行窗口 在命令行窗口里输入mvn clean 等重新加载完然后重新编译项目即可
  • mint-ui引用iconfont图标

    mint ui引用iconfont图标 mint ui作为一种基于 Vue js 的移动端组件库 在移动端前端开发中备受欢迎 其特性就不多说了 想了解的博友可上mint ui官网自行了解 但是 mint ui提供的字体图标 通过查看mint
  • 深度学习实战1-(keras框架)企业数据分析与预测

    大家好 我是微学AI 今天给大家带来深度学习框架keras的实战项目 用于基本的企业数据分析 预测企业净利润情况 并利用灰色预测函数GM11进行预测模型 我们拿到企业数据 这里参数抽象成x1 x9 y表示净利润 数据如下 下面我们开始编写代
  • 云服务 pytorch 使用错误总结

    云服务 pytorch 使用错误总结 数据加载 Dataloader 使用Dataloader加载文件 设置num workers 1 batch size gt 1或者num workers gt 1时 会报错总线错误bus error
  • popen 使用方法

    popen 可以执行shell命令 并读取此命令的返回值 popen 函数通过创建一个管道 调用fork 产生一个子进程 执行一个shell以运行命令来开启一个进程 可以通过这个管道执行标准输入输出操作 这个管道必须由pclose 函数关闭
  • 那些30几岁的程序员都去哪了

    三十而立 简单四个字 鞭策着多少年轻人 不成想 三十已过 变成了三十而已 程序员对三十这个词比较敏感 之前不少文章也都提及过 有天 忽然冒出来一个问题 90后慢慢变成了中坚力量 曾经的80后程序员一代在公司里慢慢变少了 这些人去哪了呢 下面
  • 2023逆向分析代码渗透测试flag0071解析(超详细)

    PS 这里没有找到题目所以我直接直接做到最后一步把flag即可 1 将flag0071使用IDA打开 使用shift f12可以看到wrong和right的字符串 2 双击到data段按x交叉引用即可到达main主函数 3 程序逻辑很清晰
  • 疯壳Android嵌入式Linux平板开发教程4-3LCD驱动实验

    详情地址 https fengke club GeekMart views offline android 购买链接 https fengke club GeekMart su fHnaDyD1o jsp 视频地址 https fengke
  • win10下的wsl真是太好用了

    生命在于折腾 前段时间使用的是linuxmint 这个系统很好 但无奈抵挡不住win10的诱惑 其实主要的原因是玩游戏 搞了几天wine没搞好 重新加入win10的怀抱 在msdn上下载了原版光盘镜像 又经过了漫长的更新 终于进入了win1
  • tnsping遇到TNS-12546: TNS: 权限被拒绝

    从客户端tnsping 一台数据库 报错 TNS 12537 TNS 连接关闭 奇怪 服务器端可以tnsping通 也可以正常访问数据库 listener状态也正常 为什么客户端连接不上 查了一下原因 为sqlnet ora文件做了Vali
  • <Linux开发>驱动开发 -之-基于pinctrl/gpio子系统的LED驱动

    Linux开发 驱动开发 之 基于pinctrl gpio子系统的LED驱动 交叉编译环境搭建 Linux开发 linux开发工具 之 交叉编译环境搭建 uboot移植可参考以下 Linux开发 之 系统移植 uboot移植过程详细记录 第
  • [633]pyppeteer驱动浏览器

    当使用selenium去某宝或其他网站进行爬虫或者模拟登陆时 会出现滑动验证码 并且无论是用ActionChains滑还是手动滑 都会很委婉的告诉你 哎呀网络错误 请刷新 等等 why 爬虫都会碰到某些网站刚刚打开页面就被判定为 非人类行为