0


python版puppeteer——pyppeteer&selenium的加强版——seleniumwire

目录

前言

书接上文,selenium添加代理:

rom selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.proxy import Proxy, ProxyType
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By

# 代理供应商
proxy_host ='your_host'
proxy_port ='your_port'
proxy_username ='your_username'
proxy_password ='your_password'# 创建代理对象
proxy = Proxy()
proxy.proxy_type = ProxyType.MANUAL
proxy.http_proxy = f'http://{proxy_username}:{proxy_password}@{proxy_host}:{proxy_port}'
proxy.ssl_proxy = f'http://{proxy_username}:{proxy_password}@{proxy_host}:{proxy_port}'# 设置Chrome浏览器驱动程序使用代理
options = webdriver.ChromeOptions()
options.add_argument('--proxy-server=%s' % proxy.http_proxy)
options.add_argument('--disable-notifications')
options.add_argument('--disable-popup-blocking')
options.add_argument('--disable-infobars')
options.add_argument('--mute-audio')
driver = webdriver.Chrome(options=options)

对于无校验的代理,也就是代理形式为:

{proxy_host}:{proxy_port}

这样加没问题,但

对于需要校验用户名,密码的代理,也就是代理形式为:

proxy.http_proxy =f'http://{proxy_username}:{proxy_password}@{proxy_host}:{proxy_port}'
proxy.ssl_proxy =f'http://{proxy_username}:{proxy_password}@{proxy_host}:{proxy_port}'

访问页面就会出现"ERR_NO_SUPPORTED_PROXIES"

解决方法:

  1. 代理提供商通常会提供白名单校验:将你的主机ip加入白名单就可以替换username,password校验了。
  2. 使用selenium的扩展库:selenium-wire

seleniumwire

SeleniumWire 是一个 Python 库,它是在 Selenium WebDriver 的基础上扩展而来的。它提供了对浏览器的网络请求和响应进行拦截、修改和监控的功能,使得你可以更灵活地控制浏览器与服务器之间的通信过程。

以下是 SeleniumWire 提供的一些主要功能和特点:

  1. 请求和响应拦截:SeleniumWire 允许你拦截浏览器发送的请求和接收的响应,从而可以在请求发送前、发送后、响应接收前、接收后等时机对请求和响应进行修改、记录或拦截。
  2. 修改请求和响应:你可以修改请求头、请求体、查询参数、响应头、响应体等内容,以便在自动化测试过程中模拟不同的场景和测试条件。
  3. 请求过滤:SeleniumWire 支持根据 URL、请求方法、请求头等条件对请求进行过滤,使得你可以只关注感兴趣的请求,忽略其他请求。
  4. 请求记录和导出:SeleniumWire 可以记录浏览器发送和接收的所有网络请求,并且支持将请求记录导出为 HAR 文件,方便分析和调试。
  5. 网络性能分析:通过拦截和记录网络请求,你可以对页面加载时间、资源加载情况等进行性能分析和优化。
  6. 无需修改浏览器配置:SeleniumWire 是在 Selenium WebDriver 的基础上扩展的,因此无需额外的浏览器配置或插件即可使用。

以下是一个简单的示例代码,演示了如何使用 SeleniumWire 进行网络请求的拦截和修改:

from seleniumwire import webdriver

# 创建 Chrome WebDriver,并将日志级别设置为 INFO,用于查看网络请求日志
driver = webdriver.Chrome(seleniumwire_options={'log_level':0})# 访问目标网页
driver.get('https://www.example.com')# 获取所有的网络请求for request in driver.requests:if request.response:print(request.url, request.response.status_code)# 关闭 WebDriver
driver.quit()

在上述示例代码中,创建了一个 Chrome WebDriver,并使用

seleniumwire_options

参数将日志级别设置为 0(INFO),以便在控制台查看网络请求日志。然后,我们访问了一个网页,并获取了所有的网络请求,打印了请求的 URL 和响应的状态码。

总体而言,SeleniumWire 提供了强大的网络请求拦截和修改功能,可以更灵活地控制和分析浏览器与服务器之间的通信过程。它在自动化测试、网络性能分析和数据采集等场景中都有很多实用价值。

安装

pip install selenium-wire

创建web driver

确保你从seleniumwire导入webdriver库:

from seleniumwire import webdriver

