Interact with Other Programs Using Python

Interact with other programs using Python

If what you're really looking into is a good excuse to teach yourself how to interact with other apps, this may not be the best one. Web browsers are messy, the timing is going to be unpredictable, etc. So, you've taken on a very hard task—and one that would be very easy if you did it the usual way (talk to the server directly, create the text file directly, etc., all without touching any other programs).

But if you do want to interact with other apps, there are a variety of different approaches, and which is appropriate depends on the kinds of apps you need to deal with.

  • Some apps are designed to be automated from the outside. On Windows, this nearly always means they a COM interface, usually with an IDispatch interface, for which you can use pywin32's COM wrappers; on Mac, it means an AppleEvent interface, for which you use ScriptingBridge or appscript; on other platforms there is no universal standard. IE (but probably not Chrome) and Word both have such interfaces.

  • Some apps have a non-GUI interface—whether that's a command line you can drive with popen, or a DLL/SO/DYLIB you can load up through ctypes. Or, ideally, someone else has already written Python bindings for you.

  • Some apps have nothing but the GUI, and there's no way around doing GUI automation. You can do this at a low level, by crafting WM_ messages to send via pywin32 on Windows, using the accessibility APIs on Mac, etc., or at a somewhat higher level with libraries like pywinauto, or possibly at the very high level of selenium or similar tools built to automate specific apps.

So, you could do this with anything from selenium for Chrome and COM automation for Word, to crafting all the WM_ messages yourself. If this is meant to be a learning exercise, the question is which of those things you want to learn today.


Let's start with COM automation. Using pywin32, you directly access the application's own scripting interfaces, without having to take control of the GUI from the user, figure out how to navigate menus and dialog boxes, etc. This is the modern version of writing "Word macros"—the macros can be external scripts instead of inside Word, and they don't have to be written in VB, but they look pretty similar. The last part of your script would look something like this:

word = win32com.client.dispatch('Word.Application')
word.Visible = True
doc = word.Documents.Add()
doc.Selection.TypeText(my_string)
doc.SaveAs(r'C:\TestFiles\TestDoc.doc')

If you look at Microsoft Word Scripts, you can see a bunch of examples. However, you may notice they're written in VBScript. And if you look around for tutorials, they're all written for VBScript (or older VB). And the documentation for most apps is written for VBScript (or VB, .NET, or even low-level COM). And all of the tutorials I know of for using COM automation from Python, like Quick Start to Client Side COM and Python, are written for people who already know about COM automation, and just want to know how to do it from Python. The fact that Microsoft keeps changing the name of everything makes it even harder to search for—how would you guess that googling for OLE automation, ActiveX scripting, Windows Scripting House, etc. would have anything to do with learning about COM automation? So, I'm not sure what to recommend for getting started. I can promise that it's all as simple as it looks from that example above, once you do learn all the nonsense, but I don't know how to get past that initial hurdle.

Anyway, not every application is automatable. And sometimes, even if it is, describing the GUI actions (what a user would click on the screen) is simpler than thinking in terms of the app's object model. "Select the third paragraph" is hard to describe in GUI terms, but "select the whole document" is easy—just hit control-A, or go to the Edit menu and Select All. GUI automation is much harder than COM automation, because you either have to send the app the same messages that Windows itself sends to represent your user actions (e.g., see "Menu Notifications") or, worse, craft mouse messages like "go (32, 4) pixels from the top-left corner, click, mouse down 16 pixels, click again" to say "open the File menu, then click New".

Fortunately, there are tools like pywinauto that wrap up both kinds of GUI automation stuff up to make it a lot simpler. And there are tools like swapy that can help you figure out what commands you want to send. If you're not wedded to Python, there are also tools like AutoIt and Actions that are even easier than using swapy and pywinauto, at least when you're getting started. Going this way, the last part of your script might look like:

word.Activate()
word.MenuSelect('File->New')
word.KeyStrokes(my_string)
word.MenuSelect('File->Save As')
word.Dialogs[-1].FindTextField('Filename').Select()
word.KeyStrokes(r'C:\TestFiles\TestDoc.doc')
word.Dialogs[-1].FindButton('OK').Click()

Finally, even with all of these tools, web browsers are very hard to automate, because each web page has its own menus, buttons, etc. that aren't Windows controls, but HTML. Unless you want to go all the way down to the level of "move the mouse 12 pixels", it's very hard to deal with these. That's where selenium comes in—it scripts web GUIs the same way that pywinauto scripts Windows GUIs.

How to interact with a window's GUI with Python?

pywinauto seems to be much more in-line with what you want - it utilizes the Win32 API and MS UI Automation among other things.

Here is an example of automation of the notepad application:

from pywinauto.application import Application
app = Application().start("notepad.exe")

app.UntitledNotepad.menu_select("Help->About Notepad")
app.AboutNotepad.OK.click()
app.UntitledNotepad.Edit.type_keys("pywinauto Works!", with_spaces = True)

Python 3.x Interaction with other Program GUIs

You could look into sikuli. It lets you automate clicks and other actions based on region or matched graphic. Fairly smart. Is there a reason you're dead set on using py3?

Using Python to manipulate the GUI's of other programs?

pyWinAuto will work nicely for this. With it you can "type" text into windows based on window title( or window class) as well as "click" buttons. Its fairly easy to use, and the website is pretty good about giving you examples on how to do what you want.

http://pywinauto.openqa.org/howto.html

How to interact with an external program in Python 3?

If you have fixed input to your program (means input not changing at run time) then this solution can be relevant.

Answer

First create file.

  • Input file. name it input.txt and put 1 2 in it

command = "python test.py < input.txt > output.txt 2>&1"

# now run this command

os.system(command)

When you run this, you will find output.txt in same directory. If your program is executed successfully then output.txt contains output of code test.py but if your code gives any error then error is in output.txt.

Answer As You Want

main.py become

import sys
from subprocess import PIPE, Popen

EXTERNAL_PROG = 'test.py'

p = Popen(['python3', EXTERNAL_PROG], stdout=PIPE, stdin=PIPE, stderr=PIPE)

print(p.stdout.readline())
print(p.stdout.readline())
p.stdin.write(b'1\n')
p.stdin.write(b'2\n')
p.stdin.flush()
print(p.stdout.readline())
print(p.stdout.readline())

Simplest way to interact with a Python script that is called by another program?

You can make client.py temporarily override sys.stdin and sys.stdout with the system's console device whenever it needs to input from or output to the console, and restore sys.stdin and sys.stdout afterwards. In UNIX-like systems, the console device is /dev/tty, and in Windows, it is con.

For example, with a client.py like:

import sys

original_stdin = sys.stdin
original_stdout = sys.stdout
console_device = 'con' if sys.platform.startswith('win') else '/dev/tty'

def user_print(*args, **kwargs):
sys.stdout = open(console_device, 'w')
print(*args, **kwargs)
sys.stdout = original_stdout

def user_input(prompt=''):
user_print(prompt, end='')
sys.stdin = open(console_device)
value = input('')
sys.stdin = original_stdin
return value

user_print('Server says:', input())
print(user_input('Enter something for the server: '), end='')

and a server.py like:

from subprocess import Popen, PIPE

p = Popen('python client.py', stdin=PIPE, stdout=PIPE, encoding='utf-8', shell=True)
output, _ = p.communicate('Hello client\n')
print('Client says:', output)

you can interact with server.py like:

Server says: Hello client
Enter something for the server: hi
Client says: hi

Demo: https://repl.it/@blhsing/CheeryEnchantingNasm



Related Topics



Leave a reply



Submit