CLI scraping is fragile. Model-driven APIs — NETCONF and RESTCONF, described by YANG models — treat device config as structured data you read and write like an API.
Why: screen-scraping the CLI is fragile because it was designed for humans — NETCONF and RESTCONF expose config and state as structured data (XML/JSON) defined by YANG models, so you interact with a device like a real API. When: prefer these on modern gear; fall back to Netmiko on older devices without API support. Where: YANG is the schema (what fields exist and their types); NETCONF/RESTCONF are the transports that carry the data.
CLI (Netmiko) send text commands, scrape text back (fragile)
NETCONF XML over SSH, transactional (robust)
RESTCONF JSON over HTTPS, REST-style (familiar)
YANG the MODEL: defines the data structure and types
Model-driven = config is DATA with a schema, not text to parse.Why: RESTCONF exposes device config over HTTPS as JSON, so you read and change it with ordinary REST calls — GET to read, PATCH/PUT to change — using tools you already know. When: use RESTCONF when you want familiar REST semantics and JSON. Where: the URL path mirrors the YANG data hierarchy.
import requests
requests.packages.urllib3.disable_warnings()
base = "https://192.168.1.1/restconf/data"
headers = {"Accept": "application/yang-data+json"}
auth = ("admin", "...")
# Read interface config as JSON (structured, no parsing):
r = requests.get(f"{base}/ietf-interfaces:interfaces",
headers=headers, auth=auth, verify=False)
print(r.json())Why: NETCONF is the transactional, XML-based standard — it supports candidate configs, commit, and rollback natively, which is ideal for reliable automated changes. When: use NETCONF (via the ncclient library) on devices that support it for safe, all-or-nothing changes. Where: filters let you fetch just the subtree you care about instead of the whole config.
# pip install ncclient
from ncclient import manager
with manager.connect(host="192.168.1.1", port=830, username="admin",
password="...", hostkey_verify=False) as m:
# Fetch only the interfaces subtree, as structured XML:
filt = "<interfaces xmlns='urn:ietf:params:xml:ns:yang:ietf-interfaces'/>"
reply = m.get_config(source="running", filter=("subtree", filt))
print(reply)