92318


機器のログを取得し、CSV化しようとしましたが、ログが100万行程度あり、VBAでは全件表示できず、処理できない状態です。  
そこで、pythonでログをCSV化しようとしておりますが、以下2点をどの様にすればよいのか全く分からない状況です。

＜分からないこと＞  
①dataコマンドで表示した日時をID、MAC Addressなどの列の左側に追記したい  
②ID、MAC Addressなどのヘッダーがコマンドを実行する度に表示されるので、CSV化する場合は、一番最初だけにしたい  
③CSV化するにあたり、date、wlc# show ap-discovered、 Discovered APs and Stations(4249
entries)など不要な  
コマンド等は削除したい

＜記載したコード＞  
sample.py

[code]

    file_name = "C:/Work/before.log"
    
    with open(file_name, 'r', encoding='shift-jis') as f:
        lines = f.readlines()
    
    for line in lines:
        newlines = line.split()
        print(newlines)
    
[/code]

＜その他＞  
before.log→機器から出力したログ（100万行程度ですが、数行だけ掲載しております）  
after.csv→before.logを加工し、実現したい形式

before.log

[code]

    date
    Tue Nov 11 00:00:00 JST 2022
    wlc# show ap-discovered
    
    ID     MAC Address       Type          Channel Confirmed-Channel SSID                             BSSID             Last            Previous  Current   Pkts Rx  RF Band       Name            
    
    40     aa:bb:cc:dd:ee:ff AP            6       6                 samplesamplesample               11:22:33:44:55:66 00d:00h:00m:00s 0         -77       313382   802.11gn      AP1        
    40     gg:hh:ii:jj:kk:ll AP            6       7                 samplesamplesample               22:33:44:55:66:77 00d:00h:00m:01s 0         -75       2840     802.11gn      AP2
        Discovered APs and Stations(4249 entries)
    date
    Tue Nov 11 00:05:00 JST 2022
    wlc# show ap-discovered
    
    ID     MAC Address       Type          Channel Confirmed-Channel SSID                             BSSID             Last            Previous  Current   Pkts Rx  RF Band       Name            
    
    40     aa:bb:cc:dd:ee:ff AP            6       6                 samplesamplesample               11:22:33:44:55:66 00d:00h:00m:00s 0         -77       313382   802.11gn      AP1        
    40     gg:hh:ii:jj:kk:ll AP            6       7                 samplesamplesample               22:33:44:55:66:77 00d:00h:00m:01s 0         -75       2840     802.11gn      AP2
    date
    Tue Nov 11 00:10:00 JST 2022
    wlc# show ap-discovered
    
    ID     MAC Address       Type          Channel Confirmed-Channel SSID                             BSSID             Last            Previous  Current   Pkts Rx  RF Band       Name            
    
    40     aa:bb:cc:dd:ee:ff AP            6       6                 samplesamplesample               11:22:33:44:55:66 00d:00h:00m:00s 0         -77       313382   802.11gn      AP1        
    40     gg:hh:ii:jj:kk:ll AP            6       7                 samplesamplesample               22:33:44:55:66:77 00d:00h:00m:01s 0         -75       2840     802.11gn      AP2
        Discovered APs and Stations(4249 entries)
    
[/code]

after.csv

[code]

    Day,Month,Date,Time,ID,MAC Address,Type,Channel,Confirmed-Channel,SSID,BSSID,Last,Previous,Current,Pkts,Rx,RF,Band,Name            
    Tue,Nov,11,00:00:00,40,aa:bb:cc:dd:ee:ff,AP,6,6,samplesamplesample,11:22:33:44:55:66,00d:00h:00m:00s,0,-77,313382,802.11gn,AP1
    Tue,Nov,11,00:00:00,40,gg:hh:ii:jj:kk:ll,AP,6,6,samplesamplesample,22:33:44:55:66:77,00d:00h:00m:00s,0,-77,313382,802.11gn,AP2        
    Tue,Nov,11,00:05:00,40,aa:bb:cc:dd:ee:ff,AP,6,6,samplesamplesample,11:22:33:44:55:66,00d:00h:00m:00s,0,-77,313382,802.11gn,AP1
    Tue,Nov,11,00:05:00,40,gg:hh:ii:jj:kk:ll,AP,6,6,samplesamplesample,22:33:44:55:66:77,00d:00h:00m:00s,0,-77,313382,802.11gn,AP2          
    
[/code]

コード例をご提示いただき、ご教示いただけると助かります。

* * *

追記

