/*auto readmore*/ /*auto readmore*/ /* an hien script*/ // an hien password /*an hien ma chuong trinh cong tru */ /*Scrollbox thanh cuon*/ /***Nhung CODE***/ /* dòng xanh dòng trắng */ /* https://cdnjs.com/libraries/prism lay thu vien, can vao ten file ma goi 1. copy link vao vi du:prism-python.min.js 2. ten ngon nua la python */ /*=== New posts ===*/ /*header slider*/ /*=== bai viet lien quan===*/ /*===tabcode===*/

Network Automation #010 - Kiểm Tra MAC Address Lạ Gắng Vào Switch

 YÊU CẦU:

Kiểm tra các địa chỉ mac hiện trên switch nếu địa chỉ nào không có trong danh sách các địa chỉ mac đang đăng ký thì lưu thông tin của chúng vào file

THỰC HIỆN:

Chuẩn bị template lưu nội dung file show_mac_address.template:

Value VLAN (\d+)
Value MAC_ADDRESS ([0-9a-fA-F]{4}(?:\.[0-9a-fA-F]{4}){2})
Value INTERFACE ([^,\s]+)

Start
  ^Vlan\s+Mac Address\s+Type\s+Ports -> TYPE1

TYPE1
  ^\s*${VLAN}\s+${MAC_ADDRESS}\s+\w+\s+${INTERFACE}(?:\s|$$) -> Record


Code:

'''
- Kết nối switch kiểm tra các địa chỉ mac hiện trên switch nếu địa chỉ nào không có trong danh sách các địa chỉ mac đã đăng ký thì lưu thông tin của chúng vào file

- Câu lệnh sử dụng trong bài:
  show mac address-table

- Thư viện cần cài:
+ pip install textfsm
+ pip install pandas

'''

import pandas as pd # dùng khi ghi file csv 
from pprint import pprint # dùng để in ra đẹp, dễ nhìn hơn
import textfsm
from netmiko import ConnectHandler
import os

path = os.getcwd()	# lấy đường dẫn hiện tại

show_mac_01 = pd.read_csv('mac_store.csv', encoding = "utf-8") # đọc và xử lý chuyển dữ liệu về dạng DataFrame, và sử dụng code utf-8, lấy tất cả các cột hiện có
column_name = 'MAC_ADDRESS' # tên của cột phải tồn tại trong file mac_store.csv
mac_store = show_mac_01.values.tolist() # Trích lọc cột MAC_ADDRESS
mac_store = show_mac_01[column_name].values.tolist() 
#pprint(mac_store)

Sw_1 = { 
	"host":"192.168.100.23",
	"username":"admin",
	"password":"l2Hsv-Tw!!)",
	"device_type":"cisco_ios"
	}


print("Connecting to a host: " + Sw_1["host"] + "...\n") # Hiển thị thông báo kết nối tới
# dùng hàm ConnectHandler trong thư viện netmiko để kết nối với Sw_1 với các thông tin đã định nghĩa trong dictionnary
net_connect = ConnectHandler(**Sw_1) 
print("Connected successfully")

sh_mac_addr = "show mac address-table"
sh_mac_addr = net_connect.send_command(sh_mac_addr) # thực hiện lênh show arp với chính IP cần tìm

with open('show_mac_address.template') as template: # Mở file show_mac_address.template vừa định nghĩa
    fsm = textfsm.TextFSM(template)
    sh_mac_addr = fsm.ParseText(sh_mac_addr)
'''
for item in sh_mac_addr :
    if item[1] not in mac_store:
        print(item)
    else: print ("x")
'''
# lấy cụm thứ 2 (là địa chỉ MAC) và kiểm tra nếu chúng không có trong có trong file mac_store.csv thì đưa vào biến mac_diff
mac_diff = [item for item in sh_mac_addr if item[1] not in mac_store] 

