V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
heartlocker
V2EX  ›  Python

Clicknium 中文指南 2

  •  
  •   heartlocker · 2023-03-03 15:44:10 +08:00 · 1274 次点击
    这是一个创建于 422 天前的主题,其中的信息可能已经有所发展或是发生改变。

    Clicknium是一个可以用来控制桌面应用和浏览器的 Python 库。 在Clicknium 使用指南 1 中介绍了 Clicknium 的基本概念和使用方法。本章将更深入的介绍 Clicknium 的高级功能。

    1. 获取相似元素(Similar elements)

    我们经常需要处理网页或应用中大量相似的元素,例如 List 和 Grid 中的 UI 元素。 依次抓取这些元素会产生大量的 locator ,显然不是一个好方法。 有用户甚至提问,将同一类 locator 放在了一个文件夹下,怎么能遍历 locator 文件夹。 当然,采用之前提到了参数化 locator 也是一种做法。但是,一方面你需要分析是用哪个属性和什么值来遍历 UI 元素,另一方面,参数的范围很可能不得而知,尤其随着应用越来越复杂,越来越多采用动态加载的方式导致要抓取的 UI 元素总量无法预测。 通常我们会使用 BeautifulSoup 这类的库来解析网站的 HTML 结构,由于网站的样式越来越复杂,抓取的内容并不会总是在同一个结构中, 每个 Item 可能被多层 div 或者其他元素包裹,所以在解析时,我们需要分析 HTML 的结构并构建一个算法找所有元素的最小公共节点,并且遍历该结构。 这一过程确实比较花时间, 同时也是一个能被算法解决的问题。

    Clicknium Recorder 中,包含了抓取相似元素的功能。 用户通过抓取两个相似(同一层级)的元素,Clicknium 内置算法自动解析 HTML 结构,并计算最小公共节点和层级信息 ,以实现抓取相似元素。 如果计算出来的元素并不是用户想要的,可进行第三次抓取,算法将通过三个 UI 元素的信息,重新计算抓取路径。

    1.1 使用方法:

    以 Opensea 中Okay Bear图片为例,这是一个典型的 Grid 结构:

    a. 点击 VS Code 插件中的 Capture 按钮,启动录制器:

    b. 点击录制器中的 Similar elements:

    c. Ctrl +鼠标单击抓取第一和第二个元素:

    抓取到相似元素对应的 locator 后, 调用find_elements返回一个 UI element List (find_element返回单个 UI element 。

    Sample code:

    使用get_property获取图片地址后,通过 request 下载图片,并通过send_hotkey触发 PgDn 下滑加载图片。

    import requests
    from time import sleep
    from clicknium import clicknium as cc, locator
    def main():
        cc.chrome.open("https://opensea.io/collection/okay-bears")
        nftDic = {}
    
        while True:
            newDic = {}
            finish = True
            sleep(4)
            nfts = cc.find_elements(locator.sample.opensea.img_okay_bear)
            for nft in nfts:
                src = nft.get_property("src")
                name = nft.get_property("alt")
                if name not in nftDic:
                    newDic[name]=src
                    finish = False
    
            for key,value in newDic.items():
                r = requests.get(value)
                print("Downloading:"+ key)
                imagePath = ".\image\" + key + ".jpg"
                with open(imagePath,'wb') as f:
                    f.write(r.content)
    
            nftDic = nftDic | newDic
            if finish:
                break
            else:
                print("next page")
                cc.send_hotkey("{PGDN}")
    
    if __name__ == "__main__":
        main()
    

    2. 获取结构化数据

    在自动化场景中, 获取结构化数据,尤其是表格数据也有很大的需求。获取相似元素只适合抓取一列数据。当然可以一列一列抓取一个表格,当这种方式会存在不同列之间的对齐问题,存在出错的可能同时操作也非常麻烦。

    结构化数据有两个常见的场景:

    • 表格
    • 非表格类结构化数据

    表格比较好理解, 什么是非表格类结构化数据呢?如上面提到了 OpenSea 的页面中, 如果同时需要抓取 NFT 图片对应的价格,编号,从而构成一个表格就可以认为非表格类结构化数据。相比获取相似元素,结构化数据增加了不同列之前的匹配算法和一系列方便表格操作的功能。

    2.1 抓取表格数据:

    1. 在 VS Code 中启动录制器
    2. 在录制器中选择 data scraper

    Coingecko举例,当需要抓取下面的表格

    1. 使用 Ctrl+鼠标左键单击表格第一行第一列数据

    Clicknium 会自动探测抓取对象为表格,并提示是否抓取全表信息:

    点击 Yes ,即可看到数据预览。在预览页面,支持修改列名,改变列的顺序, 删除列等操作。也可以选择 No ,然后一列一列选择需要的数据。

    2.2 抓取非表格类结构化数据:

    以最常见的京东作为例:京东手机页面

    在这个例子中, 我们需要抓取商品名,价格和图片。操作的方式与获取相似元素类似, 两个元素决定一列:

    a. 抓取第一列,第一个元素:第一个商品名。

    b. 抓取第一列,第二个元素:第二个商品名。

    c. 第一列抓取成功,点击添加列,开始抓取第二列元素。

    d. 抓取第二列,第一个元素: 第一个商品价格。

    。。。。。。

    需要注意的是不同列抓取的元素的相对位置需要是一致的,即都是前两个元素。不能出现第一列抓取第一第二行,第二列抓取第三第四行,这样会导致匹配出现问题。

    抓取结束后,Clicknium 会将数据整理为表格:

    在预览页面同样可以修改列名,列顺序和选择不同的属性作为列的值:

    Sample Code:

    对于结构化数据,Clicknium 提供了scrape_data方法,返回 Json 格式的文本数据, 不仅如此该函数支持传入翻页按钮的 locator 实现自动翻页,翻页支持设置控件和模拟鼠标等方式,等待页面加载,抓取数据条数控制和超时。

    from clicknium import clicknium as cc, locator
    import pandas as pd
    
    row = cc.scrape_data(locator.jd.phone)
    df = pd.json_normalize(row)
    print(df.head(10))
    

    3. 自动化技术

    在默认情况下,Clicknium 会自动选择合适的自动化技术。 但在自动化桌面端应用时, 有时候还是需要我们来选择不同的自动化技术, 同时不同自动化技术也以为可能会产生不同的 locator attributes 。

    Clicknium 包含的自动化技术:

    需要注意的是, 不同自动化技术录制的 Locator 有着不同的 Locator attributes 和 Element properties 。对于 Element properties ,可以查上面对应技术的文档中,通过 get_property 方法获得 property 的值。

    下面的表格对 Clicknium 支持的自动化技术做了概括和总结

    自动化技术 场景 简介
    浏览器自动化 Chrome/Edge/IE/Firfox 等浏览器。 Chrome DevTools Protocol/ 利用 Clicknium 浏览器插件,采用注入 JavaScript 脚本对 Web 元素进行控制。
    UIA Windows 桌面应用 基于 Microsoft UI Automation,相比 IA 有更丰富的方法和属性信息, 针对 WPF 特别优化。
    IA Windows 桌面应用 基于 Microsoft Active Accessibility(MSAA), 利用 COM 接口将界面的部分属性和 API 暴露出来。对于开发年代比较早的软件支持较好。
    图像识别 其他自动化识别不准确时采用 基于 Open CV ,也是导致 Clicknium Python SDK 比较大的原因
    JAVA 自动化 自动化 JAVA 应用 以 Java Access Bridge 为基础,并对 AWT 组件等进行加强,需要依赖 Clicknium Java 插件。
    SAP 自动化 SAP WinGUI API 基于 SAP GUI Scripting 。

    在录制器中,可以修改默认选项,选择自己需要的自动化技术:

    4. 打包 Clicknium 项目为可执行文件

    自动化脚本的用户,不一定就是 Python 程序员本人。 当自动化脚本需要交给不同用户时,会需要各种各样的问题。 有可能对方没有 Python 环境,缺乏某个 Python 库,或者存在版本冲突,甚至对方是业务人员不是程序员。 将脚本打包成人人可运行的 exe 可执行文件能很好的解决上述问题。

    打包方式:

    • Clicknium Project
    • PyInstaller

    4.1 Clicknium Project 打包

    Clicknium Package 是 Clicknium 内置的项目管理方式,旨在保证自动化脚本在开发,调试,执行和分发过程中保证相同的运行结果。

    a. 创建 Clicknium Project

    在 VS Code 中, 按下 Ctrl+Shift+P 调出 Command Palette, 选择 Clicknium: Create Project ,然后指定一个路径用来保存项目。 在项目创建的过程中, 会同时为项目创建一个虚拟环境。 可以在 VS Code 的右下角看到 Python 解释器旁显示的环境信息。

    区别于普通的 Python 项目,这个 Project 中会自动创建几个文件:

    • app.py: Python 源文件
    • logo.icon:打包后可执行文件的 Icon
    • clicknium.yaml:Clicknium Project 的配置文件

    clicknium.yaml ,其中包含了项目的基本信息,包括入口和依赖,日志路径等。logo.icon 可以替换为你想要的 icon 文件。

    b. 运行和调试 Clicknium Project

    同样,在 VS Code 中, 按下 Ctrl+Shift+P 调出 Command Palette, 选择 Clicknium: Run Project 。Clicknium 就会更具 clicknium.yaml 中的配置运行项目。F5 直接运行文件时,是不会查看 yaml 中的配置进行部署和执行的。

    c. Clicknium Project 打包

    在 VS Code 中, 按下 Ctrl+Shift+P 调出 Command Palette, 选择 Clicknium: Package Project , 然后选择一个路径存放可执行文件,然后选择 console ,如果脚本中包含图形界面请选择 GUI ,否则图形界面可能无法正常显示。Clicknium 会根据 clicknium.yaml 中的信息进行打包。

    下面是一个 clicknium.yaml 文件的示例:

    startUp: app
    ignoreFiles: .gitignore
    log:
      folder: 
      type: File
    type: project
    requirements:
      python: 3.9.13
      pip: 
      packages:
      - package: clicknium
        version: 
      - package: pandas
        version: 1.5.3
      locators: []
    

    在上面的例子中:

    app:是 Python 程序的 entrypoint 文件

    log: 默认的 log path 是 C:\Users{currentUser}\AppData\Local\Clicknium\Log 。可以修改到其他路径,比如当前路径为 .\

    python: 打包进可执行文件的 Python 解释器版本

    packages: 需要打包进可执行文件的依赖库。Clicknium 会自动扫描脚本中使用到的 Python 库,并自动添加对应的库名和版本号。如果自动添加功能有问题, 可以收到修改这个部分。

    4.2 使用 Pyinstaller 打包

    除了内置的打包方式, 在 Python 开发中, 更常见的做法是使用 Pyinstaller: PyInstaller Manual进行打包。

    为保证项目的干净, 仍然建议使用 Python 虚拟环境进行开发。 通常,可以打开项目文件中的.vscode 文件夹中的 setting.json 文件找到项目使用的 Python 虚拟环境:

    a. 进入虚拟环境目录,使用 pip install pyinstaller 安装 pyinstaller 。可用 pip list 查看 pyinstaller 是已包含和具体的版本信息。

    b. 编辑 publish.spec

    配置说明:

    • 项目地址:{$"project app.py full path"},填写 project app.py 全路径,如:'c:\Users\{Username}\Desktop\Sample\app.py'
    • Clicknium SDK 路径:($'clicknium .lib automation full path', 'clicknium\.lib\automation'),填写 Python 虚拟环境 site-packages 文件夹 clicknium 文件夹下.lib\automation 全路径,譬如:binaries=[('C:\Users\{Username}\AppData\Local\Clicknium\Envs\Sample_17aea73e4ca65262\.virtualEnv\Lib\site-packages\clicknium\.lib\automation', 'clicknium\.lib\automation')]
    • 项目 Locator 地址:datas=[($'project .locator full path', '.locator')],填写 project .locator 文件夹全路径:譬如:datas=[('c:\Users\YanZhiwei\Desktop\Sample\.locator', '.locator')]
    • 可执行文件名:name=$'project name',填写打包生成 exe 名称,可自行填写

    下面是一个例子:

    # -*- mode: python ; coding: utf-8 -*-
    
    
    block_cipher = None
    
    
    a = Analysis(
        ['c:\Users\KayYOLO\Desktop\Sample\app.py'],
        pathex=[],
        binaries=[('C:\Users\KayYOLO\AppData\Local\Clicknium\Envs\Sample_17aea73e4ca65262\.virtualEnv\Lib\site-packages\clicknium\.lib\automation', 'clicknium\.lib\automation')],
        datas=[('c:\Users\KayYOLO\Desktop\Sample\.locator', '.locator')],
        hiddenimports=[],
        hookspath=[],
        hooksconfig={},
        runtime_hooks=[],
        excludes=[],
        win_no_prefer_redirects=False,
        win_private_assemblies=False,
        cipher=block_cipher,
        noarchive=False,
    )
    pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
    
    exe = EXE(
        pyz,
        a.scripts,
        a.binaries,
        a.zipfiles,
        a.datas,
        [],
        name='Sample',
        debug=False,
        bootloader_ignore_signals=False,
        strip=False,
        upx=True,
        upx_exclude=[],
        runtime_tmpdir=None,
        console=True,
        disable_windowed_traceback=False,
        argv_emulation=False,
        target_arch=None,
        codesign_identity=None,
        entitlements_file=None
    )
    

    5. 常见的问题:

    5.1 如何启动 Windows 应用程序

    可以利用 Python 的 subprocess 启动桌面应用程序

    import subprocess
    
    process_notpad = subprocess.Popen("notepad")
    process_feishu = subprocess.Popen("C:\Users\kay\AppData\Local\Feishu\Feishu.exe")  
    

    5.2 如果设置定时运行

    a. 在任务栏搜索任务计划程序

    b. 新建基本任务或新建任务

    c. 依次填入:

    • 任务名称
    • 触发器:选择触发条件,每日、周或月,启动时,登录时等
    • 操作: 选择启动程序,程序或脚本: 填写 python.exe 的地址。添加参数:自动化脚本的地址。

    5.3 对同一网站,如果开多个浏览器登录不同账号

    在浏览器自动化插件模式下,采用的是 attach 的方式,这种情况推荐使用 Chrome 和 Edge 浏览器调用 CDP 接口,将 tab 对象绑定对应的浏览器 tab 。 要使 web 浏览器实例之间不共享 cookie 并能在相同网站登录不同的账号,可以采用不同的 User profile 。

    根据open方法:

    def open(
            self,
            url: str,
            is_maximize: bool = True,
            is_wait_complete: bool = True,
            userdata_folder_mode: Literal["automatic", "default", "custom"] = WebUserDataMode.Automatic,
            userdata_folder_path: str = "",
            timeout: int = 30
        ) -> BrowserTab 
    

    将 userdata_folder_mode 设置为'custom', userdata_folder_path 传入不同的文件夹路径,作为不同 user profile 存储路径。不同浏览器 tab ,使用不同的路径,即可实现多账户登录。

    5.4 为什么有时候脚本会卡主很长时间,如何查看日志

    大部分脚本卡住的情况是因为无法找到 locator 对应的 UI 元素造成的。Clicknium 对 locator 的操作有默认 30 秒的 timeout 时间。 可以查看 API 文档,方法的 timeout 时间。 如果出现卡住的情况,先利用 Validation 确认 locator 是否能识别到 UI 元素。

    日志的默认路径为:C:\Users{currentUser}\AppData\Local\Clicknium\Log

    5.5 为什么一段时间后,locator 失效了

    导致 locator 失效的原因有很多,动态加载,版本更新,上下文变化都有可能。 首先可以在 locator 页面使用 Recapture&Compare 功能进行重新录制并对比新旧 locator 的区别。 不同的属性会高亮。

    对比不同属性,修改属性的值以匹配新 UI 。为了使 locator 更加稳定,推荐使用通配符,正则表达式,参数化 locator 等功能提高 locator 的鲁班性。

    5.6 为什么鼠标点击,键入文字没有效果

    可以查看Clicknium 使用指南 1。 切换系统调用方式和模拟鼠标方式。 某些情况录制按钮时,可能会录制到按钮内的 logo 或者外围的边框,对于系统调用来说,只有按钮才有点击属性。部分输入框也存在 click 或者 focus 状态下才能激活的情况,可选择输入前点击或者 focus 参数。 由于系统调用触发后并没有返回值,所以 Clicknium 无法抛出错误。 这种时候,建议采用模拟鼠标的方式点击按钮。

    上一篇: Clicknium 使用指南 1

    6 条回复    2024-04-21 16:21:55 +08:00
    N9f8Pmek6m8iRWYe
        1
    N9f8Pmek6m8iRWYe  
       2023-03-03 16:23:51 +08:00
    xinali
        2
    xinali  
       2023-03-03 17:30:02 +08:00
    老哥,如果是桌面应用,自动化依次点击打开文件夹中文件可以实现吗?我没看到类似的 samples
    heartlocker
        3
    heartlocker  
    OP
       2023-03-04 20:34:02 +08:00
    @xinali 可以。不过这个需求既然用 Python 了, 你可以直接 list 文件名然后执行应该会更简单。
    xinali
        4
    xinali  
       2023-03-06 08:32:39 +08:00
    @heartlocker 嗯,主要是有的桌面应用的部分复杂操作,没法实现直接用命令行来执行 python 列出来的文件,所以需要手动点击,你这个有类似的 sample 吗?
    heartlocker
        5
    heartlocker  
    OP
       2023-03-08 12:00:54 +08:00
    @xinali 你可以看一下上一篇文章。https://v2ex.com/t/920840#reply0
    桌面端的体验和网页端是一样的。只要录制以后,使用 locator 调用 click 方法就可以了。vs code 插件上有 sample 可以直接运行
    Abbeyok
        6
    Abbeyok  
       7 天前
    想问下,如果我是开发软件给卖给客户,我是需要买企业版?
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1191 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 18:10 · PVG 02:10 · LAX 11:10 · JFK 14:10
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.