[code]

    file_name = "C:/Work/before.log"
    
    # 追記
    out = open('output.txt','w')
    
    with open(file_name, 'r', encoding='shift-jis') as f:
        # lines = f.readlines()
    
        print('Day,Month,Date,Time,ID,MAC Address,Type,Channel,Confirmed-Channel,SSID,BSSID,Last,Previous,Current,Pkts,Rx,RF,Band,Name')
    
        # Fileを1行ずつ読む
        line = f.readline()
        while line:
    
            # date 行だったら次の行を読んで４列だけ取得してカンマでつないで date_csv 変数に記憶
            if line.startswith('date'):
                line = f.readline()
                date = line.split()[:4]
                date_csv = ','.join(date) + ','
    
            # 数字から始まってたら記憶した date_csv とその行を , つなぎにしてものを１行で出力
            if line[0] >= '0' and line[0] <= '9':
                # print(date_csv + ','.join(line.split()))
                print(date_csv + ','.join(line.split()))
                
            line = f.readline()
    
            # 追記↓
            out.write(line + "\n")
    # 追記↓
    out.close()
    
[/code]

out.txt出力結果

[code]

    wlc# show ap-discovered
    
    
    
    ID     MAC Address       Type          Channel Confirmed-Channel SSID                             BSSID             Last            Previous  Current   Pkts Rx  RF Band       Name            
    
    
    
    40     aa:bb:cc:dd:ee:ff AP            6       6                 samplesamplesample               11:22:33:44:55:66 00d:00h:00m:00s 0         -77       313382   802.11gn      AP1        
    
    40     gg:hh:ii:jj:kk:ll AP            6       7                 samplesamplesample               22:33:44:55:66:77 00d:00h:00m:01s 0         -75       2840     802.11gn      AP2
    
    date
    
    wlc# show ap-discovered
    
    
    
    ID     MAC Address       Type          Channel Confirmed-Channel SSID                             BSSID             Last            Previous  Current   Pkts Rx  RF Band       Name            
    
    
    
    40     aa:bb:cc:dd:ee:ff AP            6       6                 samplesamplesample               11:22:33:44:55:66 00d:00h:00m:00s 0         -77       313382   802.11gn      AP1        
    
    40     gg:hh:ii:jj:kk:ll AP            6       7                 samplesamplesample               22:33:44:55:66:77 00d:00h:00m:01s 0         -75       2840     802.11gn      AP2
    
    date
    
[/code]


CC BY-SA 4.0
2022-11-19T07:39:38.077
92311
2022-11-21T15:20:35.217
2022-11-21T08:30:27.910
question
python python3
pythonテキストファイル（log）のCSV化


readlines() を使うとメモリ上にすべてのファイル内容を取得してしまうので  
１００万行単位だとメモリ的に厳しいかもしれません

基本的には date 行をよんだら date の内容を覚えておいて  
レコード行をよんだときに date とあわせて吐き出してしまえば  
過去呼んだ部分を覚えておくのは最新の date 内容だけでいいはずです

こんな感じでしょうか

[code]

    file_name = "C:/Work/before.log"
    
    with open(file_name, 'r', encoding='shift-jis') as f:
        # lines = f.readlines()
    
        print('Day,Month,Date,Time,ID,MAC Address,Type,Channel,Confirmed-Channel,SSID,BSSID,Last,Previous,Current,Pkts,Rx,RF,Band,Name')
    
        # Fileを1行ずつ読む
        line = f.readline()
        while line:
    
            # date 行だったら次の行を読んで４列だけ取得してカンマでつないで date_csv 変数に記憶
            if line.startswith('date'):
                line = f.readline()
                date = line.split()[:4]
                date_csv = ','.join(date) + ','
    
            # 数字から始まってたら記憶した date_csv とその行を , つなぎにしてものを１行で出力
            if line[0] >= '0' and line[0] <= '9':
                print(date_csv + ','.join(line.split()))
    
            line = f.readline()
    
[/code]

※ ログなので出力先は標準出力にしましたがリダイレクトなりすればファイルにはけると思いますし、固定ファイル出力するならwith
open(file_name, 'w') みたいなコードにうめこんでもいいと思います

※ １文字目が数字ではじまるものをレコード行としましたが ③
の内容にどんなものがあるか不明なので正確にやるなら正規表現でマッチングしたほうがいいかもしれないです  
その分判定コストが重くなるので１００万行分となると時間かかるかもですが

* * *

追記

ファイル出力版です

[code]

    file_name = "C:/Work/before.log"
    
    with open('output.txt','w') as out:
        with open(file_name, 'r', encoding='shift-jis') as f:
            # lines = f.readlines()
    
            out.write('Day,Month,Date,Time,ID,MAC Address,Type,Channel,Confirmed-Channel,SSID,BSSID,Last,Previous,Current,Pkts,Rx,RF,Band,Name\n')
    
            # Fileを1行ずつ読む
            line = f.readline()
            while line:
    
                # date 行だったら次の行を読んで４列だけ取得してカンマでつないで date_csv 変数に記憶
                if line.startswith('date'):
                    line = f.readline()
                    date = line.split()[:4]
                    date_csv = ','.join(date) + ','
    
                # 数字から始まってたら記憶した date_csv とその行を , つなぎにしてものを１行で出力
                if line[0] >= '0' and line[0] <= '9':
                    out.write(date_csv + ','.join(line.split()) + "\n")
    
                line = f.readline()
    
