1

I added a line in the python code “speedtest.py” that I found at pimylifeup.com. I hoped it would allow me to track the internet provider and IP address along with all the other speed information his code provides. But when I execute it, the code only grabs the next word after the find all call. I would also like it to return the IP address that appears after the provider. I have attached the code below. Can you help me modify it to return what I am looking for.

Here is an example what is returned by speedtest-cli

$ speedtest-cli
Retrieving speedtest.net configuration...
Testing from Biglobe (111.111.111.111)...
Retrieving speedtest.net server list...
Selecting best server based on ping...
Hosted by GLBB Japan (Naha) [51.24 km]: 118.566 ms
Testing download speed................................................................................
Download: 4.00 Mbit/s
Testing upload speed......................................................................................................
Upload: 13.19 Mbit/s
$

And this is an example of what it is being returned by speediest.py to my .csv file

Date,Time,Ping,Download (Mbit/s),Upload(Mbit/s),myip

05/30/20,12:47,76.391,12.28,19.43,Biglobe

This is what I want it to return.

Date,Time,Ping,Download (Mbit/s),Upload (Mbit/s),myip

05/30/20,12:31,75.158,14.29,19.54,Biglobe 111.111.111.111

Or may be,

05/30/20,12:31,75.158,14.29,19.54,Biglobe,111.111.111.111

Here is the code that I am using. And thank you for any help you can provide.

import os
import re
import subprocess
import time

response = subprocess.Popen(‘/usr/local/bin/speedtest-cli’, shell=True, stdout=subprocess.PIPE).stdout.read().decode(‘utf-8’)

ping = re.findall(‘km]:\s(.*?)\s’, response, re.MULTILINE)
download = re.findall(‘Download:\s(.*?)\s’, response, re.MULTILINE)
upload = re.findall(‘Upload:\s(.*?)\s’, response, re.MULTILINE)
myip = re.findall(‘from\s(.*?)\s’, response, re.MULTILINE)

ping = ping[0].replace(‘,’, ‘.’)
download = download[0].replace(‘,’, ‘.’)
upload = upload[0].replace(‘,’, ‘.’)
myip = myip[0]

try:
f = open(‘/home/pi/speedtest/speedtestz.csv’, ‘a+’)
if os.stat(‘/home/pi/speedtest/speedtestz.csv’).st_size == 0:
f.write(‘Date,Time,Ping,Download (Mbit/s),Upload (Mbit/s),myip\r\n’)
except:
pass

f.write(‘{},{},{},{},{},{}\r\n’.format(time.strftime(‘%m/%d/%y’), time.strftime(‘%H:%M’), ping, download, upload, myip))
ccdanieldb
  • 11
  • 1
  • 2

2 Answers2

1

Let me know if this works for you, it should do everything you're looking for

#!/usr/local/env python
import os
import csv
import time
import subprocess
from decimal import *

file_path = '/home/pi/speedtest/speedtestz.csv'

def format_speed(bits_string):
  """ changes string bit/s to megabits/s and rounds to two decimal places """
  return (Decimal(bits_string) / 1000000).quantize(Decimal('.01'), rounding=ROUND_UP)

def write_csv(row):
  """ writes a header row if one does not exist and test result row """
  # straight from csv man page
  # see: https://docs.python.org/3/library/csv.html
  with open(file_path, 'a+', newline='') as csvfile:
    writer = csv.writer(csvfile, delimiter=',', quotechar='"')

    if os.stat(file_path).st_size == 0:
      writer.writerow(['Date','Time','Ping','Download (Mbit/s)','Upload (Mbit/s)','myip'])

    writer.writerow(row)


response = subprocess.run(['/usr/local/bin/speedtest-cli', '--csv'], capture_output=True, encoding='utf-8')

# if speedtest-cli exited with no errors / ran successfully
if response.returncode == 0:

  # from the csv man page
  # "And while the module doesn’t directly support parsing strings, it can easily be done"
  # this will remove quotes and spaces vs doing a string split on ','
  # csv.reader returns an iterator, so we turn that into a list
  cols = list(csv.reader([response.stdout]))[0]

  # turns 13.45 ping to 13
  ping = Decimal(cols[5]).quantize(Decimal('1.'))

  # speedtest-cli --csv returns speed in bits/s, convert to bytes
  download = format_speed(cols[6])
  upload = format_speed(cols[7])

  ip = cols[9]

  date = time.strftime('%m/%d/%y')
  time = time.strftime('%H:%M')

  write_csv([date,time,ping,download,upload,ip])

else:
  print('speedtest-cli returned error: %s' % response.stderr)

chason
  • 101
  • 5
0
$/usr/local/bin/speedtest-cli --csv-header > speedtestz.csv
$/usr/local/bin/speedtest-cli --csv >> speedtestz.csv

output:

Server ID,Sponsor,Server Name,Timestamp,Distance,Ping,Download,Upload,Share,IP Address

Does that not get you what you're looking for? Run the first command once to create the csv with header row. Then subsequent runs are done with the append '>>` operator, and that'll add a test result row each time you run it

Doing all of those regexs will bite you if they or a library that they depend on decides to change their debugging output format

Plenty of ways to do it though. Hope this helps

chason
  • 101
  • 5
  • chason, thank you for the reply. I am not sure how to implement your solution. Do I need to change any of the code in my speedtest.py file. In the end, all I really wanted was to change the {myip = re.findall(‘from\s(.*?)\s’, response, re.MULTILINE)} line in speedtest.py to grab all that appears after {Testing from} in the out put of speedtest-cli. – ccdanieldb Jun 04 '20 at 11:50
  • Sorry I missed this. I edited my answer, I fudged the command, I can see how that's confusing. What I'm trying to say is you can ditch Python entirely and just run those two commands in the shell to do exactly what your script is doing.. albeit with a couple extra columns. speedtest-cli is already set up to do csv exporting. I'll submit a Python answer using the --csv flag – chason Jun 15 '20 at 18:17