質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
CSV

CSV(Comma-Separated Values)はコンマで区切られた明白なテキスト値のリストです。もしくは、そのフォーマットでひとつ以上のリストを含むファイルを指します。

Apache

Apacheは、Apache HTTP Serverの略で、最も人気の高いWebサーバソフトウェアの一つです。安定性が高いオープンソースソフトウェアとして商用サイトから自宅サーバまで、多くのプラットフォーム向けに開発・配布されています。サーバーソフトウェアの不具合(NCSA httpd)を修正するパッチ(a patch)を集積、一つ独立したソフトウェアとして開発されました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

2回答

796閲覧

Pythonでリクエストの最初の行の値(リクエストURL)に"が含まれているApacheのaccess_logをCSV、TSVに変換する方法

退会済みユーザー

退会済みユーザー

総合スコア0

CSV

CSV(Comma-Separated Values)はコンマで区切られた明白なテキスト値のリストです。もしくは、そのフォーマットでひとつ以上のリストを含むファイルを指します。

Apache

Apacheは、Apache HTTP Serverの略で、最も人気の高いWebサーバソフトウェアの一つです。安定性が高いオープンソースソフトウェアとして商用サイトから自宅サーバまで、多くのプラットフォーム向けに開発・配布されています。サーバーソフトウェアの不具合(NCSA httpd)を修正するパッチ(a patch)を集積、一つ独立したソフトウェアとして開発されました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2018/11/28 23:52

編集2018/11/29 06:13

件名の通りです。対処方法をご教授いただけませんでしょうか?よろしくお願いいたします。

解決したい問題
%r(リクエストの最初の行)に「"」が含まれていても対応できる方法をご教授いただきたいです。

環境

  • Windows10
  • Spyder(Python 3.6)

サンプル

log

1 2hoge.fuga.com - - [04/Sep/2018:20:38:28 +0900] "GET /index.php?&q=type%3Apiyo" HTTP/1.1" 200 144155 "-" "-" 3

得たい結果

tsv

1 2hoge.fuga.com~-~-~04/Sep/2018:20:38:28 +0900~GET~/index.php?&q=type%3Apiyo~200~144155~-~- 3

現在の表示結果

txt

1#log 2123.hoge.jp - - [01/Sep/2018:02:00:03 +0900] "GET /index.php?&q=1 HTTP/1.1" 200 622 "https://www.hoge.com" "Mozilla/5.0 (iPhone; CPU iPhone OS 11_4_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.0 Mobile/15E148 Safari/604.1" 34#tsv 5123.hoge.jp~-~-~01/Sep/2018:02:00:03 +0900~GET~/index.php?&q=1~200~622~https://www.hoge.com~Mozilla/5.0~(iPhone;~CPU~iPhone~OS~11_4_1~like~Mac~OS~X)~AppleWebKit/605.1.15~(KHTML,~like~Gecko)~Version/11.0~Mobile/15E148~Safari/604.1" 6

分割ルール(取得したいテキスト)

  • 全ての列の「"」はエスケープ
  • %h(クライアントのホスト名)そのまま
  • %l(リモートログ名)そのまま
  • %u(Basic認証のユーザー名)そのまま
  • %t(リクエスト時刻)[中身]の中身を取得[]は不要
  • %r(リクエストの最初の行)HTTPメソッドとリクエストURL(スペースが含まれる場合にはエンコード)に分割、HTTP○○(HTTPS○○)は不要
  • %>s(HTTPステータス)そのまま
  • %b(レスポンスのバイト数)そのまま
  • %{Referer}i(リファラ)そのまま(スペースはそのまま取得)
  • %{User-Agent}i(ユーザーエージェント)そのまま(スペースはそのまま取得)

Apacheのログ

conf

1 2"%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" 3

Pythonスクリプト

python

