I am trying to write a code that takes in a csv, runs a ping on the value in the first column and then outputs the status to the second column. Everything in the code runs fine until it tries to write out to the csv at which time I get this error
line 35, in writer.writerows(columns)
TypeError: 'str' does not support the buffer interface
import os
import csv
from collections import defaultdict
i = 0
#read file
columns = defaultdict(list)
with open('hosts.csv') as f:
reader = csv.DictReader(f)
for row in reader:
for (k,v) in row.items():
columns[k].append(v)
f.close()
print('[DEBUG]', columns['host'])
print('[DEBUG] 1st host is', (columns['host'])[0])
print('[DEBUG]', columns['status'])
#ping hosts
hostname = (columns['host'])[i]
response = os.system("ping -n 1 " + hostname)
print ("[DEBUG]", response)
if response == 0:
print (hostname, 'is up')
(columns['status'])[i] = 'Up'
i = i+1
else:
print (hostname, 'is down')
(columns['status'])[i] = 'Down'
i = i+1
#write results
with open("hosts.csv", "wb") as f:
writer =csv.writer(f)
print("[DEBUG] just before write rows")
writer.writerows(columns)
print("[DEBUG] after write rows")
f.close()
The csv contains the following
host,status,name
8.8.8.8,down,google.com
and should return
host,status,name
8.8.8.8,Up,google.com
I am using Python 3.4
You are reading the CSV in one format and writing in another one, where columns is defaultdict with list of values inside a dict.
Here's a better way to solve this problem, maintaing the original file structure:
import os
import csv
with open('hosts.csv') as f:
reader = csv.DictReader(f)
rows = list(reader)
hosts = [row['host'] for row in rows]
statuses = [row['status'] for row in rows]
print('[DEBUG]', hosts)
print('[DEBUG] 1st host is', hosts[0])
print('[DEBUG]', statuses)
for row in rows:
#ping hosts
hostname = row['host']
response = os.system("ping -n 1 " + hostname)
print ("[DEBUG]", response)
if response == 0:
print (hostname, 'is up')
row['status'] = 'Up'
else:
print (hostname, 'is down')
row['status'] = 'Down'
#write results
with open("hosts.csv", "wb") as f:
writer = csv.DictWriter(f, reader.fieldnames)
# to maintain the same structure from the original file, rewrite header in original position
writer.writeheader()
print("[DEBUG] just before write rows")
writer.writerows(rows)
print("[DEBUG] after write rows")
Before instantiate csv.DictWriter, you can change the field names that you want to be in the new file:
newfieldnames = csvreader.fieldnames
lastfield = newfieldnames.pop() # remove last field
if 'field_name' in newfieldnames:
newfieldnames.remove('field_name') # remove by field name
writer = csv.DictWriter(f, newfieldnames)
Related
I am trying to import a csv file that has hostnames and do ping test for such ~100 devices.
CSV1:
Hostname
abc
bcd
efg
.
.
and so on
I want to do ping test and write the ping status whether it is UP or Down in the output csv file along with the corresponding hostnames.
Something like this:
Output:
Hostname Ping Status
abc UP
bcd DOWN
efg DOWN
. .
. .
and so on
I have tried my best to lookup on the internet and SO, but found no luck. I am very new to python and I am still in the learning stages. Please help!!
import os
import csv
with open('CSV1.csv', 'r') as f:
reader = csv.DictReader(f)
rows = list(reader)
hosts = [row['CI_Name'] for row in rows]
statuses = [row['Status'] for row in rows]
for row in rows:
#ping hosts
hostname = row['CI_Name']
response = os.system("ping -n 1 " + hostname)
print ("[DEBUG]", response)
if response == 0:
print (hostname, 'is up')
row['Status'] = 'Up'
else:
print (hostname, 'is down')
row['Status'] = 'Down'
#write results
with open("Output Final.csv", "w") as w:
writer = csv.writer(w)
I am getting the output in Python console, and it is displaying the same details of ping that we get when done from 'CMD'. but my output csv file goes untouched.
This is much finished version of the code; although i am still working on it to print the ip address of those devices and get the headers correct when writing it to the csv file.
import socket
import os
import csv
name = {}
CI = {}
hostname = {}
status = {}
with open('Output1.csv', 'r', newline='') as csvinput:
reader = csv.DictReader(csvinput)
for rows in reader:
CI = rows['CI_Name']
name = socket.getfqdn(CI)
data = name
hostname = rows['CI_Name']
response = os.system('ping -n 2 ' + hostname)
if response == 0:
status = 'Up'
else:
status = 'Down'
with open('Output Final.csv', 'a', newline='') as csvoutput:
output = csv.writer(csvoutput)
output.writerow([hostname] + [data] + [status])
#write results
with open("Output Final.csv", "w", newline='') as w:
writer = csv.writer(w)
writer.writerow(["CI_NAME","Status"])
for r in rows:
writer.writerow((r['CI_Name'], r['Status']))
Finally fixed the whole code:
Note: I am integrating nslookup, ping test and ip address in this script to write FQDN, PING TEST and IP ADDRESS by passing in a list of devices that I have in my csv file
import socket
import os
import csv
import subprocess
name = {}
CI = {}
hostname = {}
status = {}
with open('Output1.csv', 'r', newline='') as csvinput:
reader = csv.DictReader(csvinput)
for rows in reader:
CI = rows['CI_Name']
try:
ip = socket.gethostbyname(CI)
except socket.error:
pass
name = socket.getfqdn(CI)
data = name
hostname = rows['CI_Name']
response = subprocess.Popen(['ping.exe',hostname], stdout = subprocess.PIPE).communicate()[0]
response = response.decode()
print(response)
if 'bytes=32' in response:
status = 'Up'
elif 'destination host unreachable' in response:
status = 'Unreachable'
else:
status = 'Down'
if status == 'Down':
ip = 'Not Found'
with open('Output Final.csv', 'a', newline='') as csvoutput:
output = csv.writer(csvoutput)
output.writerow([hostname] + [data] + [status] + [ip])
If list stored in csv file below the example, does each row stored in the array?
import csv
import os
DIR = "C:/Users/Administrator/Desktop/key_list.csv"
def Customer_List(csv):
customer = open(DIR)
for line in customer:
row = []
(row['MEM_ID'],
row['MEM_SQ'],
row['X_AUTH_USER'],
row['X_AUTH_KEY'],
row['X_STORAGE_URL'])=line.split(",")
if csv == row['MEM_ID']:
customer.close()
return(row)
else:
print ("Not search for ID")
return([])
query = input("Input the your email id: ")
result = Customer_List(query)
This example alert errors code.. Why ..?
Additionally update the this code & error
Input the your email id: sdfsdf#naver.com
Traceback (most recent call last):
File "C:\Users\Administrator\Desktop\PyDev\Pydev\Day4\uCloudStorage.py", line 32, in <module>
result = Customer_List(query)
File "C:\Users\Administrator\Desktop\PyDev\Pydev\Day4\uCloudStorage.py", line 20, in Customer_List
row['X_STORAGE_URL'])=line.split(",")
ValueError: too many values to unpack (expected 5)
To show what's in the CSV, here's some simple code and the result:
DIR = "C:/Users/Administrator/Desktop/key_list.csv"
def Customer_List():
customer = open(DIR)
for line in customer:
print (line)
result:
MEM_ID, MEM_SQ, X_AUTH_USER, X_AUTH_KEY, X_STORAGE_URL
kimdm98#gmail.com, M100009, M100009:M100009, wreQew3u, AUTH_xxxxxx-xxxxx
minsejisuk#paran.com, M100022, M100022:M100022, PEm6tREx, AUTH_xxxxx-xxxxx
sdfsdf#naver.com, M100034, M100034:M100034, 3tAzEf3u, AUTH_xxxx-xxxxx
=============================================================================
I edited this script..... Is it best practice ?
DIR = "C:/Users/Administrator/Desktop/key_list.csv"
DATA = csv.reader(open(DIR,"r"))
ID = input("Input the Customer EMAIL ID: ")
def cList(value):
for row in DATA:
MEM_ID = row[0]
MEM_SQ = row[1]
X_AUTH_USER = row[2]
X_AUTH_KEY = row[3]
X_STORAGE_URL = row[4]
ACCESSKEY = row[5]
ACCESSKEYID1 = row[6]
SECRETKEY1 = row[7]
ACCESSKEYID2 = row[8]
SECRETKEY2 = row[9]
if MEM_ID == value:
print(".EMAIL ID :" + MEM_ID)
print(".MID :" + MEM_SQ)
print(".PASSWORD :" + X_AUTH_KEY)
print(".AUTH_ACCOUNT :" + X_STORAGE_URL)
print(".API KEY :" + ACCESSKEY)
cList(ID)
print ("============================")
print ("1. Upload / Download Error")
print ("2. Permission Error")
print ("3. 4xx Error")
print ("4. etc... Error")
print ("============================")
Result
Input the Customer EMAIL ID: kiyoung.jung#kt.com
.EMAIL ID :kiyoung.jung#kt.com
.MID :xxxxxx
.PASSWORD :xxxxxx
.AUTH_ACCOUNT :xxxxxx-d50a-xxxx-xxxbc05-6267d5ff6712
.API KEY :xxxxxxxx
============================
1. Upload / Download Error
2. Permission Error
3. 4xx Error
4. etc... Error
============================
If your input data is formatted like what you added at the very end of your question, your could get your approach to work like this:
import csv
DIR = "C:/Users/Administrator/Desktop/key_list.csv"
def Customer_List(email_id):
with open(DIR, newline='') as f: # open assuming Python 3.x
csvreader = csv.reader(f, skipinitialspace=True)
for fields in csvreader:
row = {} # initialize to an empty dictionary
(row['MEM_ID'],
row['MEM_SQ'],
row['X_AUTH_USER'],
row['X_AUTH_KEY'],
row['X_STORAGE_URL']) = fields
if row['MEM_ID'] == email_id:
return [row['MEM_ID'],
row['MEM_SQ'],
row['X_AUTH_USER'],
row['X_AUTH_KEY'],
row['X_STORAGE_URL']]
else:
print("ID not found")
return []
match = Customer_List('minsejisuk#paran.com')
if match:
print('found! {}'.format(match))
However you could simplify things slightly by using a csv.DictReader to read the file which will automatically read the header line to obtain the fieldnames and then return a dictionary using them as keys for each row read:
def Customer_List(email_id):
with open(DIR, newline='') as f: # open assuming Python 3.x
csvreader = csv.DictReader(f, skipinitialspace=True)
for row in csvreader:
if row['MEM_ID'] == email_id:
return [row['MEM_ID'],
row['MEM_SQ'],
row['X_AUTH_USER'],
row['X_AUTH_KEY'],
row['X_STORAGE_URL']]
else:
print("ID not found")
return []
I have an application that works. But in the interest of attempting to understand functions and python better. I am trying to split it out into various functions.
I"m stuck on the file_IO function. I'm sure the reason it does not work is because the main part of the application does not understand reader or writer. To better explain. Here is a full copy of the application.
Also I'm curious about using csv.DictReader and csv.DictWriter. Do either provide any advantages/disadvantages to the current code?
I suppose another way of doing this is via classes which honestly I would like to know how to do it that way as well.
#!/usr/bin/python
""" Description This script will take a csv file and parse it looking for specific criteria.
A new file is then created based of the original file name containing only the desired parsed criteria.
"""
import csv
import re
import sys
searched = ['aircheck', 'linkrunner at', 'onetouch at']
def find_group(row):
"""Return the group index of a row
0 if the row contains searched[0]
1 if the row contains searched[1]
etc
-1 if not found
"""
for col in row:
col = col.lower()
for j, s in enumerate(searched):
if s in col:
return j
return -1
#Prompt for File Name
def file_IO():
print "Please Enter a File Name, (Without .csv extension): ",
base_Name = raw_input()
print "You entered: ",base_Name
in_Name = base_Name + ".csv"
out_Name = base_Name + ".parsed.csv"
print "Input File: ", in_Name
print "OutPut Files: ", out_Name
#Opens Input file for read and output file to write.
in_File = open(in_Name, "rU")
reader = csv.reader(in_File)
out_File = open(out_Name, "wb")
writer = csv.writer(out_File, delimiter=',', quotechar='"', quoting=csv.QUOTE_ALL)
return (reader, writer)
file_IO()
# Read header
header = reader.next()
stored = []
writer.writerow([header[0], header[3]])
for i, row in enumerate(reader):
g = find_group(row)
if g >= 0:
stored.append((g, i, row))
stored.sort()
for g, i, row in stored:
writer.writerow([row[0], row[3]])
# Closing Input and Output files.
in_File.close()
out_File.close()
If I were you, I'd only separate find_group.
import csv
def find_group(row):
GROUPS = ['aircheck', 'linkrunner at', 'onetouch at']
for idx, group in enumerate(GROUPS):
if group in map(str.lower, row):
return idx
return -1
def get_filenames():
# this might be the only other thing you'd want to factor
# into a function, and frankly I don't really like getting
# user input this way anyway....
basename = raw_input("Enter a base filename (no extension): ")
infilename = basename + ".csv"
outfilename = basename + ".parsed.csv"
return infilename, outfilename
# notice that I don't open the files yet -- let main handle that
infilename, outfilename = get_filenames()
with open(infilename, 'rU') as inf, open(outfilename, 'wb') as outf:
reader = csv.reader(inf)
writer = csv.writer(outf, delimiter=',',
quotechar='"', quoting=csv.QUOTE_ALL)
header = next(reader)
writer.writerow([[header[0], header[3]])
stored = sorted([(find_group(row),idx,row) for idx,row in
enumerate(reader)) if find_group(row) >= 0])
for _, _, row in stored:
writer.writerow([row[0], row[3]])
I am trying to find a way to send the output of crop_rows called at the very bottom into the input of delete_Apps called directly after, but I'm unsure as to what to feed it. Also, do I need to remove:
file_obj.close()
from the crop_rows function so that my script continues to run through both functions?
import os, csv, sys, Tkinter, tkFileDialog as fd
# stop tinker shell from opening as only needed for file dialog
root = Tkinter.Tk()
root.withdraw()
#crop_rows deletes the extra info automatically generated in the Waders report
def crop_rows(in_path):
# read file into memory
file_obj = open(in_path, 'rb')
reader = csv.reader(file_obj, delimiter='\t')
data = []
for row in reader:
if not row or not any(row):
break #stop at empty row
else:
data.append(row)
file_obj.close()
print 'Found', len(data), 'rows of data without empty lines.'
conf = raw_input('delete remaining lines? (Y|N): ').upper()[0]
if conf == 'Y':
# write data to file
file_obj = open(in_path, 'wb')
writer = csv.writer(file_obj)
writer.writerows(data)
file_obj.close
#delete_Apps deletes and leads that are currently Applicants in gHire as their Status
def delete_Apps(in_path):
# read file into memory
file_obj = open(in_path, 'rb')
reader = csv.reader(file_obj, delimiter='\t')
data = []
for row in reader:
if 'Applicant' not in row:
data.append(row)
file_obj.close()
print 'Found', len(data), 'Leads with Applicant in gHire as Status.'
conf = raw_input('delete these leads? (Y|N): ').upper()[0]
if conf == 'Y':
# write data to file
file_obj = open(in_path, 'wb')
writer = csv.writer(file_obj)
writer.writerows(data)
file_obj.close
def main():
in_path = None
prog_name = sys.argv[0]
# check if in_path are inlcuded as cmd line args...
if len(sys.argv) > 1:
in_path = sys.argv[1]
if not os.path.exists(in_path):
print 'Usage:', prog_name, '[file_path>]'
print 'cannot find the file provided for file_path:\n', in_path
sys.exit("Error - invalid excel_file_path arg")
else:
try:
# set current working directory to user's my documents folder
os.chdir(os.path.join(os.getenv('userprofile'),'documents'))
except:
pass
# ask user for path to file...
while not in_path:
print "Please select the file to read data from ..."
try:
in_path = fd.askopenfilename()
except:
print 'Error selecting file.'
if not in_path:
cont = raw_input('Do you want to continue? (Y|N): ').upper()[0]
if cont == 'N':
sys.exit("Error - unable to select input file")
crop_rows(in_path)
delete_Apps(in_path)
if __name__ == '__main__':
main()
Change crop_rows into a generator function (see https://wiki.python.org/moin/Generators) and use it in delete_Apps.
Read the .csv file separately
Change crop_rows so that it takes rows as input and returns the new data
Then change delete_Apps to take rows input and to return the modified data
Finally write the .csv file
You can then simply nest calls to the functions, like this:
def read_input_file(in_path):
# use with not to worry about closing the file
with open(in_path, 'rb') as file_obj:
reader = csv.reader(file_obj, delimiter='\t')
return list(reader)
def crop_rows(input_rows):
data = []
for row in input_rows:
if not row or not any(row):
break #stop at empty row
else:
data.append(row)
print 'Found', len(data), 'rows of data without empty lines.'
conf = raw_input('delete remaining lines? (Y|N): ').upper()[0]
if conf == 'Y':
return data
else:
# return unmodified data
return input_rows
def delete_Apps(input_rows):
data = []
for row in input_rows:
if 'Applicant' not in row:
data.append(row)
print 'Found', len(data), 'Leads with Applicant in gHire as Status.'
conf = raw_input('delete these leads? (Y|N): ').upper()[0]
if conf == 'Y':
return data
else:
return input_rows
def write_output_file(data, out_path):
wirg open(out_path, 'wb') as file_obj:
writer = csv.writer(file_obj)
writer.writerows(data)
file_obj.close()
The final call:
file_path='/tmp/whatever.csv'
write_output_file(delete_Apps(crop_rows(read_input_file(file_path)), file_path)
Python 2.4
For my example I have a 2 column csv file
Eg:
HOST, FILE
server1, /path/to/file1
server2, /path/to/file2
server3, /path/to/file3
I would like to get the file size of the object at PATH for each row in the csv FILE, then add that value to the csv FILE on a new column.
Making it:
HOST, PATH, FILESIZE
server1, /path/to/file1, 6546542
server2, /path/to/file2, 46546343
server3, /path/to/file3, 87523
Ive tried a couple methods but havnt had much success.
The code below executes fileSizeCmd (du -b) on the PATH and outputs the filezie correctly, but I havnt figured out how to use the data to add to the csv FILE
import datetime
import csv
import os, time
from subprocess import Popen, PIPE, STDOUT
now = datetime.datetime.now()
fileSizeCmd = "du -b"
SP = " "
# Try to get disk size and append to another row after entry above
#st = os.stat(row[3])
#except IOError:
#print "failed to get information about", file
#else:
#print "file size:", st[ST_SIZE]
#print "file modified:", time.asctime(time.localtime(st[ST_MTIME]))
incsv = open('my_list.csv', 'rb')
try:
reader = csv.reader(incsv)
outcsv = open('results/results_' + now.strftime("%m-%d-%Y") + '.csv', 'wb')
try:
writer = csv.writer(outcsv)
for row in reader:
p = Popen(fileSizeCmd + SP + row[1], shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE)
stdout, empty = p.communicate()
print 'Command: %s\nOutput: %s\n' % (fileSizeCmd + SP + row[1], stdout)
# Results in bytes example
#
# Output:
# 8589935104 /path/to/file
#
# Write 8589935104 to new column of csv FILE
finally:
outcsv.close()
finally:
incsv.close()
Sketch w/o error handling:
#!/usr/bin/env python
import csv
import os
filename = "sample.csv"
# localhost, 01.html.bak
# localhost, 01.htmlbak
# ...
def filesize(filename):
# no need to shell out for filesize
return os.stat(filename).st_size
with open(filename, 'rb') as handle:
reader = csv.reader(handle)
# result is written to sample.csv.updated.csv
writer = csv.writer(open('%s.updated.csv' % filename, 'w'))
for row in reader:
# need to strip filename, just in case
writer.writerow(row + [ filesize(row[1].strip()) ])
# result
# localhost, 01.html.bak,10021
# localhost, 01.htmlbak,218982
# ...
You can
1) read the cvs content into a list of tuple of (server, filename)
2) collect the file size for each element of this list
3) package the result into another tuple (server, filename, filesize) into another list ('result')
4) write out the result to new file
First, getting file size is a lot easier than using subprocess (see os.stat):
>>> os.stat('/tmp/file').st_size
100
Second, you're on the right track with your writer object writing to a different file, but you just need to add a column to the row lists you're getting back from the reader and then feed them to writerow on the writer (see here). Something like this:
>>> writerfp = open('out.csv', 'w')
>>> writer = csv.writer(writerfp)
>>> for row in csv.reader(open('in.csv', 'r')):
... row.append('column')
... writer.writerow(row)
...
>>> writerfp.close()