file_name = f"MAC_diff_{Sw_1['host']}.csv"
df = pd.DataFrame(mac_diff) # convert dữ liệu sang kiểu DataFrame
df.to_csv(file_name, header = fsm.header, index = False) # thực hiện lưu các địa chỉ mac khác nhau vào file
print (f"Cac dia chi MAC chua dang ky duoc luu vao '{file_name}' tai '{path}'")

Tham khảo bài export MAC Address trong switch tại đây

Xong!

Network Automation #009 - Exporting MAC Address From Switches Cisco IOS & TextFSM Template

 YÊU CẦU:

1. Sử dụng thư viện netmiko kết nối vào switch kết hợp với TextFSM template để export toàn bộ MAC Address và lưu vào file MAC_TextFSM_template.CSV

2. Định nghĩa TextFSM template chỉ lấy các trường: Vlan (chỉ lấy các vlan là số), Mac Address, Port là lưu thành vào file MAC_TextFSM_Custom.CSV


THỰC HIỆN:

1. Sử dụng thư viện netmiko kết nối vào switch kết hợp với TextFSM template để export toàn bộ MAC Address và lưu vào file MAC_TextFSM_template.CSV

  • Chuẩn bị:
Cài đặt thư viện:
- pip install textfsm
- pip install pandas

Tham khảo cách cài đặt thư viện tại đây

  • Code:

'''
- Kết nối switch export tất cả các MAC Address và lưu thành file MAC_TextFSM_template.CSV

- Câu lệnh sử dụng trong bài:
+ show mac address-table

- Thư viện cần cài:
+ pip install textfsm
+ pip install pandas

'''
from netmiko import ConnectHandler
import textfsm
import pandas as pd
import os

path = os.getcwd()	# lấy đường dẫn hiện tại
file_name = "MAC_TextFSM_template.CSV" # tên file cần lưu

# Thông tin thiết bị cần SSH vào (định nghĩa dictionnary)
Sw_1 = { 
	"host":"192.168.100.23",
	"username":"admin",
	"password":"admin1234",
	"device_type":"cisco_ios"
	}
	
print("Dang ket noi den thiet bi co IP: " + Sw_1["host"] + "...\n") # Hiển thị thông báo kết nối tới
# dùng hàm ConnectHandler trong thư viện netmiko để kết nối với Sw_1 với các thông tin đã định nghĩa trong dictionnary
net_connect = ConnectHandler(**Sw_1) 
print("Ket noi thanh cong!")

sh_mac_addr = "show mac address-table"
sh_mac_addr = net_connect.send_command(sh_mac_addr, use_textfsm = True) # thực hiện lệnh và sử dụng thư viện TextFSM
df = pd.DataFrame(sh_mac_addr) # chuyển dữ liệu thành dạng DataFrame
df.to_csv(file_name, index = False) # thực hiện lưu file nhưng không lưu cột index
print (f"\n=====Tat ca MAC Address duoc luu vao file '{file_name}' tai '{path}'=====")


  • Kết Quả:

Dang ket noi den thiet bi co IP: 192.168.100.23...
Ket noi thanh cong!
=====Tat ca MAC Address duoc luu o file 'MAC_TextFSM_template.CSV' tai 'C:\python'=====
[Finished in 3.3s]



Nhận xét:
Khi sử dụng TextFSM để xử lý cột Mac Address đổi thành destination_address, và Ports đổi thành destination_port chúng ta khó có thể để chỉnh được theo ý.

2. Định nghĩa TextFSM template chỉ lấy các trường: Vlan (chỉ lấy các vlan là số), Mac Address, Port là lưu thành vào file MAC_TextFSM_Custom.CSV

  • Định nghĩa TextFSM Template lưu nội dung vào file show_mac_address.template
Value VLAN (\d+)
Value MAC_ADDRESS ([0-9a-fA-F]{4}(?:\.[0-9a-fA-F]{4}){2})
Value INTERFACE ([^,\s]+)

Start
  ^Vlan\s+Mac Address\s+Type\s+Ports -> TYPE1

