Скрипт на Python для извлечения данных из txt в csv

#python #excel

#python #excel

Вопрос:

Я пытаюсь написать скрипт на Python для извлечения данных Wi-Fi из файла txt в csv

Вот данные txt:

 Wed Oct  7 09:00:01 UTC 2020

BSS 02:ca:fe:ca:ca:40(on ap0_1)
freq: 2422
capability: IBSS (0x0012)
signal: -60.00 dBm
primary channel: 3
last seen: 30 ms ago
BSS ac:86:74:0a:73:a8(on ap0_1)
TSF: 229102338752 usec (2d, 15:38:22)
freq: 2422
capability: ESS (0x0421)
signal: -62.00 dBm
primary channel: 3
  

Мне нужно извлечь данные txt в файл csv в этом формате:

  Time                        | BSS                       | freq |capability   |signal| primary channel |                                                
 ---------------------------- --------------------------- ------ ------------- ------ -----------------                   
 Wed Oct  7 09:00:01 UTC 2020|02:ca:fe:ca:ca:40(on ap0_1)| 2422 |IBSS (0x0012)|-60.00|             3   |
                             |ac:86:74:0a:73:a8(on ap0_1)| 2422 |IBSS (0x0012)|-62.00|             3   |
  

Это мой незаконченный код:

 import csv
import re

fieldnames = ['TIME', 'BSS', 'FREQ','CAPABILITY', 'SIGNAL', 'CHANNEL']

re_fields = re.compile(r'({}) :s(.*)'.format('|'.join(fieldnames)), re.I)

with open('ap0_1.txt') as f_input, open('ap0_1.csv', 'w', newline='') as f_output:
    csv_output = csv.DictWriter(f_output, fieldnames= fieldnames)
    csv_output.writeheader()
    start = False

    for line in f_input:
        line = line.strip()

        if len(line):
            if 'BSS' in line:
                if start:
                    start = False
                    block.append(line)
                    text_block = 'n'.join(block)

                    for field, value in re_fields.findall(text_block):
                        entry[field.upper()] = value

                    if line[0] == 'on ap0_1':
                        entry['BSS'] = block[0]

                    csv_output.writerow(entry)

                else:
                    start = True
                    entry = {}
                    block = [line]
            elif start:
                block.append(line)
  

Когда я его запускаю, данные размещаются неправильно.

введите описание изображения здесь

Пожалуйста, дайте мне знать, как это исправить. Я всего лишь новичок в программировании и был бы признателен за любой совет. Спасибо.

Комментарии:

1. Пожалуйста, добавьте желаемый и наблюдаемый результат для входных образцов к вашему вопросу.

2. Привет, Клаус Д. Я добавил желаемый результат.

3. Вопрос сбивает с толку. Вы говорите «вот данные», и вы также говорите «данные в этом формате», и эти два примера сильно отличаются. Как на самом деле выглядят входные данные?

4. Привет, Джон Гордон, извините, что сбил вас с толку. я отредактировал вопрос

Ответ №1:

Использование str.startswith

Пример:

 import csv

fieldnames = ('TIME', 'BSS', 'freq','capability', 'signal', 'primary channel')
with open(filename) as f_input, open(outfile,'w', newline='') as f_output:
    csv_output = csv.DictWriter(f_output, fieldnames= fieldnames)
    csv_output.writeheader()
    result = {"TIME": next(f_input).strip()}   #Get Time, First Line
    for line in f_input:
        line = line.strip()
        if line.startswith(fieldnames):
            if line.startswith('BSS'):
                key, value = line.split(" ", 1)
            else:
                key, value = line.split(": ")
            result[key] = value
            
    csv_output.writerow(result)
  

РЕДАКТИРОВАТЬ согласно комментарию

Если у вас есть несколько блоков приведенного выше текста

 import re
import csv

week_ptrn = re.compile(r"b("   "|".join(('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'))   r")b")
fieldnames = ('TIME', 'BSS', 'freq','capability', 'signal', 'primary channel')

with open(filename) as f_input, open(outfile,'w', newline='') as f_output:
    csv_output = csv.DictWriter(f_output, fieldnames= fieldnames)
    csv_output.writeheader()
    result = []    #Get Time, First Line
    for line in f_input:
        line = line.strip()
        week = week_ptrn.match(line)
        if week:
            result.append({"TIME": line})
            
        if line.startswith(fieldnames):
            if line.startswith('BSS'):
                key, value = line.split(" ", 1)
            else:
                key, value = line.split(": ")
            result[-1][key] = value
            
    csv_output.writerows(result)
  

Комментарии:

1. Привет, Ракеш, код извлекает только 1-й BSS, но не 2-й BSS

2. Извините, я не понимаю… У вас есть несколько блоков приведенной выше строки в текстовом файле?

3. Да, каждый блок начинается с BSS и заканчивается основным каналом

Ответ №2:

Вы пытались выполнить поиск времени с помощью «TIME». Но во входных данных нет «ВРЕМЕНИ». Таким образом, вывод с пустым временем является естественным.

И я думаю, что следующие строки также имеют проблему.

             if line[0] == 'on ap0_1':
                entry['BSS'] = block[0]
  

По-моему, вы пытались найти on ap0_1 of BSS ac:86:74:0a:73:a8(on ap0_1) .
Но строка [0] — это ‘BSS’, первая из [‘BSS’, ‘ac:86:74:0a:73:a8(on’, ‘ap0_1)’] . Это должно измениться следующим образом:

             if 'on ap0_1' in block[0]:
                entry['BSS'] = block[0][4:].lstrip()
  

Ответ №3:

Вот моя версия кода.

 import csv, re

fieldnames = ['TIME', 'BSS', 'FREQ','CAPABILITY', 'SIGNAL', 'CHANNEL']
re_fields = re.compile(r'({}) :s(.*)'.format('|'.join(fieldnames)), re.I)

with open('ap0_1.txt') as f_input, open('ap0_1.csv', 'w', newline='') as f_output:
    csv_output = csv.DictWriter(f_output, fieldnames= fieldnames)
    csv_output.writeheader()
    start = False
 
    time_condition = lambda @l: l.startswith('Mon') or l.startswith('Tue') or  
                     l.startswith('Wed') or l.startswith('Thu') or l.startswith('Fri')  
                     or l.startswith('Sat') or l.startswith('Sun')
    
    row = dict{}
    for line in f_input:
        line = line.strip()
        if not line:
            continue
        elif time_condition(line):
            row['TIME'] = line
        else:
            # not sure how you define the start of a new block, say, it is by 'BSS' string
            key, value = line.split(' ', 1) # split one time exactly
            key = key.rstrip(':').upper()
            if key == 'BSS' and row:
                row = (row.get(k, '') for k in fieldnames)
                csv_output.writerow(row)
                row = dict()
  
            row[key.upper()] = value
    row = (row.get(k, '') for k in fieldnames)
    csv_output.writerow(row)   
  

Похоже, что ‘ n’ создает пустые строки.

Комментарии:

1. Привет @kate-melnykova, когда я попытался запустить код, он сказал, что block [‘TIME’] = строка не определена.