【问题标题】:Python: Access to external process infoPython:访问外部进程信息
【发布时间】:2014-11-05 04:17:28
【问题描述】:

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

恢复我正在努力实现的目标:

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

我的目的是创建一个脚本来管理其他软件,类似于 Selenium 对浏览器所做的事情,但适用于任何程序。也许使用子进程使用 Python 执行进程会给我管理进程 UI 的选项


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

现在我正在使用psutil 在Linux 中制作这个脚本。我知道有一些 Windows 库,例如 pywinpywindll

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

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

  • 一旦我的脚本中有发送点击到 UI 按钮的流程,是否有可能? (或写入某个文本框)

我正在使用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

【问题讨论】:

  • @AntonSavin 非常感谢你提供这个链接,听起来很有趣!!
  • @AntonSavin 哇,从那个谷歌搜索的顶部结果中,我被引导到了autopy 0_o 我怎么会错过这个! +1
  • @Liarez 不要认为有这方面的书籍。试试明显的 wiki 链接和this。 GDbus 是现在实际存在的。命令行版本是here,绑定在here。您还可以使用 d-feet 轻松查看 dbus 消息

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


【解决方案1】:

我喜欢你认为 :D UI 自动化很棒的方式

就问题本身而言,据我所知,所有可以与流程的 GUI 交互的软件都是基于计算机视觉的 OCR 或读取内存以获取 UI 的对象模型。后者可能不是通用的,因为不同的小部件工具包和构建 UI 的方法会有不同的底层模型——它可能比 CV+OCR 更让人头疼。

如果您想查看已经为此目的制作的一些东西,请查看wikpedia list。您已经了解 Selenium,但还有更多 - AutoIt 和 Sikuli,我在其中检查了我想在 python 中制作的类似项目。 (AutoIt 类似于 BASIC -YUCK- 仅适用于 Windows,但 Sikuli 似乎与 python 相关并且是跨平台的 - 我很久以前就检查过它们,所以我不记得细节了)。

真正的好消息是 python 有非常好的 CV 和 OCR 模块。我个人的推荐是simplecv,它可以环绕opencv和其他cv软件,虽然我没有推荐用于OCR的模块,但我在寻找模块时最喜欢python-tesseract

该方法通常是拍摄 GUI 的快照(graphicsmagick 可以很好地做到这一点,并且有一个 python 包装器),用 CV 确定元素的位置,用 OCR 读取标签,这样你就得到了窗户上的模型。然后,根据脚本在 GUI 上的位置,为脚本提供关于做什么和何时执行的说明。由于 python 可以发送鼠标和键盘事件,所以你是金子。您甚至可以使用minidom 模块为您的代码创建更简单的对象模型。

顺便说一句,与《炉石传说》相关的应用程序也使用 CV+OCR 方法,该应用程序拍摄游戏快照并读取分数,然后跟踪玩家的分数,以便他们制定指标。这是一种比看起来更轻量和更简单的方法 - 我检查了代码,尽管它背后有重量级技术,但它很容易理解。

【讨论】:

  • 感谢您的回答和信息!我一直在寻找信息 OCR+CV 是实现这一目标的最流行方法,python-tesseract 听起来是一个非常好的库,我必须深入了解 simplecv ,无论如何,我非常感谢你的信息!
  • @Liarez 没问题!这是一个个人使用的项目还是你要发布它?我现在对这些东西很感兴趣,如果你要公开发布,我很想看看这个作品。
  • 现在我只是在做一些研究,我打算开始一个项目,但是小项目如果我有什么有趣的事情我会告诉你的!也许我们可以分享一些想法
  • @Liarez 太棒了!不要错过来自 OP 中的链接的 autopy,可能会节省您的工作或有一些有趣的想法。
  • 常春藤您是否尝试过使用 Xpresser 发送“Enter”?像在浏览器的地址栏中写入并按回车之类的东西?我一直在寻找 Xpresser 的文档,但没有找到太多
【解决方案2】:

我想我有一个解决方案可以从不同进程的程序中读取变量。好的,为了简化一些事情,例如,您正在尝试在用 C++ 编写的 2 个不同程序之间建立通信,例如程序 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 交互。通常,供应商向程序员公开用于与 UI 元素交互的 API。下面发生的事情很难理解和操作,因为在大多数情况下它们是封闭源代码。如果您可以访问 API 中的源代码,那么情况就不同了。然后,您可以使用上面提到的类似概念来写入另一个程序中的某个位置,该位置会触发 UI 中发生的事件。

【讨论】:

  • 感谢您的回答,但我正在尝试与现有的 外部 程序进行通信,而不是与我开发的 2 个不同的程序进行通信
  • 啊好吧,我想当你说任何程序时,你的意思是你写的任何程序:)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-08-23
  • 1970-01-01
  • 1970-01-01
  • 2012-02-28
  • 2013-08-23
  • 2020-05-09
  • 2021-10-27
相关资源
最近更新 更多