我正在试图弄清楚如何使用Python 管理进程,尽管C ++可能会更好。我正在使用 Python 2.7 而 Ubuntu 14.04 是我的操作系统。
恢复我想要实现的目标:
我的目的是创建一个脚本来管理其他软件,类似于 Selenium 对浏览器所做的事情,但与任何程序有关。也许使用Python使用Python执行流程可以让我选择管理流程UI
发送操作/与正在运行的进程交互
现在我正在使用psutil
在Linux中创建此脚本。我知道有一些Windows库,如pywin
或pywindll
。
我想管理一个流程,例如任何一种带有UI的软件(Skype,Gedit,Firefox ..),我想知道是否可以发送动作来点击按钮。
我不想在计算机上管理鼠标,因为我们说这个窗口在其他窗口/东西下是“隐藏”的:
我正在使用psutil
来完成这个过程,我有很多选择:
但这些动作似乎都不是我想要的,那就是与流程UI进行交互......
甚至有可能实现我想要实现的目标吗?
发送击键和鼠标点击是最简单的解决方案吗?
读取内存地址值
我一直在Linux中使用scanmem
来查找某个变量的内存地址,一旦我找到了我正在寻找的内存地址,我想在Python中使用该地址来获取存储在该地址中的值。
我发现最接近的是使用ctypes
,例如:
from ctypes import string_at
from sys import getsizeof
mem_address = 0x7c3f
value = string_at(id(mem_address), getsizeof(mem_address))
我在想,一个程序执行时必须将程序的UI发送到操作系统,可以“捕获”接口与python,并重定向到操作系统?
通过 Python执行软件之类的东西,可以直接管理UI
答案 0 :(得分:2)
我喜欢你的想法:D UI自动化很棒
就问题本身而言,据我所知,所有可与流程GUI交互的软件都基于OCR的计算机视觉或读取内存以获取UI的对象模型。后者可能不是通用的,因为构建UI的不同小部件工具包和方法将具有不同的底层模型 - 它可能比CV + OCR更难以屁股。
如果您想查看已经为此目的制作的一些内容,请查看wikpedia list。你已经了解了Selenium,但还有更多 - AutoIt和Sikuli,我在python中检查了我想做的类似项目。 (AutoIt类似BASIC - YUCK - 仅限Windows,但Sikuli似乎与python相关并且是跨平台的 - 我在很久以前检查过它们所以我不记得细节了。) p>
真正的好消息是python有很好的CV和OCR模块。我的个人建议是simplecv,它可以包含opencv和其他cv软件,虽然我没有选择推荐OCR的模块,但在我寻找模块时,我最喜欢python-tesseract。
这种方法通常是对GUI进行快照(graphicsmagick可以很好地完成它并且有一个python包装器),用CV表示元素的位置,用OCR读取标签,这样你得到一个窗口上的内容模型。然后,根据GUI上的位置,为脚本提供有关操作和时间的说明。由于python可以发送鼠标和键盘事件,你是金色的。您甚至可以使用minidom
模块为代码创建更简单的对象模型。
另外,一个与炉石相关的应用程序也使用CV + OCR方法,该应用程序拍摄游戏的快照并读取分数,然后分析该分数,以便他们可以组成指标。这是一个比看起来更轻巧,更简单的方法 - 我检查了代码并且它很容易理解,尽管背后有重量级技术。
答案 1 :(得分:0)
我认为我有一个解决方案,可以从不同进程的程序中读取变量。好的简化一些事情可以说比如说你试图建立一个用C ++编写的两个不同程序之间的通信,比如程序A和程序B.关于你的查询,我们会遇到程序'A'尝试的情况访问程序'B'中变量的值。
在这种情况下,我认为您可以使用Boost进程间通信。因此Boost Interprocess是Boost中的一个库,允许您使用共享内存在两个进程之间进行通信。您可以使用库中的消息队列。有关详细信息,请在此处查看:
http://www.boost.org/doc/libs/1_56_0/doc/html/interprocess.html
回到示例,您需要编写一些代码来支持在进程之间读取和写入变量。让我们说现在我们只能读写数组和标量值。因此,您需要维护一个数据结构(最好是一个映射),将变量名称映射到内存中的某个位置。像这样:
#include <map>
//Somewhere in your program you have a variable
int my_var = 5;
//Declare a map of string mapping to 64 bit pointers
std::map<std::string, long long> var_map;
//At any point you decide to register the reference of this value
var_map["my_var"] = (long long) &my_var;
//Now that you have registered this value,
//you can access it according to the name and
//type cast it as well to a data structure that you like
int *ptr = (int *) var_map["my_var"];
//Now you can play around with this:
*ptr = 1024;
所以我希望你能看到我在这里尝试做什么,所以这种类型的代码将出现在我们的程序B中。这样做的原因是程序A可以向程序B发送命令,说我想要读取一个名为“my_var”的变量。
现在是实际沟通的一部分。在Boost Interprocess中,您可以打包可以读取命令的结构,例如:
typedef ReadCommand {
char *var_name;
int read_bytes;
}
请阅读Boost中的文档,了解如何设置共享内存实例,因为一旦设置完毕,您就可以发送如下命令:
//Code in program A
ReadCommand read_command;
read_command.var_name = "my_var";
read_command.bytes = 4;
try {
//Need to declare message_queue, please see doc in Boost
message_queue_A->send(&read_command, sizeof(ReadCommand), 0);
} catch (boost::interprocess::interprocess_exception &ex){
//Handle exception
}
再次回到程序B,您可以使用这样的代码来接收消息:
//Best to have struct definition in shared header file
ReadCommand read_command_B;
int some_priority;
boost::interprocess::message_queue::size_type size_of_data_recvd;
message_queue_B->receive(&read_command_B, sizeof(ReadCommand), size_of_data_recvd, some_priority);
//use information in read_command_B
//to access var_map then use another
//message queue to send back data to
//Program A which will be expecting
//some information from program B.
无论如何,一旦你完成了,你就可以将python与Boost python库集成。希望这是有道理的。尝试一下,如果您有任何问题,请告诉我。这不是确切的实现,而是一个可以为您的读取值问题提供解决方案的想法。
至于发送动作问题,我不确定如何在另一个进程中与UI进行交互。通常,供应商向程序员公开API,该程序员用于与UI元素交互。下面发生的事情很难理解和操纵,因为在大多数情况下它们都是封闭源。如果您可以访问API中的源代码,那么这将是一个不同的情况。然后,您可以使用上面提到的类似概念来写入另一个触发UI中发生的事件的程序中的某个位置。