TYPE1
  ^\s*${VLAN}\s+${MAC_ADDRESS}\s+\w+\s+${INTERFACE}(?:\s|$$) -> Record


Tham khảo TextFSM template tại đây

  • Code:

'''
- Kết nối switch export tất cả các MAC Address và lưu thành file MAC_TextFSM_Custom.CSV
- Chúng ta tự định nghĩa TextFSM template, các cột tiêu đề chúng ta cũng có thể đặt tên tùy thích và cũng có thể chọn ra/định nghĩa các vlan cần lấy ra trong file đó.

- Câu lệnh sử dụng trong bài:
+ show mac address-table

- Thư viện cần cài:
+ pip install textfsm
+ pip install pandas

'''
from netmiko import ConnectHandler
import textfsm
import pandas as pd
import os

path = os.getcwd()	# lấy đường dẫn hiện tại
file_name = "MAC_TextFSM_Custom.CSV" # tên file cần lưu
textfsm_template = 'show_mac_address.template' # tên template
# Thông tin thiết bị cần SSH vào (định nghĩa dictionnary)
Sw_1 = { 
	"host":"192.168.100.23",
	"username":"admin",
	"password":"admin1234",
	"device_type":"cisco_ios"
	}
	
print("Dang ket noi den thiet bi co IP: " + Sw_1["host"] + "...\n") # Hiển thị thông báo kết nối tới
# dùng hàm ConnectHandler trong thư viện netmiko để kết nối với Sw_1 với các thông tin đã định nghĩa trong dictionnary
net_connect = ConnectHandler(**Sw_1) 
print("Ket noi thanh cong!")

sh_mac_addr = "show mac address-table"
sh_mac_addr = net_connect.send_command(sh_mac_addr) # thực hiện lệnh show
try:
	with open(textfsm_template) as template: # Mở file show_mac_address.template vừa định nghĩa
		fsm = textfsm.TextFSM(template)
		sh_mac_addr = fsm.ParseText(sh_mac_addr)
	#print(fsm.header)
	#pprint(sh_mac_addr)
	df = pd.DataFrame(sh_mac_addr) # convert dữ liệu sang kiểu DataFrame
	df.to_csv(file_name, header = fsm.header, index = False) # Ghi dữ liệu vừa trích lọc vào file với header tương ứng và không cần điền thêm cột index	
	print (f"\n=====Tat ca MAC Address duoc luu vao file '{file_name}' tai '{path}'=====")
except:
	print (f"\n=====Kiem tra file template '{textfsm_template}' tai '{path}'=====")	


  • Kết quả:



Nhận xét:
Việc tự định nghĩa template chúng ta có thể tùy chọn các trường cần lấy và phần tiêu đề của các cột chúng ta có thể đặt tên tùy thích. Với kết quả trên chúng ta thấy trường Type và các dòng vlan không phải là số sẽ không được đưa vào file MAC_TextFSM_Custom.csv


Xong!


Học Python Qua Ví Dụ #026 - Pandas DataFrame & Đọc CSV File

 YÊU CẦU:

1. Dùng panda để đọc file device_list.csv với các yêu cầu:
- Hiển thị tất cả dữ liệu hiện có trong file
- Lọc và chỉ định các cột muốn đọc ('username', 'password','host','device_type') và chuyển đổi thành Dictionnary
- Chỉ đọc 5 dòng đầu tiên
- Không đọc các dòng thứ nhất, thứ 5 và thứ 6
- Chỉ đọc dòng đầu tiên và chuyển dòng này thành List

2. Dùng panda để đọc file show_mac_address.csv trích lọc cột 'MAC_ADDRESS' và chuyển từng dòng giá trị sang List


THỰC HIỆN

1. Dùng panda để đọc file .csv với các yêu cầu:
- Hiển thị tất cả dữ liệu hiện có trong file
- Lọc và chỉ định các cột muốn đọc ('username', 'password','host','device_type') và chuyển đổi thành Dictionnary
- Chỉ đọc 5 dòng đầu tiên
- Không đọc các dòng thứ nhất, thứ 5 và thứ 6
- Chỉ đọc dòng đầu tiên và chuyển dòng này thành List

