【问题标题】:How to get a count of every item in a list?如何获取列表中每个项目的计数?
【发布时间】:2014-09-11 15:18:55
【问题描述】:

上下文:

我有一个程序可以解析日志文件以在我的机器上进行连接尝试。 它提取了一个 IP 地址列表,然后我想在这个信息列表上运行其他功能,特别是其中一个功能没有按预期工作。它应该计算每个国家/地区的连接尝试次数。

代码 - ip_tools.py

#!/usr/bin/python

import requests
import json
import socket

#function to get the ip address of the host user
def get_host_ipad():
    host_ip_request = requests.get("http://ipinfo.io/ip")
    return host_ip_request.text

#function to get gelocation info of a remote host
def get_rhost_geo(ipad):
    full_geo_info = {}
    rhost_ip_request = requests.get("http://ipinfo.io/%s/json" % (ipad))
    json_response = json.loads(rhost_ip_request.text)
    for value in json_response:
        full_geo_info.update({str(value) : str(json_response[value])})
    return full_geo_info

#function to return country of rhost
def get_geo_country(ipad):
    geo_info = get_rhost_geo(ipad)
    geo_country = geo_info["country"]
    return geo_country

#function to perform reverse dns lookup
def get_rhost_url(ipad):
    try:
        rhost_url = socket.gethostbyaddr(ipad)
        rhost_url = rhost_url[0]
    except Exception:
        rhost_url = 'No URL found for this ip address.'
    return rhost_url



#main function to run the code only if called directly
def Main():

#printing the options menu and taking a variable to be passed
    print '_' * 20
    print "1: Get your ip address: \n"
    print "2: Get Geolocation of an IP address: \n"
    print "3: Atempt getting URL from IP address"
    sel = raw_input("Choose an option: \n")

#if statement to control menu navigation
    if sel == '1':
        print get_host_ipad()

#calls the get_rhost_ipad function defined above on user input
    elif sel == '2':
        ipad = raw_input("Which IP address?: \n")
        print get_rhost_geo(ipad)
    elif sel == 'quit':
        quit()
    elif sel == '3':
        ipad = raw_input("Which IP address?: \n")
        print get_rhost_url(ipad)

    else:
        print "Please choose one of the other options. \n"

if __name__=="__main__":
        Main()

代码 - log_auditor.py:

import re
import ip_tools

#global variable to open kippo log in read mode

MY_LOG = open("/path/to/log", "r").read()

#function to get ip address from log file with a regular expression
def get_ips_from_log():
    re_ip_search = re.findall(r"\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b", MY_LOG)
    return re_ip_search

#function to get attempts per unique ip address
def get_ip_count():
    ip_log = get_ips_from_log()
    ip_count = [(i, ip_log.count(i)) for i in set(ip_log)]
    return ip_count


#function to get attempts per country
def get_country_count():
    ip_list = get_ips_from_log()
    get_country_count = [(ip_tools.get_geo_country(ip), ip_list.count(ip)) for ip in set(ip_list)]
    return get_country_count

#main function to only run program when called:

def Main():
    print get_country_count()

if __name__=='__main__':
    Main()

有问题的函数是这个:

#function to get attempts per country
def get_country_count():
    ip_list = get_ips_from_log()
    get_country_count = [(ip_tools.get_geo_country(ip), ip_list.count(ip)) for ip in set(ip_list)]
    return get_country_count

不幸的是,它的输出看起来像:

[('CN', 2), ('CN', 566), ('NL', 2), ('CN', 3040), ('CN', 2), ('CN', 1042), ('CN', 2), ('US', 2), ('KR', 382), ('DE', 2), ('US', 127)]

如何进一步分组?

【问题讨论】:

  • 你能发布你的预期输出吗?
  • 您的问题可以使用一个示例输入列表、一个函数(您指定的那个)和一个所需输出示例来解释。请缩小您的问题范围 - 人们对您的生活故事并不真正感兴趣;)
  • “进一步分组”是什么意思?
  • @Zenadix OP 可能希望将 'CN' 的计数加在一起,因此他们希望每个标签只需要一个而不是多个结果 ('CN', 2), ..., ('CN', 2)('CN', 4)
  • 一旦你删除了所有无关的东西,我想你正在寻找像collections.Counter(ip_tools.get_geo_country(ip) for ip in ip_list) 这样的东西,在这种情况下,这是许多“我如何计算东西”问题的重复。

标签: python python-2.7


【解决方案1】:

使用字典记录每个国家/地区代码的总数。

from collections import defaultdict
def get_country_count():
    ip_list = get_ips_from_log()
    country_count = defaultdict(int)
    for ip in set(ip_list):
        country_count[ip_tools.get_geo_country(ip)] += ip_list.count(ip)
    return country_count

【讨论】:

  • 漂亮,我不知道这个库。现在的输出如下:defaultdict(<type 'int'>, {'NL': 2, 'CN': 4654, 'DE': 2, 'US': 141, 'KR': 448, 'ID': 14}) 如何删除 defaultdict(, ? 最终,只要信息在字典或元组列表中,它就可以满足我的需要。跨度>
  • 使用dict构造函数dict(country_count),它将打印{'NL' : 2, 'CN': 4654, 'DE': 2, 'US': 141, 'KR': 448, 'ID': 14}
  • 很简单,我早该想到的。感谢您的帮助,我对这一切还是很陌生
  • 这似乎需要大量的工作来模拟带有collections.Counter 的单线器会做什么,除了在二次时间而不是线性时间。为什么?
【解决方案2】:

如果我们不触及所有其他代码,函数可以这样重写:

from collections import defaultdict

....

def get_country_count():
    country_count = defaultdict(int)
    for ip in get_ips_from_log():
        country_count[ip_tools.get_geo_country(ip)] += 1
    return country_count

或者如果使用get_geo_country花费很多:

def get_country_count():
    country_count = defaultdict(int)
    ip_list = get_ips_from_log()
    for ip in set(ip_list):
        country_count[ip_tools.get_geo_country(ip)] += ip_list.count(ip)
    return country_count

defaultdict 只是出于某种原因不要写出这样丑陋的结构:

def get_country_count():
   ....
   for ....
       country = ip_tools.get_geo_country(ip)
       if country in country_count:
           country_count[country] += ...
       else:
           country_count[country] = ...

【讨论】:

  • 感谢您的回复。其他人也提到了使用 defaultdict,我什至不知道它的存在,但这非常有帮助。第二个代码 sn-p 是我将使用的代码。
猜你喜欢
  • 2014-02-16
  • 1970-01-01
  • 2015-06-25
  • 1970-01-01
  • 1970-01-01
  • 2015-03-24
  • 1970-01-01
  • 2016-06-05
  • 1970-01-01
相关资源
最近更新 更多