然后,只需像直接使用Selenium一样实例化WebDriver。你可以传递任何所需的功能或浏览器特定选项,比如可执行路径、无头模式等。Selenium Wire也有自己的选项,可以通过seleniumwire_options属性传递进去。

# Create the driver with no options (use defaults)
driver = webdriver.Chrome()# Or create using browser specific options and/or seleniumwire_options options
driver = webdriver.Chrome(
    options = webdriver.ChromeOptions(...),
    seleniumwire_options={...})

设置代理

options ={'proxy':{'http':'http://username:password@host:port','https':'https://username:password@host:port',}}
browser = webdriver.Chrome(path_to_driver, seleniumwire_options=options)

而且最最最最最最重要的是,它支持热加载代理,如下,内部实现了proxy的setter和getter:

@propertydefproxy(self)-> Dict[str, Any]:...return conf

@proxy.setterdefproxy(self, proxy_conf: Dict[str, Any]):...

牛刀小试:

from seleniumwire import webdriver
proxy = next_proxy()
options ={'proxy':{'http': proxy["http"],'https': proxy["https"],}}

browser = webdriver.Chrome(seleniumwire_options=options)
browser.get("https://myip.ipip.net/")print(browser.proxy)print(browser.page_source)

proxy = next_proxy()
browser.proxy ={"http": proxy["http"],"https": proxy["https"]}
browser.get("https://myip.ipip.net/")print(browser.proxy)print(browser.page_source)--------------------------------------------------------------------
当前 IP:xxxxxxxx  来自于:中国 安徽
当前 IP:xxxxxxxx  来自于:中国 陕西

反屏蔽

我们使用

https://bot.sannysoft.com/

来查看请求是否完全被判定为用户浏览器:
在这里插入图片描述
先不加任何参数直接访,100%会被检测出来web driver

from seleniumwire import webdriver
browser = webdriver.Chrome()
browser.get("https://bot.sannysoft.com/")# 此处用于阻塞解释器input(">>>")

在这里插入图片描述
除了我关于selenium的另一篇博客:https://blog.csdn.net/General_zy/article/details/128712331 介绍的反屏蔽方法,此处再介绍一些方法:
(或者也可以使用另一个库:pip install undetected-chromedriver)

修改window.navigator.webdriver关键字返回结果