1 2import bz2 3import re 4import codecs 5 6def conv_line(l): 7 cols = l.split(' ') # まずは無条件で空白で分割する 8 dst = cols[:3] 9 dst += [cols[3].lstrip('[')+' '+cols[4].rstrip(']')] # 04/Sep/2018:20:38:28 +0900 10 dst += [cols[5].lstrip('"')] # GET 11 dst += [cols[6].rstrip('"')] # /index.php?&q=type%3Apiyo 12 dst += [col.strip('"') for col in cols[8:]] 13 return '~'.join(dst) 14 15fr = bz2.open(r'C:\Users\user\Desktop\bz2\access_log.bz2', 'rt') 16fw = codecs.open(r'C:\Users\user\Desktop\bz2\access_log.bz2.tsv', 'w', encoding='utf-8') 17 18line = fr.readline() 19line = line.replace('~', '') 20 21while line: 22 #リクエストの最初の行(リクエストURL)に「"」が含まれている場合ダメ 23 #fline = re.sub(r'^(\S+) (\S+) (\S+) [([^]]+)] "([A-Z]+) ([^ "]+)? (?:HTTP|HTTPS)/[0-9.]+" ([0-9]{3}) ([0-9]+|-) "([^\"]*)" "([^\"]*)"', r'\1~\2~\3~\4~\5~\6~\7~\8~\9~\10', line) 24 fline = conv_line(line) 25 check = re.search(r'/public/|/bot/|Googlebot|msnbot|bingbot|applebot|SemrushBot|AhrefsBot|MJ12bot|AdsBot|DotBot|istellabot|Twitterbot|YandexMobileBot|/bots|/bot.html|robots.txt', fline) 26 if check is None: 27 fw.write(fline) 28 line = fr.readline() 29 line = line.replace('~', '') 30fr.close() 31fw.close() 32 33

