CLI Scraping
In this lesson, we'll explore how to use the Netmiko library to automate interactions with network devices. We'll cover three scripts that progressively build on each other, demonstrating how to connect to devices, retrieve interface information, and handle multiple devices efficiently.
Prerequisites - venv and Netmiko¶
mkdir cli-scraping
cd cli-scraping
uv venv
uv pip install netmiko
What we've done here:
- Created a new directory
cli-scraping. - Changed to the new directory.
- Created a new virtual environment using
uv venv. - Installed the
netmikolibrary usinguv pip install netmiko.
What is uv?
uv is a command-line tool that simplifies common tasks in Python development. It is designed to be easy to use and remember.
uv installation instructions.
Third-Party Libraries and imports¶
We have installed netmiko, a third-party library for the first time. Third party libraries are not included in the Python
standard library. They are developed by the community and can be installed using pip, uv, pdm and other similar tools.
When we use third party libraries, we need to import them into our scripts. This is done using the import statement. In the
following scripts, we import the netmiko library to use its functions.
The above code import the netmiko module into our script. A module is a library or file containing Python definitions and
statements. Modules can contain functions, classes, and variables, and can be imported into other modules or scripts. In the
case of netmiko, it is a module that provides wide range of functions and classes to interact with network devices.
In the example today we will use the ConnectHandler class from the netmiko module to establish a connection to a network device.
Running scripts in a virtual environment¶
When you install a library in a virtual environment, you need to activate the virtual environment to use the library.
Visual Studio Code users can use the integrated terminal to run the scripts - the terminal will automatically activate the virtual environment for you, when you press the play / run button in the top right corner of the editor.
If you like execute the script on the command line in a terminal, you would normally run the script like this:
This can still be done, but you need to activate the virtual environment first. To activate the virtual environment, run:
To deactivate the virtual environment, run:
Even better! Use uv run to execute your scripts¶
Forget about activating and deactivating the virtual environment. Use uv run to execute your scripts.
Basic Connection and Command Execution with Netmiko¶
This section demonstrates how to establish a connection to a network device and execute a command to retrieve interface information.
As we already established, we installed netmiko to handle SSH connections.
Next, we use the getpass function from the standard library to securely prompt the user for a password.
The pprint function is used to print the output in a structured format, to help us build the code step by step.
ops = "cisco_ios"
ip_addr = input("Device IP or hostname: ")
user = input("Enter username: ")
pw = getpass("Enter password: ")
the ConnectHandler class requires a few parameters to establish a connection, so we start by collecting the necessary
information from the user. We have hardcoded the device type as cisco_ios for now, but this can be changed to a variable if needed.
handler = netmiko.ConnectHandler(
device_type=ops,
username=user,
password=pw,
host=ip_addr,
)
We instantiate Netmiko's ConnectHandler class with the device type, username, password, and IP address. This establishes a
connection to the device. The handler object is an instance of the ConnectHandler class used to interact with the device.
# saves the result to a variable - note the use_textfsm toggle, it gives us structured data rather than a text blob
result = handler.send_command("show ip interface brief", use_textfsm=True)
pprint(result)
After the hard work is done it's pretty simple to send commands to our device, and have the results printed to the screen.
In this example we are using the show ip interface brief command, and the use_textfsm=True option to format the output
as structured data.
We get a nice list of dicts as output, which is easy to manipulate or use with Python. This is thanks to Netmiko,
TextFSM and NTC-templates doing a lot of background work for us, out of the box.
As a final task, we could choose to print only the name and status of the interfaces to practice working with structured data like lists and dictionaries.
for interface in result:
print(f"{interface['interface']} is {interface['status']}")
Using a Dictionary for Device Settings¶
This script improves upon the first by using a dictionary to store device settings, making the code more organized and flexible.
Thanks to the starred expression **device, we can pass the dictionary directly to ConnectHandler instead of specifying each
setting in the function call. This requires the dict keys to match the parameter names expected by ConnectHandler.
Let's rename the variables to match the expected names and store them as dict keys instead.
import netmiko
from getpass import getpass
from pprint import pprint
# create an empty settings dict
device = {}
# specify the device type
device["device_type"] = "cisco_ios"
# ask the user for a device hostname/ip:
device["host"] = input("Device IP or hostname: ")
# ask the user for credentials
device["username"] = input("Enter username: ")
device["password"] = getpass("Enter password: ")
# the double starred expression allows you to use a dict instead of specifying each setting in the function call,
# this is also the way the netmiko documentation describes it (https://ktbyers.github.io/netmiko/#getting-started-1)
handler = netmiko.ConnectHandler(**device)
# query the device
result = handler.send_command("show ip interface brief", use_textfsm=True)
# print the result in a simple human-readable format
for interface in result:
print(f"{interface['interface']} is {interface['status']}")
Handling Multiple Devices¶
This script extends the previous examples to handle multiple devices, demonstrating how to iterate over a list of devices and execute commands on each.
import netmiko
from getpass import getpass
from pprint import pprint
# create a devices list to hold multiple devices
devices = []
num_devices = int(input("How many devices do you want to connect to? "))
We start by asking the user how many devices they want to connect to, and store the number in a variable. This will be used to determine how many times to run the loop.
We also create an empty list to store the device dictionaries, as we need to create a connection dict for each device.
# use the range command to create a loop that runs the number of times specified by the user
for _ in range(num_devices):
# create a settings dict per device
device = {
"device_type": "cisco_ios",
"host": input("Device IP or hostname: "),
"username": input("Enter username: "),
"password": getpass("Enter password: "),
}
# add the device to the devices list
devices.append(device)
This is a bit cool, instead of values in the dict, we simply ask the user for the values and store them directly in the dict.
Another thing to notice is the use of the _ variable in the loop. This is a common convention in Python to indicate that the
variable is not used in the loop. In this case, we don't need the loop index, so we use _ as a thow-away placeholder.
# create an empty list to store the results
interfaces = []
# iterate over the devices list and connect to each device
for device in devices:
# for each device, create a handler and execute the command
handler = netmiko.ConnectHandler(**device)
result = handler.send_command("show ip interface brief", use_textfsm=True)
interfaces.append(result)
# print the final result in a structured data format - easy to manipulate or use with Python.
for result in interfaces:
pprint(result)
Lost in transit?
Unfortunately the script does not correlate device with interface information. This means that you end up with a list of
interfaces for each device, but you don't know which device they belong to. Perhaps a dictionary could be used to store the
device and its interfaces instead? Or perhaps you should add another "hostname" key to the result dict before appending
it, to keep track of the device name? Give it a try!
Summary¶
In this lesson, we covered how to use Netmiko to automate interactions with network devices. We started with a basic connection script, improved it by using a dictionary for device settings, and finally extended it to handle multiple devices efficiently.
Key Points
- Netmiko simplifies network automation by providing easy-to-use methods for connecting to devices and executing commands.
- Using dictionaries for device settings improves code organization and flexibility.
- Iterating over a list of devices allows for scalable automation.
Try It Yourself
Extend the final script to include additional commands or handle different device types.
Congratulations on completing this lesson on network automation with Netmiko! Keep practicing to enhance your automation skills and streamline your network management tasks.