Code:

import pandas as pd # dùng khi ghi file csv 
from pprint import pprint # dùng để in ra đẹp, dễ nhìn hơn

device_info = pd.read_csv('device_list.csv', encoding = "utf-8") # đọc và xử lý chuyển dữ liệu về dạng DataFrame, và sử dụng code utf-8, lấy tất cả các cột hiện có
pprint(device_info)

'''
orient str {‘dict’, ‘list’, ‘series’, ‘split’, ‘records’, ‘index’}

‘dict’ (default) : dict like {column -> {index -> value}}
‘list’ : dict like {column -> [values]}
‘series’ : dict like {column -> Series(values)}
‘split’ : dict like {‘index’ -> [index], ‘columns’ -> [columns], ‘data’ -> [values]}
‘records’ : list like [{column -> value}, … , {column -> value}]
‘index’ : dict like {index -> {column -> value}}
'''
column_name = ['username', 'password','host','device_type'] # chỉ định các cột cần lấy
device_info = pd.read_csv('device_list.csv', usecols = column_name, encoding = "utf-8") # đọc và xử lý chuyển dữ liệu về dạng DataFrame, và sử dụng code utf-8
device_info = device_info.to_dict(orient='records') # chuyển đổi về dict tương ứng (ví dụ: nếu file có 10 dòng thì sẽ tạo ra 9 (10 dòng bỏ đi dòng đầu tiên đã làm key) dictionary tương ứng)
pprint(device_info)

device_info = pd.read_csv('device_list.csv', nrows=5) # đọc 5 dòng đầu tiên
pprint(device_info)

device_info = pd.read_csv('device_list.csv', skiprows=[0,5,6]) # KHÔNG ĐỌC các dòng thứ nhất, thứ 5, thứ 6
pprint(device_info)

device_info = pd.read_csv('device_list.csv', nrows=0).columns.tolist() # chỉ lấy 1 dòng đầu tiên 
pprint(device_info) 


2. Dùng panda để đọc file show_mac_address.csv trích lọc cột 'MAC_ADDRESS' và chuyển từng dòng giá trị sang List

import pandas as pd # dùng khi ghi file csv 
from pprint import pprint # dùng để in ra đẹp, dễ nhìn hơn

show_mac_address = pd.read_csv('show_mac_address.csv', encoding = "utf-8") # đọc và xử lý chuyển dữ liệu về dạng DataFrame, và sử dụng code utf-8, lấy tất cả các cột hiện có
column_name = ['MAC_ADDRESS']
show_mac_address = show_mac_address[column_name].values.tolist() # Trích lọc cột MAC_ADDRESS
pprint (show_mac_address)

Tham khảo convert panda to list
Tham khảo convert panda to dict

Xong!

Học Python Qua Ví Dụ #025 - TextFSM, Pandas DataFrame & Ghi CSV File

 YÊU CẦU:

1. Trích lọc lấy các cột dữ liệu Address và Hardware Addr trong khối dữ liệu thô lấy được từ kết quả show arp

2. Trích lọc lấy cột VLAN và MAC_ADDRESS trong khối dữ liệu thô từ kết quả show mac address-table, nhưng chỉ lấy các vlan 101 -> 104 và vlan 107 -> 108. Kết quả trích lọc sẽ được lưu vào file theo định dạng CSV


THỰC HIỆN:

1. Trích lọc lấy các cột dữ liệu Address và Hardware Addr trong khối dữ liệu thô lấy được từ kết quả show arp.

Nhận xét:
Có rất nhi ều cách xử lý để lấy ra được dữ liệu theo yêu cầu. Tuy nhiên hôm nay chúng tôi giới thiệu các bạn sử dụng TextFSM kết hợp với Regular Expression

