Clicknium是一个可以用来控制桌面应用和浏览器的 Python 库。 在Clicknium 使用指南 1 中介绍了 Clicknium 的基本概念和使用方法。本章将更深入的介绍 Clicknium 的高级功能。
我们经常需要处理网页或应用中大量相似的元素,例如 List 和 Grid 中的 UI 元素。 依次抓取这些元素会产生大量的 locator ,显然不是一个好方法。 有用户甚至提问,将同一类 locator 放在了一个文件夹下,怎么能遍历 locator 文件夹。 当然,采用之前提到了参数化 locator 也是一种做法。但是,一方面你需要分析是用哪个属性和什么值来遍历 UI 元素,另一方面,参数的范围很可能不得而知,尤其随着应用越来越复杂,越来越多采用动态加载的方式导致要抓取的 UI 元素总量无法预测。 通常我们会使用 BeautifulSoup 这类的库来解析网站的 HTML 结构,由于网站的样式越来越复杂,抓取的内容并不会总是在同一个结构中, 每个 Item 可能被多层 div 或者其他元素包裹,所以在解析时,我们需要分析 HTML 的结构并构建一个算法找所有元素的最小公共节点,并且遍历该结构。 这一过程确实比较花时间, 同时也是一个能被算法解决的问题。
Clicknium Recorder 中,包含了抓取相似元素的功能。 用户通过抓取两个相似(同一层级)的元素,Clicknium 内置算法自动解析 HTML 结构,并计算最小公共节点和层级信息 ,以实现抓取相似元素。 如果计算出来的元素并不是用户想要的,可进行第三次抓取,算法将通过三个 UI 元素的信息,重新计算抓取路径。
以 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()
在自动化场景中, 获取结构化数据,尤其是表格数据也有很大的需求。获取相似元素只适合抓取一列数据。当然可以一列一列抓取一个表格,当这种方式会存在不同列之间的对齐问题,存在出错的可能同时操作也非常麻烦。
结构化数据有两个常见的场景:
表格比较好理解, 什么是非表格类结构化数据呢?如上面提到了 OpenSea 的页面中, 如果同时需要抓取 NFT 图片对应的价格,编号,从而构成一个表格就可以认为非表格类结构化数据。相比获取相似元素,结构化数据增加了不同列之前的匹配算法和一系列方便表格操作的功能。
以Coingecko举例,当需要抓取下面的表格
Clicknium 会自动探测抓取对象为表格,并提示是否抓取全表信息:
点击 Yes ,即可看到数据预览。在预览页面,支持修改列名,改变列的顺序, 删除列等操作。也可以选择 No ,然后一列一列选择需要的数据。
以最常见的京东作为例:京东手机页面
在这个例子中, 我们需要抓取商品名,价格和图片。操作的方式与获取相似元素类似, 两个元素决定一列:
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))
在默认情况下,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 。 |
在录制器中,可以修改默认选项,选择自己需要的自动化技术:
自动化脚本的用户,不一定就是 Python 程序员本人。 当自动化脚本需要交给不同用户时,会需要各种各样的问题。 有可能对方没有 Python 环境,缺乏某个 Python 库,或者存在版本冲突,甚至对方是业务人员不是程序员。 将脚本打包成人人可运行的 exe 可执行文件能很好的解决上述问题。
打包方式:
Clicknium Package 是 Clicknium 内置的项目管理方式,旨在保证自动化脚本在开发,调试,执行和分发过程中保证相同的运行结果。
a. 创建 Clicknium Project
在 VS Code 中, 按下 Ctrl+Shift+P 调出 Command Palette, 选择 Clicknium: Create Project ,然后指定一个路径用来保存项目。 在项目创建的过程中, 会同时为项目创建一个虚拟环境。 可以在 VS Code 的右下角看到 Python 解释器旁显示的环境信息。
区别于普通的 Python 项目,这个 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 库,并自动添加对应的库名和版本号。如果自动添加功能有问题, 可以收到修改这个部分。
除了内置的打包方式, 在 Python 开发中, 更常见的做法是使用 Pyinstaller: PyInstaller Manual进行打包。
为保证项目的干净, 仍然建议使用 Python 虚拟环境进行开发。 通常,可以打开项目文件中的.vscode 文件夹中的 setting.json 文件找到项目使用的 Python 虚拟环境:
a. 进入虚拟环境目录,使用 pip install pyinstaller 安装 pyinstaller 。可用 pip list 查看 pyinstaller 是已包含和具体的版本信息。
b. 编辑 publish.spec
配置说明:
下面是一个例子:
# -*- 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
)
可以利用 Python 的 subprocess 启动桌面应用程序
import subprocess
process_notpad = subprocess.Popen("notepad")
process_feishu = subprocess.Popen("C:\Users\kay\AppData\Local\Feishu\Feishu.exe")
a. 在任务栏搜索任务计划程序
b. 新建基本任务或新建任务
c. 依次填入:
在浏览器自动化插件模式下,采用的是 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 ,使用不同的路径,即可实现多账户登录。
大部分脚本卡住的情况是因为无法找到 locator 对应的 UI 元素造成的。Clicknium 对 locator 的操作有默认 30 秒的 timeout 时间。 可以查看 API 文档,方法的 timeout 时间。 如果出现卡住的情况,先利用 Validation 确认 locator 是否能识别到 UI 元素。
日志的默认路径为:C:\Users{currentUser}\AppData\Local\Clicknium\Log
导致 locator 失效的原因有很多,动态加载,版本更新,上下文变化都有可能。 首先可以在 locator 页面使用 Recapture&Compare 功能进行重新录制并对比新旧 locator 的区别。 不同的属性会高亮。
对比不同属性,修改属性的值以匹配新 UI 。为了使 locator 更加稳定,推荐使用通配符,正则表达式,参数化 locator 等功能提高 locator 的鲁班性。
可以查看Clicknium 使用指南 1。 切换系统调用方式和模拟鼠标方式。 某些情况录制按钮时,可能会录制到按钮内的 logo 或者外围的边框,对于系统调用来说,只有按钮才有点击属性。部分输入框也存在 click 或者 focus 状态下才能激活的情况,可选择输入前点击或者 focus 参数。 由于系统调用触发后并没有返回值,所以 Clicknium 无法抛出错误。 这种时候,建议采用模拟鼠标的方式点击按钮。
上一篇: Clicknium 使用指南 1
1
N9f8Pmek6m8iRWYe 2023-03-03 16:23:51 +08:00
收
|
2
xinali 2023-03-03 17:30:02 +08:00
老哥,如果是桌面应用,自动化依次点击打开文件夹中文件可以实现吗?我没看到类似的 samples
|
3
heartlocker OP @xinali 可以。不过这个需求既然用 Python 了, 你可以直接 list 文件名然后执行应该会更简单。
|
4
xinali 2023-03-06 08:32:39 +08:00
@heartlocker 嗯,主要是有的桌面应用的部分复杂操作,没法实现直接用命令行来执行 python 列出来的文件,所以需要手动点击,你这个有类似的 sample 吗?
|
5
heartlocker OP @xinali 你可以看一下上一篇文章。https://v2ex.com/t/920840#reply0
桌面端的体验和网页端是一样的。只要录制以后,使用 locator 调用 click 方法就可以了。vs code 插件上有 sample 可以直接运行 |
6
Abbeyok 245 天前
想问下,如果我是开发软件给卖给客户,我是需要买企业版?
|
7
skymanv2 157 天前
99 美刀有点贵,如果便宜一点,愿意支持一下
|
8
crystom 128 天前
分页数据怎么抓取处理?
|