options = webdriver.ChromeOptions()# 此步骤很重要,设置为开发者模式,防止被各大网站识别出来使用了Selenium
driver = webdriver.Chrome(options=options)
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument",{"source":"""
    Object.defineProperty(navigator, 'webdriver', {
      get: () => undefined
    })
    """})

options追加参数

add_experimental_option

add_argument

都是用于向 ChromeOptions 添加参数的方法,但它们在使用上有一些区别:

  1. add_experimental_option:- 用途:用于向 ChromeOptions 添加一些实验性的选项或特性。- 适用对象:通常用于添加一些不常用的或特定于浏览器版本的选项。- 示例:在 Selenium 中,使用 add_experimental_option 可以添加一些实验性的 Chrome 参数,比如启用/禁用某些功能、设置浏览器性能优化选项等。
  2. add_argument:- 用途:用于向 ChromeOptions 添加普通的命令行选项或配置参数。- 适用对象:通常用于添加一些常规的浏览器配置参数,比如设置 User-Agent、启用/禁用 JavaScript、设置代理服务器等。- 示例:在 Selenium 中,使用 add_argument 可以添加一些普通的 Chrome 命令行选项,比如设置 User-Agent,可以使用 options.add_argument("--user-agent=Your_User_Agent")

总的来说,

add_experimental_option

更多用于添加一些不常用或实验性的选项,而

add_argument

则更常用于添加普通的浏览器配置参数。在实际使用中,可以根据具体需求选择使用哪种方法。

通过

options = webdriver.ChromeOptions()

来添加参数的方式主要是在 Selenium 中模拟浏览器操作,以尽量避免被网站屏蔽。以下是一些常用参数和选项的介绍:

  1. User-Agent:通过 options.add_argument("--user-agent=Your_User_Agent") 可以设置自定义的 User-Agent 字段,以伪装成不同的浏览器或设备。
  2. 代理:通过 options.add_argument("--proxy-server=your_proxy_ip:your_proxy_port") 可以设置代理服务器,通过不同的代理 IP 来访问网站,避免频繁使用相同的 IP 地址。
  3. 禁用图片加载:通过 options.add_argument("--blink-settings=imagesEnabled=false") 可以禁用图片加载,减少页面请求,提高访问速度。
  4. 禁用 JavaScript:通过 options.add_argument("--disable-javascript") 可以禁用 JavaScript 的执行,有些网站的屏蔽机制可能依赖于 JavaScript 的操作。
  5. 无头模式:通过 options.add_argument("--headless") 可以启用 Chrome 的无头模式,即在后台运行 Chrome,无界面显示,模拟真实浏览器行为。
  6. 禁用 GPU 加速:通过 options.add_argument("--disable-gpu") 可以禁用 GPU 加速,有些网站可能会检测 GPU 信息,通过禁用 GPU 可以降低被检测的概率。
  7. 禁用扩展插件:通过 options.add_argument("--disable-extensions") 可以禁用 Chrome 的扩展插件,减少特定插件对网站访问的影响。
  8. 禁用自动化提示:通过 options.add_experimental_option("excludeSwitches", ["enable-automation"]) 可以禁用自动化提示,模拟真实用户行为。
  9. options.add_argument(‘–ignore-certificate-errors’),options.add_argument(‘–ignore-ssl-errors’)忽略 SSL 证书错误和 SSL 错误,用于处理在使用自签名证书或过期证书的网站时避免弹出警告。
  10. options.add_argument(‘–disable-logging’),options.add_argument(‘–log-level=3’) 禁用日志记录,以减少日志文件的输出。
options = webdriver.ChromeOptions()
    options.add_experimental_option('excludeSwitches',['enable-automation'])
    options.add_experimental_option('useAutomationExtension',False)
    options.add_argument("--disable-blink-features=AutomationControlled")
    options.add_argument("--disable-gpu")
    browser = webdriver.Chrome(options=options)withopen('stealth.min.js')as f:
        js = f.read()
    browser.execute_cdp_cmd('Page.addScriptToEvaluateOnNewDocument',{'source': js
    })

    browser.get("https://bot.sannysoft.com/")# 此处用于阻塞解释器input(">>>")

在这里插入图片描述

pyppeteer

是 Puppeteer 的 Python 版本的实现,但他不是 Google 开发的,是一位来自于日本的工程师依据 Puppeteer 的一些功能开发出来的非官方版本。

在 Pyppetter 中,实际上它背后也是有一个类似 Chrome 浏览器的 Chromium 浏览器在执行一些动作进行网页渲染。

Chromium 是谷歌为了研发 Chrome 而启动的项目,是完全开源的。二者基于相同的源代码构建,Chrome 所有的新功能都会先在 Chromium 上实现,待验证稳定后才会移植,因此 Chromium 的版本更新频率更高,也会包含很多新的功能,但作为一款独立的浏览器,Chromium 的用户群体要小众得多。两款浏览器“同根同源”,它们有着同样的 Logo,但配色不同,Chrome 由蓝红绿黄四种颜色组成,而 Chromium 由不同深度的蓝色构成。

在这里插入图片描述

puppeteer

Puppeteer是一个基于Node.js的库,它提供了一个高级API,可以通过DevTools协议控制Chrome/Chromium浏览器。Puppeteer默认以无界面模式运行,但可以配置为在完整(“headful”)Chrome/Chromium浏览器中运行。

中文文档:https://puppeteer.bootcss.com/

安装

pip install pyppeteer

官方github库提示:

注意:此存储库未维护,并且已经很长时间没有进行任何重大更改。请考虑使用 playwright-python 作为替代方案。

如果您希望对此代码进行全面更新,请与我联系。

pyppeteer的语法和puppeteer相同,可以参考puppeteer文档。

快速入门

pyppeteer是基于asyncio的,所以需要引入async,await关键字:

import asyncio
from pyppeteer import launch

asyncdefmain():
    browser =await launch()
    page =await browser.newPage()await page.goto('https://example.com')await page.screenshot({'path':'example.png'})await browser.close()# python3.10后run函数成为一个稳定的版本# 推荐使用run函数
asyncio.run(main())

更多demo:https://www.jianshu.com/p/f1a8fb7037d7

在页面上执行Js:

import asyncio
from pyppeteer import launch

asyncdefmain():
    browser =await launch()
    page =await browser.newPage()await page.goto('https://example.com')await page.screenshot({'path':'example.png'})

    dimensions =await page.evaluate('''() => {
        return {
            width: document.documentElement.clientWidth,
            height: document.documentElement.clientHeight,
            deviceScaleFactor: window.devicePixelRatio,
        }
    }''')print(dimensions)# >>> {'width': 800, 'height': 600, 'deviceScaleFactor': 1}await browser.close()

asyncio.run(main())

参数配置

属性参数描述executablePathstrchrome.exe运行的路径ignorehttpserrrorsbool忽略https错误,默认falseheadlessboolTrue 开始无头浏览器 False关闭无头dumpiobool设置True 解决浏览器多开卡死 (没有测试过)下面是args的参数设置下面是args的参数设置下面是args的参数设置–disable-infobars-关闭自动化提示框–window-size=1920,1080str设置浏览器大小吗,1920是宽,1080是宽–log-level=30str日志保存等级, 建议设置越好越好,要不然生成的日志占用的空间会很大 30为warning级别–start-maximized-窗口最大化模式–proxy-server=http://localhost:1080str设置代理userDataDir=D:\userData\str用户文件保存地址
其他参数:

  • ignoreHTTPSErrors (bool): 是否要忽略 HTTPS 的错误,默认是 False。
  • headless (bool): 是否启用 Headless 模式,即无界面模式,如果 devtools 这个参数是 True 的话,那么该参数就会被设置为 False,否则为 True,即默认是开启无界面模式的。
  • executablePath (str): 可执行文件的路径,如果指定之后就不需要使用默认的 Chromium 了,可以指定为已有的 Chrome 或 Chromium。
  • slowMo (int|float): 通过传入指定的时间,可以减缓 Pyppeteer 的一些模拟操作。
  • args (List[str]): 在执行过程中可以传入的额外参数。
  • ignoreDefaultArgs (bool): 不使用 Pyppeteer 的默认参数,如果使用了这个参数,那么最好通过 args 参数来设定一些参数,否则可能会出现一些意想不到的问题。这个参数相对比较危险,慎用。
  • handleSIGINT (bool): 是否响应 SIGINT 信号,也就是可以使用 Ctrl + C 来终止浏览器程序,默认是 True。
  • handleSIGTERM (bool): 是否响应 SIGTERM 信号,一般是 kill 命令,默认是 True。
  • handleSIGHUP (bool): 是否响应 SIGHUP 信号,即挂起信号,比如终端退出操作,默认是 True。
  • dumpio (bool): 是否将 Pyppeteer 的输出内容传给 process.stdout 和 process.stderr 对象,默认是 False。
  • userDataDir (str): 即用户数据文件夹,即可以保留一些个性化配置和操作记录。
  • env (dict): 环境变量,可以通过字典形式传入。
  • devtools (bool): 是否为每一个页面自动开启调试工具,默认是 False。如果这个参数设置为 True,那么 headless 参数就会无效,会被强制设置为 False。
  • logLevel (int|str): 日志级别,默认和 root logger 对象的级别相同。
  • autoClose (bool): 当一些命令执行完之后,是否自动关闭浏览器,默认是 True。
  • loop (asyncio.AbstractEventLoop): 时间循环对象。
asyncdefmain():
    proxy = next_proxy()# 创建浏览器启动选项
    browser_options ={'args':[# f'--proxy-server={proxy.get("https")}',  # 设置代理,替换为你的代理IP和端口'--no-sandbox',# 非沙盒模式,'--disable-infobars',# 关闭自动化提示框'--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36',],'headless':True# 无头模式,不显示浏览器窗口}# 启动浏览器并创建页面
    browser =await launch(options=browser_options)
    page =await browser.newPage()
    resp =await page.goto('https://myip.ipip.net/')print(await resp.text())await browser.close()if __name__ =='__main__':# test()# test_with_proxy()
    asyncio.run(main())

注意,pyppeteer也只支持无认证的代理。

隐藏浏览器特征

pyppeteer跟selenium一样会有浏览器特征,所以需要修改,隐藏特征防止被识别。

主要有下面两点:

  1. 去除浏览器自动化参数 --enable-automation
  2. 去除window.navigator.webdriver等检测
from pyppeteer import launcher
# 第一步 去除浏览器自动化参数# 必须在 from pyppeteer import launch 前去除参数# 去除自动化 启动参数
launcher.AUTOMATION_ARGS.remove("--enable-automation")# 第二步,修改 navigator.webdriver检测# 其实各种网站的检测js是不一样的,这是比较通用的。有的网站会检测运行的电脑运行系统,cpu核心数量,鼠标运行轨迹等等。# 反爬js
js_text ="""
    () =>{ 
    Object.defineProperties(navigator,{ webdriver:{ get: () => false } });
    window.navigator.chrome = { runtime: {},  };
    Object.defineProperty(navigator, 'languages', { get: () => ['en-US', 'en'] });
    Object.defineProperty(navigator, 'plugins', { get: () => [1, 2, 3, 4, 5,6], });
    }