コピペ & 参考にさせていただいたページ

](https://stackoverflow.com/questions/18766955/how-to-write-utf-8-in-a-csv-file)

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

y_waiwai

2018/11/29 00:14 編集

それをどうしたい、というはなしなんでしょうか。また、提示のコードではどうなるんでしょうか。 何を聞きたいのかわかりません
退会済みユーザー

退会済みユーザー

2018/11/29 00:29

y_waiwaiさん、失礼しました。得たい結果の追加とPythonスクリプトの修正を行いました。
can110

2018/11/29 01:53

log「~piyo" HTTP/1.1" 200 ~」部分にて「"」がどこかで抜けていませんか? また、得たい結果の中に「HTTP/1.1」が抜けているようです。
退会済みユーザー

退会済みユーザー

2018/11/29 02:07 編集

can110さん、ご依頼ありがとうございます。logはこちらの通りです。得たい結果の中に「HTTP/○○」は無しでOKです。
can110

2018/11/29 02:20

logは提示の通りは了解です。①得体結果の中に「HTTP/...」が入っていてもOKですか?、②列の分割ルールが不明確ですので詳細に明文化ください。たとえば「...[04/Sep/2018:20:38:28 +0900]...」は「04/Sep/2018:20:38:28 +0900」と「[」が取り除かれないといけないのか、「"GET /index.php?&q=type%3Apiyo"」は「"」で囲まれているが「GET~/index...」のように「~」で分割されるのはなぜか?などです。
退会済みユーザー

退会済みユーザー

2018/11/29 02:44 編集

ご回答ありがとうございます。分割ルールを追加しました。 >「"GET /index.php?&q=type%3Apiyo"」は「"」で囲まれているが「GET~/index...」のように「~」で分割されるのはなぜか? こちらについては、%r(リクエストの最初の行)に「"」が含まれていても対応できる方法をご教授いただきたいです。
can110

2018/11/29 02:48

追記ありがとうございます。「こちらについては~」は質問本文に疑問(解決したい問題)点として追記ください。
退会済みユーザー

退会済みユーザー

2018/11/29 02:55

解決したい問題を追記しました。
guest

回答2

0

ベストアンサー

各列にそれぞれ分割ルールがあるので、それに沿った変換を施すconv_line関数を使えばできそうです。

Python

1def conv_line(l): 2 cols = l.split(' ') # まずは無条件で空白で分割する 3 dst = cols[:3] 4 dst += [cols[3].lstrip('[')+' '+cols[4].rstrip(']')] # 04/Sep/2018:20:38:28 +0900 5 dst += [cols[5].lstrip('"')] # GET 6 dst += [cols[6].rstrip('"')] # /index.php?&q=type%3Apiyo 7 dst += [col.strip('"') for col in cols[8:]] 8 return '~'.join(dst) 9 10ret = conv_line('hoge.fuga.com - - [04/Sep/2018:20:38:28 +0900] "GET /index.php?&q=type%3Apiyo" HTTP/1.1" 200 144155 "-" "-"') 11print(ret) 12# hoge.fuga.com~-~-~04/Sep/2018:20:38:28 +0900~GET~/index.php?&q=type%3Apiyo~200~144155~-~-

投稿2018/11/29 03:57

can110

総合スコア38233

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2018/11/29 04:06

can110さん、ご回答ありがとうございます!試してみます。
退会済みユーザー

退会済みユーザー

2018/11/29 05:02

can110さん、現在の表示結果のようになる場合があります。こちらに対応する方法をご教授いただけませんでしょうか?何度もすみません。。
can110

2018/11/29 05:16

そもそも「%r(リクエストの最初の行)」は「"」で囲っているにもかかわらず、その中に「"」がエスケープもされず含まれる(複数個の可能性もある)ため、一般的な列分割のルールが適用できないデータになってしまっています。 よって(より厳密なルール、データの縛りがない限り)原理的には対応不能です。
退会済みユーザー

退会済みユーザー

2018/11/29 06:15

ご回答ありがとうございます。ルールを追記しました。この程度ではまだ対応不能でしょうか? 【追記したルール】全ての列の「"」はエスケープ、リクエストURL:スペースが含まれる場合にはエンコード、リファラ:そのまま(スペースはそのまま取得)、ユーザーエージェント:そのまま(スペースはそのまま取得)
can110

2018/11/29 06:24

ルール見ました。少なくとも私の回答の手法(最初に空白で切る)では不可能です。 やはり「"GET /index.php?&q=type%3Apiyo" HTTP/1.1"」の中の「piyo"」のように中に「"」が含まれているのがネックですね。難しいと思います。
退会済みユーザー

退会済みユーザー

2018/11/29 06:36

そうなんですね。can110さん、ありがとうございましたm(__)m
guest

0

一応動くものができました。。

python

1import bz2 2import re 3import codecs 4 5fr = bz2.open(r'C:\Users\user\Desktop\bz2\access_log.bz2', 'rt') 6fw = codecs.open(r'C:\Users\user\Desktop\bz2\access_log.bz2.csv', 'w', encoding='utf-8') 7 8line = fr.readline() 9 10while line: 11 fline = re.sub(r'^(\S+) (\S+) (\S+) [([^]]+)] "([A-Z]+) (.+)? (?:HTTP|HTTPS)/[0-9.]+" ([0-9]{3}) ([0-9]+|-) "(.*)" "(.*)"', r'\1\2\3\4\5\6\7\8\9\10', line) 12 check = re.search(r'/public/|/bot/|Googlebot|msnbot|bingbot|applebot|SemrushBot|AhrefsBot|MJ12bot|AdsBot|DotBot|istellabot|Twitterbot|YandexMobileBot|/bots|/bot.html|robots.txt', fline) 13 if check is None: 14 match_object = re.search(r'^(\S+) (\S+) (\S+) [([^]]+)] "([A-Z]+) (.+)? (?:HTTP|HTTPS)/[0-9.]+" ([0-9]{3}) ([0-9]+|-) "(.*)" "(.*)"', line, flags=re.IGNORECASE) 15 if match_object: 16 log_text = '"' + match_object.group(1).replace('"', '') + '"' + ',' + '"' + match_object.group(2).replace('"', '') + '"' + ',' + '"' + match_object.group(3).replace('"', '') + '"' + ',' + '"' + match_object.group(4).replace('"', '') + '"' + ',' + '"' + match_object.group(5).replace('"', '') + '"' + ',' + '"' + match_object.group(6).replace('"', '') + '"' + ',' + '"' + match_object.group(7).replace('"', '') + '"' + ',' + '"' + match_object.group(8).replace('"', '') + '"' + ',' + '"' + match_object.group(9).replace('"', '') + '"' + ',' + '"' + match_object.group(10).replace('"', '') + '"' + '\n' 17 fw.write(log_text) 18 line = fr.readline() 19 20fr.close() 21fw.close()

投稿2018/12/06 00:22

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問