a. Định nghĩa/tạo file show_arp.template (file này được lưu thư mục chứa file Demo.py) với các dạng: IP Address và Hardward Addr (MAC)

Value MAC_ADDRESS ([a-fA-F0-9]{4}\.[a-fA-F0-9]{4}\.[a-fA-F0-9]{4}) 
Value IP_ADDRESS (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})

Start 
  ^Internet\s+${IP_ADDRESS}\s+(\d+|\-)\s+${MAC_ADDRESS}\s+ -> Record 

Giải thích:
* Hàng 1:
- MAC_ADDRESS: tên của biến
- ([a-fA-F0-9]{4}\.[a-fA-F0-9]{4}\.[a-fA-F0-9]{4}): Giá trị của địa chỉ MAC có dạng (Regular Expression sẽ thực hiện lọc ra nếu thỏa điều kiện)

Hàng 2:
- Value IP_ADDRESS: tên của biến
- (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}): Giá trị của địa chỉ IPv4 có dạng

Hàng 3:
Là dòng trắng(bắt buộc phải có dòng trắng này)

Hàng 4:
Start

Hàng 5:
2 khoảng trắng, dấu "^" chuỗi được bắt đầu bởi <nội dung định nghĩa của regular expression> -> Record: Báo hiệu kết thúc và thực hiện

-Ý nghĩa dòng RegEx "^Internet\s+${IP_ADDRESS}\s+(\d+|\-)\s+${MAC_ADDRESS}\s+":
Bắt đầu là chuỗi Internet, là khoảng trắng có thể xuất hiện 1 hoặc nhiều lầnđịnh dạng của địa chỉ IP_ADDRESS được định nghĩa (vlaue IP_ADDRESS), là khoảng trắng có thể xuất hiện 1 hoặc nhiều lần, có thể là số xuất hiện 1 hoặc nhiều lần HOẶC là ký tự "_", là khoảng trắng có thể xuất hiện 1 hoặc nhiều lần, định dạng của địa chỉ MAC_ADDRESS, là khoảng trắng xuất hiện 1 hoặc nhiều lần

Các bạn có thể tìm hiểu thêm về Regular Expression tại đây


b. Code (Demo.py):

import textfsm
from pprint import pprint # dùng để in ra đẹp, dễ nhìn hơn

show_arp = '''Building-1_Factory-1_2960_24#show arp
Protocol  Address          Age (min)  Hardware Addr   Type   Interface
Internet  192.168.100.7           6   00d7.8f0d.b83f  ARPA   Vlan1
Internet  192.168.100.11          -   08cc.a7dd.e440  ARPA   Vlan1
Internet  192.168.100.32         56   3087.d91e.1c50  ARPA   Vlan1
Internet  192.168.100.35         65   f8e7.1e34.31d0  ARPA   Vlan1
Internet  192.168.100.51         65   348f.2712.aa80  ARPA   Vlan1
Internet  192.168.100.61         65   8423.8805.8370  ARPA   Vlan1
Internet  192.168.100.62         65   c803.f53a.ccf0  ARPA   Vlan1
Internet  192.168.100.63         65   c803.f50c.4a50  ARPA   Vlan1
Internet  192.168.100.65         65   4cb1.cd3c.1af0  ARPA   Vlan1
Internet  192.168.100.66         65   4cb1.cd3b.cd30  ARPA   Vlan1
Internet  192.168.100.179        10   f28c.d229.b87b  ARPA   Vlan1
Internet  192.168.116.15         73   00d7.8f0d.b83f  ARPA   Vlan1
Internet  192.168.116.37        142   00d7.8f0d.b83f  ARPA   Vlan1
'''

with open('show_arp.template') as template: # Mở file show_arp.template vừa định nghĩa
    fsm = textfsm.TextFSM(template)
    show_arp = fsm.ParseText(show_arp)