"""await page.evaluateOnNewDocument(js_text)# 本页刷新后值不变,自动执行js

拦截请求

from pyppeteer import launcher

launcher.AUTOMATION_ARGS.remove("--enable-automation")from pyppeteer import launch

from pyppeteer.network_manager import Request, Response

asyncdefintercept_request(req:Request):await req.continue_()# 请求,看源码可以重新编写请求asyncdefintercept_response(res:Response):if'ext2020/apub/json/prevent.new'in res.url:print('拦截到请求')
        json_text =await res.text()
        title_li = jsonpath(json.loads(json_text),'$..title')for title in title_li:print(title)passasyncdefmain():# 浏览器 启动参数
    start_parm ={# 启动chrome的路径"executablePath":r"C:\Users\yq\AppData\Local\pyppeteer\pyppeteer\local-chromium\722234\chrome-win\chrome.exe",# 关闭无头浏览器 默认是无头启动的"headless":False,"args":['--disable-infobars',# 关闭自动化提示框# '--no-sandbox',  # 关闭沙盒模式'--start-maximized',# 窗口最大化模式'--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36',# UA],}# 创建浏览器对象,可以传入 字典形式参数
    browser =await launch(**start_parm)# 创建一个页面对象, 页面操作在该对象上执行
    page =await browser.newPage()await page.setJavaScriptEnabled(enabled=True)# 启用拦截器await page.setRequestInterception(True)
    page.on('request', intercept_request) 
    page.on('response', intercept_response)
    
    js_text ="""
    () =>{ 
        Object.defineProperties(navigator,{ webdriver:{ get: () => false } });
        window.navigator.chrome = { runtime: {},  };
        Object.defineProperty(navigator, 'languages', { get: () => ['en-US', 'en'] });
        Object.defineProperty(navigator, 'plugins', { get: () => [1, 2, 3, 4, 5,6], });
     }
        """await page.evaluateOnNewDocument(js_text)# 本页刷新后值不变,自动执行jsawait page.goto('https://news.qq.com/')# 页面跳转await browser.close()

asyncio.run()# 创建异步池并执行main函数。

更多文档&博客

  1. https://blog.csdn.net/qq_27900321/article/details/129402456
  2. https://github.com/pyppeteer/pyppeteer

Playwright

迁移到 Playwright的原因:

  1. Pyppeteer 是第三方的,好久没有更新了,bug 也不少
  2. Puppeteer 的原生 JS 版本本身就很不稳定,亲测 Playwright 更稳定一些
  3. Playwright 原生支持 Python,而且支持 Google Chrome/Firefox/Safari 三大浏览器

Playwright 是微软出品的浏览器自动化工具,代码质量应该是有足够保证的。而且它还官方支持同步版的 Python API, 同时支持三大浏览器。

安装

  1. pip install playwright
  2. 安装浏览器:python -m playwright install

文档地址:https://playwright.dev/python/docs/api/class-playwright

快速入门

在这里插入图片描述

同步接口:

from playwright.sync_api import sync_playwright

with sync_playwright()as p:# 打开三种浏览器并截屏for browser_type in[p.chromium, p.firefox, p.webkit]:
        browser = browser_type.launch()
        page = browser.new_page()
        page.goto('http://playwright.dev')
        page.screenshot(path=f'example-{browser_type.name}.png')
        browser.close()

异步接口:

import asyncio
from playwright.async_api import async_playwright

asyncdefmain():asyncwith async_playwright()as p:for browser_type in[p.chromium, p.firefox, p.webkit]:
            browser =await browser_type.launch()
            page =await browser.new_page()await page.goto('http://playwright.dev')await page.screenshot(path=f'example-{browser_type.name}.png')await browser.close()

asyncio.run(main())

新概念:Context

和 Puppeteer 不同的是,Playwright 新增了 context 的概念,每个 context 就像是一个独立的匿名模式会话,非常轻量,但是又完全隔离。比如说,可以在两个 context 中登录两个不同的账号,也可以在两个 context 中使用不同的代理。

通过 context 还可以设置 viewport, user_agent 等。

context = browser.new_context(
  user_agent='My user agent')
context = browser.new_context(
  viewport={'width':1280,'height':1024})
context = browser.new_context(
    http_credentials={"username":"bill","password":"pa55w0rd"})# new_context 其他几个比较有用的选项:
ignore_https_errors=False
proxy={"server":"http://example.com:3128","bypass":".example.com","username":"","password":""}
extra_http_headers={"X-Header":""}

context 中有一个很有用的函数context.add_init_script, 可以让我们设定在调用 context.new_page 的时候在页面中执行的脚本。

# hook 新建页面中的 Math.random 函数,总是返回 42
context.add_init_script(script="Math.random = () => 42;")# 或者写在一个文件里
context.add_init_script(path="preload.js")

还可以使用 context.expose_binding 和 context.expose_function 来把 Python 函数暴露到页面中,还是使用 add_init_script 暴露 JS 函数方便一些。

和 Puppeteer 一样,Playwright 的核心概念依然是 page, 核心 API 几乎都是 page 对象的方法。可以通过 context 来创建 page.

页面基本操作

按照官网文档,调用 page.goto(url) 后页面加载过程:

  1. 设定 url
  2. 通过网络加载解析页面
  3. 触发 page.on(“domcontentloaded”) 事件
  4. 执行页面的 js 脚本,加载静态资源
  5. 触发 page.on(“laod”) 事件
  6. 页面执行动态加载的脚本
  7. 当 500ms 都没有新的网络请求的时候,触发 networkidle 事件

page.goto(url) 会跳转到一个新的链接。默认情况下 Playwright 会等待到 load 状态。如果我们不关心加载的 CSS 图片等信息,可以改为等待到 domcontentloaded 状态,如果页面是 ajax 加载,那么我们需要等待到 networkidle 状态。如果 networkidle 也不合适的话,可以采用 page.wait_for_selector 等待某个元素出现。不过对于 click 等操作会自动等待。

page.goto(url, referer="", timeout=30, wait_until="domcontentloaded|load|networkidle")

Playwright 会自动等待元素处于可操作的稳定状态。当然也可以用 page.wait_for_* 函数来手工等待:

page.wait_for_event("event", event_predict, timeout)
page.wait_for_function(js_function)
page.wait_for_load_state(state="domcontentloaded|load|networkidle", timeout)
page.wait_for_selector(selector, timeout)
page.wait_for_timeout(timeout)# 不推荐使用

对页面的操作方法主要有:

# selector 指的是 CSS 等表达式
page.click(selector)
page.fill(selector, value)# 在 input 中填充值# 例子
page.click("#search")

获取页面中的数据的主要方法有:

page.url  # url
page.title()# title
page.content()# 获取页面全文
page.inner_text(selector)# element.inner_text()
page.inner_html(selector)
page.text_content(selector)
page.get_attribute(selector, attr)# eval_on_selector 用于获取 DOM 中的值
page.eval_on_selector(selector, js_expression)# 比如:
search_value = page.eval_on_selector("#search","el => el.value")# evaluate 用于获取页面中 JS 中的数据,比如说可以读取 window 中的值
result = page.evaluate("([x, y]) => Promise.resolve(x * y)",[7,8])print(result)# prints "56"

选择器表达式

在上面的代码中,使用了 CSS 表达式(比如#button)来选取元素。实际上,Playwright 还支持 XPath 和自己定义的两种简单表达式,并且是自动识别的。

# 通过文本选择元素,这是 Playwright 自定义的一种表达式
page.click("text=login")# 直接通过 id 选择
page.click("id=login")# 通过 CSS 选择元素
page.click("#search")# 除了常用的 CSS 表达式外,Playwright 还支持了几个新的伪类# :has 表示包含某个元素的元素
page.click("article:has(div.prome)")# :is 用来对自身做断言
page.click("button:is(:text('sign in'), :text('log in'))")# :text 表示包含某个文本的元素
page.click("button:text('Sign in')")# 包含
page.click("button:text-is('Sign is')")# 严格匹配
page.click("button:text-matches('\w+')")# 正则# 还可以根据方位匹配
page.click("button:right-of(#search)")# 右边
page.click("button:left-of(#search)")# 左边
page.click("button:above(#search)")# 上边
page.click("button:below(#search)")# 下边
page.click("button:near(#search)")# 50px 之内的元素# 通过 XPath 选择
page.click("//button[@id='search'])")# 所有 // 或者 .. 开头的表达式都会默认为 XPath 表达式

对于 CSS 表达式,还可以添加前缀css=来显式指定,比如说 css=.login 就相当于 .login.

除了上面介绍的四种表达式以外,Playwright 还支持使用 >> 组合表达式,也就是混合使用四种表达式。

page.click('css=nav >> text=Login')

复用 Cookies 等认证信息

在 Puppeteer 中,复用 Cookies 也是一个老大难问题了。这个是 Playwright 特别方便的一点,他可以直接导出 Cookies 和 LocalStorage, 然后在新的 Context 中使用。

# 保存状态import json
storage = context.storage_state()withopen("state.json","w")as f:
    f.write(json.dumps(storage))# 加载状态withopen("state.json")as f:
    storage_state = json.loads(f.read())
context = browser.new_context(storage_state=storage_state)

监听事件

通过 page.on(event, fn) 可以来注册对应事件的处理函数:

deflog_request(intercepted_request):print("a request was made:", intercepted_request.url)
page.on("request", log_request)# sometime later...
page.remove_listener("request", log_request)

其中比较重要的就是 request 和 response 两个事件

拦截更改网络请求

可以通过 page.on(“request”) 和 page.on(“response”) 来监听请求和响应事件。

from playwright.sync_api import sync_playwright as playwright

defrun(pw):
    browser = pw.webkit.launch()
    page = browser.new_page()# Subscribe to "request" and "response" events.
    page.on("request",lambda request:print(">>", request.method, request.url))
    page.on("response",lambda response:print("<<", response.status, response.url))
    page.goto("https://example.com")
    browser.close()with playwright()as pw:
    run(pw)

其中 request 和 response 的属性和方法,可以查阅文档:https://playwright.dev/python/docs/api/class-request

通过 context.route, 还可以伪造修改拦截请求等。比如说,拦截所有的图片请求以减少带宽占用:

context = browser.new_context()
page = context.new_page()# route 的参数默认是通配符,也可以传递编译好的正则表达式对象
context.route("**/*.{png,jpg,jpeg}",lambda route: route.abort())
context.route(re.compile(r"(\.png$)|(\.jpg$)"),lambda route: route.abort())
page.goto("https://example.com")
browser.close()

其中 route 对象的相关属性和方法,可以查阅文档:https://playwright.dev/python/docs/api/class-route

灵活设置代理

Playwright 还可以很方便地设置代理。Puppeteer 在打开浏览器之后就无法在更改代理了,对于爬虫类应用非常不友好,而 Playwright 可以通过 Context 设置代理,这样就非常轻量,不用为了切换代理而重启浏览器。

context = browser.new_context(
    proxy={"server":"http://example.com:3128","bypass":".example.com","username":"","password":""})

示例:

from playwright.sync_api import sync_playwright

if __name__ =='__main__':with sync_playwright()as p:
        browser = p.chromium.launch(proxy={"server":"per-context"})

        pxy = next_proxy()
        context1 = browser.new_context(
            proxy={"server": pxy["http"],"username":"","password":""})
        page1 = context1.new_page()
        page1.goto("https://myip.ipip.net/")print(page1.content())

        pxy2 = next_proxy()
        context2 = browser.new_context(
            proxy={"server": pxy2["http"],"username":"","password":""})
        page2 = context2.new_page()
        page2.goto("https://myip.ipip.net/")print(page2.content())

        browser.close()

在这里插入图片描述

杀手级功能:录制操作直接生成代码

Playwright 的命令行还内置了一个有趣的功能:可以通过录制你的点击操作,直接生成 Python 代码。

python -m playwright codegen http://example.com/

Playwright 还有很多命令行功能,比如生成截图等等,可以通过

python -m playwright -h

查看。


本文转载自: https://blog.csdn.net/General_zy/article/details/132070958
版权归原作者 Generalzy 所有, 如有侵权,请联系我们删除。

“python版puppeteer——pyppeteer&selenium的加强版——seleniumwire”的评论:

还没有评论