• Playwright实战案例之爬取js加密数据



    前言

    Playwright是一个强大的Python库,仅用一个API即可自动执行Chromium、Firefox、WebKit等主流浏览器自动化操作,并同时支持以无头模式、有头模式运行。 Playwright提供的自动化技术是绿色的、功能强大、可靠且快速,支持Linux、Mac以及Windows操作系统。


    一、Playwright的安装与使用

    1.安装

    • 要使用 Playwright,需要 Python 3.7 版本及以上,请确保 Python 的版本符合要求。

    安装 Playwright,命令如下:

    # 安装playwright库
    pip install playwright
    
    # 安装浏览器驱动文件(安装过程稍微有点慢)
    playwright install
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2.录制

    • 使用Playwright无需写一行代码,我们只需手动操作浏览器,它会录制我们的操作,然后自动生成代码脚本

    输入如下命令

    # 帮助命令
    playwright codegen --help
    # 尝试启动一个 Firefox 浏览器,然后将操作结果输出到 script.py 文件
    playwright codegen -o script.py -b firefox
    
    • 1
    • 2
    • 3
    • 4

    二、案例实现

    1.思路

    1. 通过 playwright 打开浏览器来获取JavaScript渲染后的数据,从而绕过解密 JavaScript 加密的数据,跟 Selenium 一样的,都是模拟人为打开浏览器来获取数据。

    2.引入库

    代码如下(示例):

    from playwright.sync_api import sync_playwright
    from lxml import etree
    import pymongo
    # pymongo有自带的连接池和自动重连机制,但是仍需要捕捉AutoReconnect异常并重新发起请求。
    from pymongo.errors import AutoReconnect
    from retry import retry
    # logging 用来输出信息
    import logging
    
    import time
    # 开始时间
    start = time.time()
    # 日志输出格式
    logging.basicConfig(level=logging.INFO,
                        format='%(asctime)s - %(levelname)s: %(message)s')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    3.驱动浏览器进行访问

    代码如下(示例):

    BTC_URL = 'https://www.oklink.com/zh-cn/btc/tx-list?limit=100&pageNum={pageNum}'
    
    def run(playwright):
        # 驱动浏览器,并开启无头模式
        browser = playwright.chromium.launch(headless=True)
        # 打开窗口
        page = browser.new_page()
        for Num in range(1, 3):
            # 触发 事件
            page.on('response', on_response)
            # 访问URL
            page.goto(BTC_URL.format(pageNum=Num))
            # 调用了 wait_for_load_state 方法等待页面某个状态完成,这里我们传入的 state 是 networkidle,也就是网络空闲状态
            page.wait_for_load_state('networkidle')
            # 生成器
            yield page.content()
            # html = page.content()
            # Get_the_data(page.content())
            # print(html)
        browser.close()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    4.触发事件

    • on_response 方法是用于判断某一些请求( /api/explorer/v1/btc/transactionsNoRestrict )返回的状态是否为 200,如果是 200 ,就可以获取该请求返回的数据,也就是加密后的数据

    代码如下(示例):

    def on_response(response):
        try:
            # 筛选请求,并判断状态
            if '/api/explorer/v1/btc/transactionsNoRestrict' in response.url and response.status == 200:
                # 返回json格式数据
                logging.info('get invalid status code %s while scraping %s',
                             response.status, response.url)
                # data_set = response.json().get('data').get('hits')
                # for item in data_set:
                #     Transaction_hashing = item.get('hash')
                #     The_block= item.get('blockHeight')
                #     print(Transaction_hashing)
                #     print(The_block)
                return response.json()
            if '/api/explorer/v1/btc/transactionsNoRestrict' in response.url and response.status != 200:
                # 如果不是200就在日志里打印出响应码和链接
                logging.error('get invalid status code %s while scraping %s',
                              response.status, response.url)
        except Exception as e:
            # exc_info为布尔值,如果该参数的值为True时,则会将异常信息添加到日志消息中;如果没有则会将None添加到日志信息中。
            logging.error('error occurred while scraping %s',
                          response.url, exc_info=True)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    5.获得数据

    • 在前面我们已经通过 run()方法来获取到网页源码了,而我们想的数据也已经在网页源码,那就直接用 xpath 来获取数据吧

    代码如下(示例):

    def Get_the_data(html):
    	# 格式化源码
        selector = etree.HTML(html)
        data_set = selector.xpath(
            '//*[@id="root"]/main/div/div[3]/div/div[2]/section/div/div/div/div/table/tbody/tr')[1:]
        for data in data_set:
            Transaction_hashing = data.xpath('td[1]/div/a/text()')[0]
            The_block = data.xpath('td[2]/a/text()')[0]
            Trading_hours = data.xpath('td[3]/div/span/text()')[0]
            The_input = data.xpath('td[4]/span/text()')[0]
            The_output = data.xpath('td[5]/span/text()')[0]
            quantity = data.xpath('td[6]/span/span/text()')[0]
            premium = data.xpath('td[7]/span/span/text()')[0]
            BTC_data = {
                '交易哈希': Transaction_hashing,
                '所在区块': The_block,
                '交易时间': Trading_hours,
                '输入': The_input,
                '输出': The_output,
                '数量(BTC)': quantity,
                '手续费(BTC)': premium
            }
            yield BTC_data
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    6.保存数据到Mongodb

    代码如下(示例):

    @retry(AutoReconnect, tries=4, delay=1)
    def save_data(data):
        """
        将数据保存到 mongodb
        使用 update_one() 方法第一个参数为查询的条件,第二个参数为要修改的字段。
        upsert:
        是一种特殊的更新,如果没有找到符合条件的更新条件的文档,就会以这个条件和更新文档为基础创建一个新的文档;如果找到了匹配的文档,就正常更新,upsert非常方便,不必预置集合,同一套代码既能用于创建文档又可以更新文档
        """
        # 存在则更新,不存在则新建,
        collection.update_one({
            # 保证 数据 是唯一的
            '交易哈希': data.get('交易哈希')
        }, {
            '$set': data
        }, upsert=True)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在这里插入图片描述

    7.调用方法

    代码如下(示例):

    with sync_playwright() as playwright:
    
        for html in run(playwright):
            for data in Get_the_data(html):
                logging.info('get detail data %s', data)
                logging.info('saving data to mongodb')
                save_data(data)
                logging.info('data saved successfully')
    # 结束时间
    end = time.time()
    print('Cost time: ', end - start)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    8.运行代码

    在这里插入图片描述


    总结

    playwright相比已有的自动化测试工具有很多优势,比如:

    • 跨浏览器,支持Chromium、Firefox、WebKit
    • 跨操作系统,支持Linux、Mac、Windows
    • 可提供录制生成代码功能,解放双手

    目前移动端存在的缺点就是生态和文档还不是非常完备。

  • 相关阅读:
    othofinder跑出来结果缺少single_copy_othologue_sequences.
    AJAX之实现省市联动
    Debian 决定允许无记名投票,候选人Felix Lechner质疑
    深入剖析 Java 类属性与类方法的应用
    看源码逐行学习ChatGLM2-6B大模型,项目中的modeling_chatglm.py文件
    阿里云服务器购买
    恒源云-Pycharm远程训练避坑指南
    基于Java的行李寄存系统设计和实现(源码+lw+部署文档+讲解等)
    rust持续学习 raw pointer 1
    【python】Sklearn—Cluster
  • 原文地址:https://blog.csdn.net/weixin_45688123/article/details/126016710