print(fsm.header) # in ra tên các biến được định nghĩa trong file show_arp.template
pprint(show_arp) # Kết quả trích lọc/lấy được thỏa điều kiện Regular Expression

Kết quả:

['MAC_ADDRESS', 'IP_ADDRESS']
[['00d7.8f0d.b83f', '192.168.100.7'],
 ['08cc.a7dd.e440', '192.168.100.11'],
 ['3087.d91e.1c50', '192.168.100.32'],
 ['f8e7.1e34.31d0', '192.168.100.35'],
 ['348f.2712.aa80', '192.168.100.51'],
 ['8423.8805.8370', '192.168.100.61'],
 ['c803.f53a.ccf0', '192.168.100.62'],
 ['c803.f50c.4a50', '192.168.100.63'],
 ['4cb1.cd3c.1af0', '192.168.100.65'],
 ['4cb1.cd3b.cd30', '192.168.100.66'],
 ['f28c.d229.b87b', '192.168.100.179'],
 ['00d7.8f0d.b83f', '192.168.116.15'],
 ['00d7.8f0d.b83f', '192.168.116.37']]
[Finished in 0.1s]

2. Trích lọc lấy cột VLAN và MAC_ADDRESS trong khối dữ liệu thô từ kết quả show mac address-table, nhưng chỉ lấy các vlan 101 -> 104 và vlan 107 -> 108. Kết quả trích lọc sẽ được lưu vào file theo định dạng CSV

a. Tạo file teamplate show_mac_address.template:

Value VLAN ([1][0]([1-4]|[7-8]))
Value MAC_ADDRESS ([0-9a-fA-F]{4}(?:\.[0-9a-fA-F]{4}){2})

Start
  ^Vlan\s+Mac Address\s+Type\s+Ports -> TYPE1

TYPE1
  ^\s*${VLAN}\s+${MAC_ADDRESS}\s+ -> Record

Giải thích:
Kết quả trả về có thể có nhiều dạng khác nhau, tùy mỗi dạng mà chúng ta xử lý/lấy/trích lọc phù hợp với yêu cầu. Ở đây chúng ta xét nếu chúng trả về dạng: ^Vlan\s+Mac Address\s+Type\s+Ports thì nhảy đến TYPE1 để thực hiện trích lọc. (chú ý phải có dòng trắng số 3, và dòng trắng số 6)

b. Code:

import textfsm
import pandas as pd # dùng khi ghi file csv 
from pprint import pprint # dùng để in ra đẹp, dễ nhìn hơn

