IBM 3270 Screen Scraping And Automation
In the late 1980s, when IBM PC had proliferated while I was still supporting IBM mainframe, I wrote a PC tool that sent commands to the mainframe and received responses back via the PC 3270 terminal emulator. This tool helped to automate repetitive keyboard entries by pretending to be an interactive user who extracts and updates information on the mainframe. Even more, we also used it to measure the response time of the mainframe commands in real-time. In today’s terminology, the tool is known as “screen scraper” (mimicking the more popular “web scraper”) but at that time it was called “PC robot”. As I recall, I wrote it in Rexx, a common scripting language for all IBM environments from mainframe to PC. The tool ran on IBM OS/2 and used EHLLAPI (Emulator High-Level Language Programming Interface) of Communication Manager/2 (CM/2) to communicate with the mainframe.
Fast forward to 2019, a friend called for help to do the same “PC robot.” Apparently, his local team is a user of an internal worldwide legacy application and the tool could help to automate the mainframe data extraction process without filling out a request form for the global IT support.
Frankly, after a couple of decades, I’m not sure if people are still using this kind of tool. However, a quick search on the Internet reveals that current users of the mainframe still indeed use it. It is no longer implemented in Rexx and OS/2, of course, but uses current popular languages and platforms, both commercial and open source. After doing some research I decided to implement it using Python, x3270 and py3270. It is free and runs on most of the modern platforms such as Windows, Linux, etc.
This short tutorial documents how to write a simple script to login to a mainframe terminal, doing some commands and then log off. You could expand it based on your requirements.
Pre-requisite
Python is the basic requirement, you can use Python 2 or Python 3. Python 3 is recommended because Python 2 is sunset. Depending on your OS, you may need to manually install it, or it’s already built-in.
Linux Ubuntu
Ubuntu 18:04 LTS comes with both Python 2 and Python 3 pre-installed. You can verify with the following commands:
$ python --version
Python 2.7.15+
$ python2 --version
Python 2.7.15+
$ python3 --version
Python 3.6.8
Please notice that the default is Python 2, so if you want to use Python 3, you have to indicate the suffix 3 explicitly.
Now what you need to do is to install: x3270, pip and py3270:
$ sudo apt update
$ sudo apt -y upgrade
$ sudo apt install -y x3270 python3-pip
$ pip3 install py3270
MS Windows
Windows doesn’t come with Python so you have to install it. The following installation steps assume your Windows is 64-bit:
- Go to https://www.python.org/downloads/windows/
- Download the “Windows x86-64 executable installer” for Python 3.7 (the latest stable release as of this writing)
- Install Python 3.7 and make sure to check “Add Python 3.7 to PATH” while doing so
To verify that python and pip are installed, open command prompts and issue these commands:
> python --version
> pip --version
You still need x3270 terminal emulator to run your 3270 screen scraper even though you may already use another terminal emulator such as IBM PCOMM to access your mainframe.
Download wc3270 (x3270 for Windows) from http://x3270.bgp.nu/download.html.
Run the installation EXE.
Once the installation completes, you will be asked to create a new wc3270 session. If you also want to use wc3270 to access the mainframe through wc3270 terminal then you need to create one, such as the case that you don’t have another 3270 terminal emulator. However to run your python screen scraper you don’t need to create a wc3270 session.
Finally, install the py3270 package.
> pip install py3270
Writing 3270 Screen Scraper
The challenge of practicing a mainframe tutorial is that not everybody has access to a mainframe. If you don’t have that kind of access, luckily you can use Hercules, a mainframe emulator that runs mainframe OS and application without any code changes on your PC or even on Raspberry Pi. See my article: “Look Ma! My $5 Pi Zero Thinks It’s a Mainframe.”
We will use the same MVS3.8J TK4 system and perform the same TSO/ISPF steps as shown in that article’s video ie: log in to TSO, create a CLIST library, create a “Hello World” clist, execute the clist and log out. In this tutorial, however, those TSO/ISPF commands will be run with scrape3270.py, a sample 3270 screen scraper written in Python. Although MVS 3.8 is very old, the IBM 3270 architecture does not change so that what is shown in this tutorial applies to the latest versions of IBM z /OS and z /VM as well.
I uploaded scrape3270.py to GitHub, please take a look at the code and the comment. Basically, it follows strictly what you do with the keyboard by calling the associated py3270 library method/function.
First, create an object of Emulator class. If you specify ‘visible=True’ as the argument then it will use x3270 so that you can see what is going on. If you specify ‘visible=False’ or no argument then it will use s3270 and it will run in the background.
Once an Emulator class object is created, the methods in py3270 library can be used to interact with the host.
- Connect to the host and login to TSO (line 20-48)
- List dataset (line 51-69)
- Capture the dataset list and store in screenrows[] (line 70-76)
- Create a clist dataset (line 77-120) unless the dataset already exists
- Write down ‘hello’ clist (line 121-161)
- Execute ‘hello’ clist from ISPF TSO command (line 162-179)
- Exit ISPF and return into TSO (line 180-193)
- Execute again ‘hello’ clist from TSO (line 197-200)
- Logoff from TSO, disconnect from host and terminate the 3270 subprocesses (line 201-207)
- Print out the dataset list information from #3 (line 208-210)
Py3270 Library References
- connect(host):
- Description: Connect to a host
- Arguments:
host (string): host name or IP address
- terminate():
- Description: terminates the underlying x3270 subprocess. Once called, this Emulator instance must no longer be used.
- Arguments: none
- exec_command(cmdstr):
- Description: Execute an x3270 command `cmdstr` gets sent directly to the x3270 subprocess on it’s stdin. Alternatively, there is some frequently used keys ‘shortcut’:
- send_enter() is equivalent to exec_command(b”Enter”)
- send_pf3() is equivalent to exec_command(b”PF(3)”)
- etc.
- Arguments:
cmdstr (string): x3270 command
- Description: Execute an x3270 command `cmdstr` gets sent directly to the x3270 subprocess on it’s stdin. Alternatively, there is some frequently used keys ‘shortcut’:
- wait_for_field():
- Description: Wait until the screen is ready, the cursor has been positioned on a modifiable field, and the keyboard is unlocked. Sometimes the server will “unlock” the keyboard but the screen will not yet be ready. In that case, an attempt to read or write to the screen will result in a ‘E’ keyboard status because we tried to read from a screen that is not yet ready. Using this method tells the client to wait until a field is detected and the cursor has been positioned on it.
- Arguments: none
- string_get(ypos, xpos, length):
- Description: Get a string of ‘length’ at screen coordinates ‘ypos’/’xpos’. Coordinates are 1 based, as listed in the status area of the terminal.
- Arguments:
ypos (int): y position (row number)
xpos (int): x position (column number)
length (int): length of the string
- string_found(ypos, xpos, string):
- Description: Return True if `string` is found at screen coordinates ‘ypos’/’xpos’, False otherwise. Coordinates are 1 based, as listed in the status area of the terminal.
- Arguments:
ypos (int): y position (row number)
xpos (int): x position (column number)
length (int): length of the string
- move_to(ypos, xpos):
- Description: move the cursor to the given coordinates. Coordinates are 1 based, as listed in the status area of the terminal.
- Arguments:
ypos (int): y position (row number)
xpos (int): x position (column number)
- send_string(tosend, ypos=none, xpos=none):
- Description: Send a string to the screen at the current cursor location or at screen coordinates ‘ypos’/’xpos’ if they are both given. Coordinates are 1 based, as listed in the status area of the terminal.
- Arguments:
tosend (string): string to be sent to the screen
ypos (int): y position (row number)
xpos (int): x position (column number)
- fill_field(ypos, xpos, tosend, length):
- Description: Clears the field at the position given and inserts the string `tosend`. Coordinates are 1 based, as listed in the status area of the terminal. Raises: FieldTruncateError if ‘tosend’ is longer than ‘length’.
- Arguments:
ypos (int): y position (row number)
xpos (int): x position (column number)
tosend: the string to insert
length: the length of the field
- delete_field():
- Description: Delete contents in field at current cursor location and positions, cursor at beginning of field.
- Arguments: none
- save_screen(file_path):
- Description: Save the current screen as a file.
- Arguments:
file_path (string): file path and name
Hi Hendro,
What I meant to say is that I am on IBMi (formerly known as AS/400) is there a way I can use your tool on IBMi to connect to a Mainframe using s3270 for screen scraping purpose?
Is s3270 available for IBMi?
We do have python on IBMi.
Hi,
I am on IBMi (formerly known as AS/400). It does have Python and a different 3270 emulator on it, is there a way I can use your tool on IBMi?
Nope, mainframe terminal (3270) is different from AS/400 terminal (5250). I never used AS/400 myself. However I notice there is 5250 terminal emulator python library that seems was created from the same 3270 terminal emulator python library used here. You may use it with some modification. Please check it on this link.
Hi,
Getting error: Error: (, CommandError(‘Ignoring invalid BIND image screen size parameters: BIND Alternate Rows-Cols 27×132 > Maximum 32×80’), )
Please suggest me how to resolve it.
Another point- If I had created a session using session-wizard then how to use it?
Kind regards,
Manish
Hi,
Facing below error while connecting to wc3270 through python script.
Error – TLS: InitializeSecurityContext: error 0x80090322 (The target principal name is incorrect.)
Disconnected
Script :
my3270 = Emulator(visible=True)
my3270.connect(myhost)
Kindly suggest How to make the verifyHostCert=false through above script or what is the keyword to set the verifyHostCert=false through script ???
Appreciate your kind response.
Hi
When I use the script to access the mainframe, it indicated the below error.
It seems like the keyboard is locked when running the python script, doesn’t it? If yes, how to unlock the keyboard? Thanks in advance!
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Traceback (most recent call last):
File “setup.py”, line 10, in
e.wait_for_field()
File “C:\Users\AppData\Local\Programs\Python\Python37\lib\site-packages\py3270\__init__.py”, line 381, in wait_for_field
self.status.keyboard.decode(“ascii”)
py3270.KeyboardStateError: keyboard not unlocked, state was: L
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Hello, I am getting following error while connecting server :
SSL: InitializeSecurityContext: error 0x80090322 (The target principal name is incorrect.)
Is it possible to send following attribute while calling connect or any other alternate methods?
wc3270.verifyHostCert: false
Hi, I am facing some issue while establishing the host connection using my3270.connect(myhost) step.
Error – TLS: InitializeSecurityContext: error 0x80090322 (The target principal name is incorrect.)
Disconnected.
Is there any argument we can pass while calling connect function similar to ‘my3270.verifyHostCert: false’ which can ignore cert verification?
Please share your thoughts.
Can py3270 be used to work with multiple host sessions at the same time? I wrote a script to create two sessions (using different variables) to different systems and logon to both of them. The first one gets logged on okay. The second session gets connected okay — but when the script tries to logon to it, for some reason the script bombs with the FIRST session reporting that the keyboard is locked.
It almost seems like by itself py3270 cannot handle multiple 3270 sessions…
Hi
While using save_screen functionality, it is accepting only html.
Can please someone suggest how to save file as png using save_screen method.
Thanks advance
Hi
Save_screen is allowing to take screenshot in HTML and if we are trying to take different format, it is not allowing and getting invalid format while opening it.
Can someone help me , how to capture screenshot as png using it
How to pass f2 and f11 key using py3270 in mainframe?
Mainframe terminal only recognizes PFn keys although PC terminal emulator will map that to PC Fn keys. So for py3270 you should use PF2 and PF11 instead of F2 and F11. Refer to section Py3270 Library References, i.e: send_pf3() is equivalent to exec_command(b”PF(3)”).
How to pass f2 and f11 key to mainframe using py3270?
I installed WC3270 and created a new session however I don’t know how to start WC3270 emulator
You do not need to install wc3270 emulator to run your python scrapper. See the previous comments below..
You do not have to install the WC3270 emulator.
You can simply copy the WC3270.exe file to the same folder as your code and append the path on the go : sys.path.append(‘wc3270’).
This will solve the issue
@Niveditha Ramayanam
you do not need to install WC3270. Instead you can keep the WC3270.exe in the same folder as your code and then add this to the code sys.path.append(‘wc3270’)
This will take care of your path on the go and it will run smoothly.
Dear Mahi, I am getting ‘ConnectionRefusedError: [WinError 10061] No connection could be made because the target machine actively refused it’ error and ‘Windows cannot find wc3270. Make sure you typed the name correctly, and try again later.’ message is thrown when attempting to execute the code – my3270 = Emulator(visible=True).
Note – I have set the system environment variable path with wc3270 installation path.
very great work thanks for sharing was able to build smoothly without change in environment variable just download MVS 3.8j Tur(n)key 4- System(http://wotho.ethz.ch/tk4-/tk4-_v1.00_current.zip) check for port number , in wc3270 need to create one time connection
steps on how to do
1- pip install py3270
2- Download wc3270 (x3270 for Windows) from http://x3270.bgp.nu/download.html. and install as it is
3- download – http://wotho.ethz.ch/tk4-/tk4-_v1.00_current.zip, extract files it to a desired folder
3.1 – cd to path where \tk4-_v1.00_current is there
3.2 run mvs.bat ( windows) , keep it running do not close
4- get u r ip and change that in python scrape3270.py script
4.1 – check where which port number TK4 is running as default MVS 3.8j Tur(n)key 4- System runs on 3124
4.3 – if connection refused is there port number mismatch is there in wc3270 ( type this in cmd wc3270 and create a new connection with port number 3124)
5 – run python scrape3270.py post changing IP numbner of your machine
no need to change any env variable
Thanks
Dear Support,
We are using scrape3270.py as it is( rest host, login and password are different)
Also we have made “Port” changes in ..\lib\site-packages\py3270\__init__.py file
Still getting below error
ValueError(‘expected “ok” or “error” result, but received: ‘),
Hi,
We are getting below error.
Error : expected “ok” or “error” result, but received:
scrape3270.py same code used by me ( replaced the host, login and Password rest code same as it is)
in ..\lib\site-packages\py3270\__init__.py file changed port number
Yes i too faced the same .. instead of fixing environment variable . set the global path in command prompt
Hi, I am not able to create an Emulator object . It says wc3270 is not found. I tried to add path to environment variable. It isn’t working at all! Please help.