импортировать вложенный dict, содержащий список в csv - PullRequest
0 голосов
/ 25 февраля 2020

Я пытаюсь импортировать следующие данные в CSV:

{'test.foo.com': {'domain': 'foo.com','FQDN': 'test.foo.com', 'AS': 'AS1111', 'ressource_type': 'A', \
'nb_ip': '1', 'IP': '1.1.1.1', 'service': ['UNKNOWN'], 'port': '[443, 8443]'}}

Я почти успешно с этим кодом:

#!/bin/python3

## Import ##
# Offical
import csv

### Main ###
if __name__ == '__main__':
  ## Variables
  csv_headers = ['domain', 'FQDN', 'AS', 'ressource_type', 'nb_ip', 'IP', 'service', 'port']
  final_data = {'test.foo.com': {'domain': 'foo.com','FQDN': 'test.foo.com', 'AS': 'AS1111', 'ressource_type': 'A', \
  'nb_ip': '1', 'IP': '1.1.1.1', 'service': ['UNKNOWN'], 'port': '[443, 8443]'}}

  # Open the csv file in "write mode"
  with open(file_name, mode='w') as file:
      # Prepare the writer to add a dict into the csv file
      csv_writer = csv.DictWriter(file, fieldnames=headers)

      # Write the columns header into the csv file
      csv_writer.writeheader()
      # Write the dict into the file
      for key, val in nest_dict.items():
          row = {'FQDN': key}
          row.update(val)
          csv_writer.writerow(row)

Результат:

domain,FQDN,AS,ressource_type,nb_ip,IP,service,port
foo.com,test.foo.com,AS1111,A,1,1.1.1.1,['UNKNOWN'],"[443, 8443]"

Но я бы хотел:

domain,FQDN,AS,ressource_type,nb_ip,IP,service,port
foo.com,test.foo.com,AS1111,A,1,1.1.1.1,'UNKNOWN','443'
foo.com,test.foo.com,AS1111,A,1,1.1.1.1,'UNKNOWN','8443'

Видите разницу? У меня есть список «сервис» (здесь не требуется лечение) и список «порт». Если в столбце «порт» имеется более 1 порта, мне нужно напечатать новую строку для каждого порта в списке.

Я изо всех сил пытаюсь сделать это, потому что я не полностью понял этот код:

# Write the dict into the file
      for key, val in nest_dict.items():
          row = {'FQDN': key}
          row.update(val)
          csv_writer.writerow(row)

Не могли бы вы помочь мне с этим?

Спасибо!

С уважением,

Steackfrite

Ответы [ 2 ]

0 голосов
/ 26 февраля 2020

Так что это окончательный код.

Не уверен, что это лучший способ, но он выглядит достаточно хорошо для меня.

#!/bin/python3

## Import ##
# Offical
import csv

### Main ###
if __name__ == '__main__':
  ## Variables
  csv_headers = ['domain', 'FQDN', 'AS', 'ressource_type', 'nb_ip', 'IP', 'service', 'port']
  final_data = {'test.foo.com': {'domain': 'foo.com','FQDN': 'test.foo.com', 'AS': 'AS1111', 'ressource_type': 'A', \
  'nb_ip': '1', 'IP': '1.1.1.1', 'service': ['UNKNOWN'], 'port': '[443, 8443]'}}

# Open the csv file in "write mode"
with open(file_name, mode='w') as file:
    # Prepare the writer to add a dict into the csv file
    csv_writer = csv.DictWriter(file, fieldnames=csv_headers)

    # Write the columns header into the csv file
    csv_writer.writeheader()

    for key, val in final_data.items():
        # ?
        row = {'FQDN': key}
        # Update the row with all columns values
        row.update(val)
        # If service contains multiple elements it will transform the list into a string with each string separate by a space
        # If service contains just one element, it will transform the list into a string (no space) added
        row['service'] = ' '.join(val['service'])

        # Write a row for each value in the port list
        for port in val['port']:
            row['port'] = port
            csv_writer.writerow(row)

Результат Вывод:

domain,FQDN,AS,ressource_type,nb_ip,IP,service,port
foo.com,test.foo.com,AS1111,A,1,1.1.1.1,'UNKNOWN','443'
foo.com,test.foo.com,AS1111,A,1,1.1.1.1,'UNKNOWN','8443'

Не голосуйте за мой ответ, я ставлю его для целей знания. Все награды должны go до @ bartonstanley

0 голосов
/ 25 февраля 2020

Это даст желаемый результат с данными:

### Main ###
if __name__ == '__main__':
  ## Variables
  csv_headers = ['domain', 'FQDN', 'AS', 'ressource_type', 'nb_ip', 'IP', 'service', 'port']
  final_data = {'test.foo.com': {'domain': 'foo.com','FQDN': 'test.foo.com', 'AS': 'AS1111', 'ressource_type': 'A', \
  'nb_ip': '1', 'IP': '1.1.1.1', 'service': ['UNKNOWN'], 'port': '[443, 8443]'}}

  # Open the csv file in "write mode"
  with open('out.csv', mode='w') as file:
      # Prepare the writer to add a dict into the csv file
      csv_writer = csv.DictWriter(file, fieldnames=csv_headers)

      # Write the columns header into the csv file
      csv_writer.writeheader()
      # Write the dict into the file
      for key, val in final_data.items():
          row = {'FQDN': key}
          # Assume that service is always a list of one value and replace it with the one value
          # it contains.
          val['service'] = val.pop('service')[0]
          row.update(val)
          # Since the value of port is quoted it will be a string, but we wat a list. Remove the
          # value of 'port' from the dict and put it in 'port_string' (= '[443, 8443'')
          port_string = val.pop('port')
          # Remove the opening and closing brackets from the port_string (= '443, 8443').
          port_string = port_string.replace('[', '')
          port_string = port_string.replace(']', '')
          # Now we can split the string into a python list (= ['443', ' 8443'])
          port_list = port_string.split(',')
          # Write a csv row for each value in the port list
          for port in port_list:
              row['port'] = port.strip()
              csv_writer.writerow(row)

(Кстати, код в исходном сообщении не запускался. Этот код включает в себя правки для его запуска.)

Обратите внимание, что, поскольку значение 'port' заключено в кавычки (в отличие от значения 'service'), оно будет считано как строка, поэтому сначала его необходимо преобразовать в список. Если одинарные кавычки вокруг [443, 8443] удаляются, тогда портовая часть кода упрощается до:

          port_list = val.pop('port')
          # Write a csv row for each value in the port list
          for port in port_list:
              row['port'] = port
              csv_writer.writerow(row)

Другая потенциальная проблема связана с «обслуживанием». Это список, поэтому он может иметь более одного значения? Если так, то код должен быть изменен, чтобы решить эту проблему.

Наконец, код, который я здесь представляю, может быть более pythoni c, но я хотел убедиться, что он как можно более читабелен для начинающих. Его можно сделать больше pythoni c, если он будет работать полностью, как нужно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...