show_mac_address = '''Building-1_Factory-1_2960_24#show mac address-table
          Mac Address Table
-------------------------------------------

Vlan    Mac Address       Type        Ports
----    -----------       --------    -----
 All    0100.0ccc.cccc    STATIC      CPU
 All    0100.0ccc.cccd    STATIC      CPU
 All    0180.c200.0000    STATIC      CPU
 All    0180.c200.0001    STATIC      CPU
 All    0180.c200.0002    STATIC      CPU
 All    0180.c200.000d    STATIC      CPU
 All    0180.c200.000e    STATIC      CPU
 All    0180.c200.000f    STATIC      CPU
 All    0180.c200.0010    STATIC      CPU
 All    ffff.ffff.ffff    STATIC      CPU
 100    0000.7d30.b3b7    DYNAMIC     Gi0/1
 100    0000.7d30.b3c2    DYNAMIC     Fa0/23
 101    0002.6510.92d3    DYNAMIC     Fa0/23
 101    0002.6510.b148    DYNAMIC     Fa0/23
 101    0002.6510.befe    DYNAMIC     Fa0/23
 101    0002.6512.8a34    DYNAMIC     Fa0/23
 102    0002.6513.c157    DYNAMIC     Fa0/23
 102    0002.6513.fd5f    DYNAMIC     Fa0/23
 102    0002.6513.fd62    DYNAMIC     Fa0/23
 102    0002.6513.fdbd    DYNAMIC     Fa0/23
 103    0002.6513.fe26    DYNAMIC     Fa0/23
 103    0002.6514.5de5    DYNAMIC     Fa0/23
 108    0002.6516.793e    DYNAMIC     Fa0/23
 103    0016.e637.f51f    DYNAMIC     Gi0/1
 104    001d.9291.71cb    DYNAMIC     Fa0/23
 113    accb.51d5.2d3d    DYNAMIC     Gi0/1
 113    accb.51f5.4e4e    DYNAMIC     Gi0/1
 115    b4a3.82c4.374a    DYNAMIC     Gi0/1
 109    c051.7ef3.c089    DYNAMIC     Gi0/1
 109    c051.7ef3.c214    DYNAMIC     Gi0/1
 108    001e.8ccd.f971    DYNAMIC     Gi0/1
 100    0024.1db9.ab37    DYNAMIC     Gi0/1
 101    006c.bcb2.5e9d    DYNAMIC     Gi0/1
 101    d027.88bd.4b80    DYNAMIC     Gi0/1
 102    e0d5.5e17.5c5c    DYNAMIC     Gi0/1
 100    eca8.6b77.808a    DYNAMIC     Gi0/1
 101    0000.7d30.b3ba    DYNAMIC     Gi0/1
 104    001b.fc9f.af1c    DYNAMIC     Gi0/1
 101    001f.d018.26e1    DYNAMIC     Gi0/1
 101    001f.d0c1.71f8    DYNAMIC     Gi0/1
 102    bc5f.f47d.cad6    DYNAMIC     Gi0/1
 110    f003.8c8e.b2cd    DYNAMIC     Gi0/1
 110    f003.8c8e.b2d1    DYNAMIC     Gi0/1
 110    f003.8c8e.b2f3    DYNAMIC     Gi0/1
 112    00d7.8f0d.b83f    DYNAMIC     Gi0/1
 112    04b4.290a.2ad1    DYNAMIC     Gi0/1
 105    04d6.aad0.3772    DYNAMIC     Gi0/1
 112    0c2f.b065.e65c    DYNAMIC     Fa0/1
 112    1881.0e21.f5ff    DYNAMIC     Gi0/1
   1    1887.407b.444d    DYNAMIC     Gi0/1
 112    2047.da27.a341    DYNAMIC     Gi0/1
 112    20a2.e416.c350    DYNAMIC     Gi0/1
 113    e0c3.7709.5c28    DYNAMIC     Gi0/1
 113    e493.6a45.0717    DYNAMIC     Gi0/1
 113    ec51.bc56.cced    DYNAMIC     Gi0/1
   1    f0db.e2ba.c6c6    DYNAMIC     Gi0/1
 113    f8da.0c82.844f    DYNAMIC     Gi0/1
 107    f8e6.1a10.79f6    DYNAMIC     Gi0/1
 107    286f.7ff2.34e0    DYNAMIC     Gi0/1
 106    0017.c498.c864    DYNAMIC     Gi0/1
 106    0095.697f.49e8    DYNAMIC     Gi0/1
 116    00d7.8f0d.b83f    DYNAMIC     Gi0/1
   1    04d6.aa5b.9e4c    DYNAMIC     Gi0/1
   1    04d6.aade.dd3b    DYNAMIC     Gi0/1
   1    08e6.89ab.13a5    DYNAMIC     Gi0/1
'''

with open('show_mac_address.template') as template: # Mở file show_mac_address.template vừa định nghĩa
    fsm = textfsm.TextFSM(template)
    show_mac_address = fsm.ParseText(show_mac_address)

#print(fsm.header)
#pprint(show_mac_address)

df = pd.DataFrame(show_mac_address) # convert dữ liệu sang kiểu DataFrame
df.to_csv("show_mac_address.csv", header = fsm.header, index = False) # Ghi dữ liệu vừa trích lọc vào file với header tương ứng và không cần điền thêm cột index
  
Kết quả file show_mac_address.csv có dạng

Xong!


/*header slide*/