Scrapli: Fast Python Network Automation Guide - 夜莺博客

Scrapli: Fast Python Network Automation Guide

Netmiko made CLI automation accessible, but its synchronous, request-response design becomes a bottleneck when you need to poll hundreds of devices or drive interactive prompts reliably. Scrapli is a newer Python library built around a promise-based core that speaks SSH (System, Paramiko, asyncssh and even Telnet transports) and adds explicit support for interactive prompts, structured parsing and asyncio. This guide explains where Scrapli fits, how it differs from Netmiko in practice, and walks through a working multi-vendor inventory script with sane error handling.

Why another library?

Netmiko:      sync, mature, huge platform support, huge community
Scrapli:      sync + async, explicit prompt handling, typed responses,
              pluggable transports, genie/textfsm/ttp parser hooks
Nornir:       orchestration framework; can use either library underneath
NAPALM:       higher-level getters/config diff, smaller platform matrix

The practical selection rule: use Scrapli when you need speed (async fan-out), interactive prompts (confirmations, enable, password change), or strict typing; use Netmiko when you need a platform nobody else supports. Orchestration frameworks like Nornir are orthogonal — they solve inventory and concurrency, not transport. For the inventory-driven approach, see Nornir inventory and tasks and the configuration-diff workflow in NAPALM getters and config diff.

Install and first connection

pip install scrapli
# optional transports
pip install scrapli[paramiko]      # pure-python SSH
pip install scrapli[asyncssh]      # async transport
pip install scrapli[genie]         # Cisco Genie parsers
pip install scrapli[community]     # extra community platforms
from scrapli import Scrapli

device = {
    "host": "10.10.10.11",
    "auth_username": "automation",
    "auth_password": "secret",
    "auth_strict_key": False,
    "platform": "cisco_iosxe",
}

with Scrapli(**device) as conn:
    resp = conn.send_command("show version")
    print(resp.result)
    print(resp.elapsed_time)   # seconds spent on the exchange

auth_strict_key=False disables host key verification. That is convenient in a lab and unacceptable in production — pin the key or use a known_hosts file instead.

Configuration changes

with Scrapli(**device) as conn:
    conn.send_configs(["interface Loopback99", "ip address 10.99.99.99 255.255.255.255"])
    # or a whole file, with the platform's config mode handled for you
    conn.send_configs_from_file("delta.cfg")
    diff = conn.send_command("show running-config interface Loopback99")
    print(diff.result)

Interactive prompts

from scrapli import Scrapli
from scrapli.exceptions import ScrapliException
from scrapli.response import Response

with Scrapli(**device) as conn:
    conn.acquire_priv("configuration")
    conn.channel.send_inputs(
        "no username temp",
        # respond when the device asks for confirmation
        # scrapli exposes this via the community "interactive" helpers
    )

The general pattern is to watch the raw channel for a prompt substring and answer it, rather than hoping a fixed delay is long enough. This is the single biggest reliability win over naive time.sleep scripts.

Async fan-out across an inventory

import asyncio, csv
from scrapli import AsyncScrapli

async def poll(row):
    dev = {
        "host": row["host"], "auth_username": row["user"],
        "auth_password": row["password"], "auth_strict_key": False,
        "platform": row["platform"], "timeout_ops": 20,
    }
    try:
        async with AsyncScrapli(**dev) as conn:
            r = await conn.send_command("show version")
            return row["host"], "ok", len(r.result)
    except Exception as e:
        return row["host"], "fail", str(e)[:80]

async def main():
    rows = list(csv.DictReader(open("inventory.csv")))
    results = await asyncio.gather(*(poll(r) for r in rows))
    for host, status, info in sorted(results):
        print(f"{host:16s} {status:5s} {info}")

asyncio.run(main())

Concurrency limits matter: 200 simultaneous SSH sessions from one server will exhaust file descriptors and trigger management-plane policing on some platforms. Cap it with a semaphore (start at 20-30) and raise the OS fd limit if needed.

Error handling that survives production

Timeouts        -> retry with backoff, log the host and command
Authentication  -> fail fast; do not loop on a rotated password
Command invalid -> Scrapli raises; catch per-host so one device cannot
                   abort the whole run
Output changes  -> never regex the banner; parse structured data or textfsm
Idempotency     -> compare rendered config to running config before pushing

Structure the run so a single failure is recorded and the batch continues — the standard trap is a bare asyncio.gather that raises on the first exception and leaves the remaining devices unreported.

FAQ

Q: Is Scrapli faster than Netmiko? Not per command — the transport dominates. It is faster in aggregate because async lets you overlap hundreds of sessions, and because prompt handling avoids fixed sleeps.
Q: Can Scrapli parse output? Yes, it integrates Genie, TTP and textfsm parsers and returns structured data. NTC templates are covered in TTC template parsing.
Q: What about NETCONF/gNMI? Scrapli focuses on CLI. For model-driven transports use ncclient or gNMI clients instead — see NETCONF/RESTCONF/gNMI comparison.

原文链接:https://github.com/carlmontanari/scrapli