[/code]

実行結果

[code]

    Day,Month,Date,Time,ID,MAC Address,Type,Channel,Confirmed-Channel,SSID,BSSID,Last,Previous,Current,Pkts,Rx,RF,Band,Name
    Tue,Nov,11,00:00:00,40,aa:bb:cc:dd:ee:ff,AP,6,6,samplesamplesample,11:22:33:44:55:66,00d:00h:00m:00s,0,-77,313382,802.11gn,AP1
    Tue,Nov,11,00:00:00,40,gg:hh:ii:jj:kk:ll,AP,6,7,samplesamplesample,22:33:44:55:66:77,00d:00h:00m:01s,0,-75,2840,802.11gn,AP2
    Tue,Nov,11,00:05:00,40,aa:bb:cc:dd:ee:ff,AP,6,6,samplesamplesample,11:22:33:44:55:66,00d:00h:00m:00s,0,-77,313382,802.11gn,AP1
    Tue,Nov,11,00:05:00,40,gg:hh:ii:jj:kk:ll,AP,6,7,samplesamplesample,22:33:44:55:66:77,00d:00h:00m:01s,0,-75,2840,802.11gn,AP2
    Tue,Nov,11,00:10:00,40,aa:bb:cc:dd:ee:ff,AP,6,6,samplesamplesample,11:22:33:44:55:66,00d:00h:00m:00s,0,-77,313382,802.11gn,AP1
    Tue,Nov,11,00:10:00,40,gg:hh:ii:jj:kk:ll,AP,6,7,samplesamplesample,22:33:44:55:66:77,00d:00h:00m:01s,0,-75,2840,802.11gn,AP2
    
    
[/code]

自分の環境ではサンプルの before.log に対しては動きました  
もしだめなようならサンプルのログをもう少し長めにはってもらえると原因がわかるかもです

* * *

更に追記

readline のほうがわかりやすいかと思ってあえて使ったんですが  
readline がどういう関数なのかわかりにくいみたいなので  
よくあるファイルをイテレーターとして使って１行ずつ読む例です

[code]

    file_name = "C:/Work/before.log"
    
    out = open('output.txt','w')
    # print('Day,Month,Date,Time,ID,MAC Address,Type,Channel,Confirmed-Channel,SSID,BSSID,Last,Previous,Current,Pkts,Rx,RF,Band,Name\n')
    
    out.write('Day,Month,Date,Time,ID,MAC Address,Type,Channel,Confirmed-Channel,SSID,BSSID,Last,Previous,Current,Pkts,Rx,RF,Band,Name\n')
    
    with open(file_name, 'r', encoding='shift-jis') as f:
    
        # Fileを1行ずつ読む
        for line in f:
    
            # date 行だったら次の行を読んで４列だけ取得してカンマでつないで date_csv 変数に記憶
            if line.startswith('date'):
                line = f.__next__() # 次の行にループを進ませる (readline と同じ)
                date = line.split()[:4]
                date_csv = ','.join(date) + ','
    
            # 数字から始まってたら記憶した date_csv とその行を , つなぎにしてものを１行で出力
            if line[0] >= '0' and line[0] <= '9':
                output_line = date_csv + ','.join(line.split())
                # print(output_line)
                out.write(output_line + "\n")
    
    out.close()
    
[/code]


CC BY-SA 4.0
2022-11-19T14:14:35.530
92318
2022-11-21T08:52:06.103
2022-11-21T08:52:06.103
92311
answer


既に解決済みなので御参考です。Python3.8 で（賛否の議論の後に）導入された代入式（`:=`）を使ってみました。

[code]

    file_name = 'C:/Work/before.log'
    
    with open(file_name, 'r', encoding='shift-jis') as f:
        print('Day,Month,Date,Time,ID,MAC Address,Type,'
              'Channel,Confirmed-Channel,SSID,BSSID,Last,'
              'Previous,Current,Pkts,Rx,RF,Band,Name')
    
        line = ''
        while line or (line := f.readline()):
            if line[:4] != 'date':
                line = ''
                continue
            date_info = f.readline().split()[:4]
    
            while f.readline()[:2] != 'ID': pass
            f.readline()  # read blank line
            while (line := f.readline())[:1].isdecimal():
                print(','.join(date_info + line.split()))
    
[/code]


CC BY-SA 4.0
2022-11-21T15:20:35.217
92361
2022-11-21T15:20:35.217
54588
92311
answer