Python:访问外部流程信息

时间:2014-09-11 09:20:49

标签: python python-2.7 process automation ui-automation

我正在试图弄清楚如何使用Python 管理进程,尽管C ++可能会更好。我正在使用 Python 2.7 Ubuntu 14.04 是我的操作系统。

恢复我想要实现的目标:

  • 操作(不是信号)发送到正在运行的进程 // 与进程的UI进行交互
  • 读取内存地址值

我的目的是创建一个脚本来管理其他软件,类似于 Selenium 对浏览器所做的事情,但与任何程序有关。也许使用Python使用Python执行流程可以让我选择管理流程UI


发送操作/与正在运行的进程交互

现在我正在使用psutil在Linux中创建此脚本。我知道有一些Windows库,如pywinpywindll

我想管理一个流程,例如任何一种带有UI的软件(Skype,Gedit,Firefox ..),我想知道是否可以发送动作来点击按钮。

我不想在计算机上管理鼠标,因为我们说这个窗口在其他窗口/东西下是“隐藏”的:

  • 我的脚本中有一个流程可以将点击发送到用户界面的按钮吗? (或写入一些文本框)

我正在使用psutil来完成这个过程,我有很多选择:

  • 获取内存映射
  • 获取流程的主题
  • 终止这个过程
  • CPU使用率

但这些动作似乎都不是我想要的,那就是与流程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))
  • 这是在Python中访问内存地址的最简单方法吗?
  • 可以实时修改/更新此号码吗?
  • 如何用IU识别内存地址?

我在想,一个程序执行时必须将程序的UI发送到操作系统,可以“捕获”接口与python,并重定向到操作系统?

通过 Python执行软件之类的东西,可以直接管理UI

2 个答案:

答案 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中发生的事件的程序中的某个位置。