1

I have written a short python script to search for urls with a http status code in a logfile. The script works as intended and counts how often an url is requested in combination with a certain http status code. The dictionary with the results is unsorted. Thats why i sorted the data afterwards using the values in the dictionary. This part of the script works as intended and i get a sorted list with the urls and the counter, The list looks like:

([('http://example1.com"', 1), ('http://example2.com"', 5), ('http://example3.com"', 10)])

I just want to make it better readable and print the list in rows.

http://example1.com      1  
http://example2.com      5  
http://example3.com      10  

I started with python only two weeks ago and i cant find a solution. I tried several solutions i found here on stackoverflow but nothing works. My current solution prints all urls in seperate rows but does not show the count. I cant use comma as a seperator because i got some url with commas in my logfile. Im sorry for my bad english and the stupid question. Thank you in advance.

from operator import itemgetter
from collections import OrderedDict

d=dict()

with open("access.log", "r") as f:
    for line in f:
        line_split = line.split()
        list = line_split[5], line_split[8]
        url=line_split[8]
        string='407'
        if string in line_split[5]:
            if url in d:
                d[url]+=1
            else:
                d[url]=1


sorted_d = OrderedDict(sorted(d.items(), key=itemgetter(1)))

for element in sorted_d:
    parts=element.split(') ')
    print(parts)
Alderven
  • 7,569
  • 5
  • 26
  • 38
NidintuBel
  • 11
  • 3

3 Answers3

2
for url, count in sorted_d.items():
    print(f'{url} {count}')

Replace your last for loop with the above.

To explain: we unpack the url, count pairs in sorted_d in the for loop, and then use the an f-string to print the url and count separated by a space.

shayaan
  • 1,482
  • 1
  • 15
  • 32
  • thank you. works perfect although i still struggle to fully understand why. :) – NidintuBel Feb 27 '19 at 09:11
  • Great to hear that it worked for you :) I used tuple unpacking in the for loop, and f-strings. The more you read about and use them, the more natural they will become. Here's a good question on [tuple unpacking in a for loop](https://stackoverflow.com/questions/10867882/tuple-unpacking-in-for-loops), and one on [f-strings](https://stackoverflow.com/questions/35745050/string-with-f-prefix-in-python-3-6). – shayaan Feb 27 '19 at 09:16
1

First if you're already importing from the collections library, why not import a Counter?

from collections import Counter

d=Counter()

with open("access.log", "r") as f:
    for line in f:
        line_split = line.split()
        list = line_split[5], line_split[8]
        url=line_split[8]
        string='407'
        if string in line_split[5]:
            d[url] += 1

for key, value in d.most_common():  # or reversed(d.most_common())
    print(f'{key} {value}')
shayaan
  • 1,482
  • 1
  • 15
  • 32
  • Interesting point. I'm having trouble thinking of how that could manifest, considering how `Counter` is a subclass of `dict`. Can you give an example? And thanks for the Python3 edit! – Jonathan Mosenkis Feb 27 '19 at 09:04
  • Whoops, you're right! I wasn't aware that counter was a subclass of dict, I'll delete my earlier comment to avoid confusion to future readers. – shayaan Feb 27 '19 at 09:08
0

There are many good tutorials on how to format strings in Python such as this

Here an example code how to print a dictionary. I set the width of the columns with the variables c1 and c2.

c1 = 34; c2 = 10 
printstr = '\n|%s|%s|' % ('-'*c1, '-'*c2)
for key in sorted(d.keys()):
    val_str = str(d[key])
    printstr += '\n|%s|%s|' % (str(key).ljust(c1), val_str.rjust(c2))
printstr += '\n|%s|%s|\n\n' % ('-' * c1, '-' * c2)
print(printstr)

The string function ljust() creates a string of the length passed as an argument where the content of the string is left justified.

Edgar H
  • 1,376
  • 2
  • 17
  • 31
  • While the `string % format` syntax is still supported, as of Python 3.7, f-strings are a far more readable. Even `str.format` is preferred. – shayaan Feb 27 '19 at 08:57
  • Sure but it depends somewhat on your use-case. If you need backward compatibility you are down to `%` format or `str.format`. – Edgar H Feb 27 '19 at 10:04