円滑なグループ運営において、活動していない参加者を退会させたい場合があります。
最後に活動した日付を取得できるツールを探しましたが、見当たらなかったので自作してみました。
グループのトーク履歴をもとに最後に活動した日付を一覧化しています。
ただし、トーク履歴に残るのは「メッセージの送信」「スタンプの利用」「写真・動画・ファイルの添付」「通話の開始」「ノートの投稿」であり、グループ通話に途中から参加してきた人はトーク履歴に残らないので注意が必要です。
手順
- スマホからトーク履歴(*.txt)を出力し、パソコンに送ります。パソコン版のLINEでもトーク履歴は取得できますが、遡れる日数に限りがあるのでスマホから出力した方がいいです。
- Pythonを公式サイトからパソコンにインストールします。
- Windows terminalかCommand Promptを開き、pandasをインストールします。
pip install pandas
- .pyファイルを作り、メモ帳か何かで開いて下に記載しているコードを貼り付けて保存します。
- .pyファイルをダブルクリックして実行すると、ファイル選択画面が表示されるのでトーク履歴のファイルを選択します。
- 実行が完了したら以下のcsvファイルとtxtファイルが出力されます。
・トーク履歴を分析しやすい状態に加工したcsvファイル
・参加者ごとの最終活動日一覧が記載されているtxtファイル(降順、メモ帳で開くと対応していない記号/顔文字が文字化けするのでVSCode等で開いて中身をテキストコピーするとよいです)
ソースコード
import re
import csv
import datetime
import os
from tkinter import filedialog
import pandas as pd
class Data:
def __init__(self, year, month, day, hour, minute, person, payload, flag):
self.year = year
self.month = month
self.day = day
self.hour = hour
self.minute = minute
self.person = person
self.payload = payload
self.flag = flag
# Set regular expression format
date_pattern = r"20\d{2}/\d{1,2}/\d{1,2}\((月|火|水|木|金|土|日)\)"
message_pattern = r"\d{1,2}:\d{2}\t.*\t.*"
photo_pattern = r"\d{1,2}:\d{2}\t.*\t\[写真]"
sticker_pattern = r"\d{1,2}:\d{2}\t.*\t\[スタンプ]"
video_pattern = r"\d{1,2}:\d{2}\t.*\t\[動画]"
file_pattern = r"\d{1,2}:\d{2}\t.*\t\[ファイル]"
album_build_pattern = r"\d{1,2}:\d{2}\t.*\t\アルバムを作成しました"
note_pattern = r"\d{1,2}:\d{2}\t.*\t.*\がノートに投稿しました"
call_start_pattern = r"\d{1,2}:\d{2}\t.*\t\グループ音声通話が開始されました"
call_end_pattern = r"\d{1,2}:\d{2}\t.*\t\グループ通話が終了しました"
exit_pattern = r"\d{1,2}:\d{2}\t.*\が退出しました"
# Get file path
file_type = [("テキストファイル", "*.txt")]
current_path = os.getcwd()
file_path = filedialog.askopenfilename(filetypes=file_type, initialdir=current_path)
date_ = datetime.datetime.now()
logs = []
exit_list = {}
# Load file
with open(file_path, "r", encoding="utf-8") as f:
log_text = f.read()
# Read file
for i, log in enumerate(log_text.splitlines()[3:]):
print(f"{log} : ", end="")
if log == "":
print("no data")
continue
if re.match(date_pattern, log):
print("day data")
date_stamp = log.replace("/", ",")[: log.find("(")]
date_ = datetime.datetime.strptime(date_stamp, "%Y,%m,%d")
elif re.match(photo_pattern, log):
print("photo data")
splited_log = re.split("\t", log)
logs.append(
Data(
date_.year,
date_.month,
date_.day,
splited_log[0][0:2],
splited_log[0][3:5],
splited_log[1],
"",
"photo",
)
)
elif re.match(video_pattern, log):
print("video data")
splited_log = re.split("\t", log)
logs.append(
Data(
date_.year,
date_.month,
date_.day,
splited_log[0][0:2],
splited_log[0][3:5],
splited_log[1],
"",
"video",
)
)
elif re.match(sticker_pattern, log):
print("sticker data")
splited_log = re.split("\t", log)
logs.append(
Data(
date_.year,
date_.month,
date_.day,
splited_log[0][0:2],
splited_log[0][3:5],
splited_log[1],
"",
"sticker",
)
)
elif re.match(call_start_pattern, log):
print("call start data")
splited_log = re.split("\t", log)
logs.append(
Data(
date_.year,
date_.month,
date_.day,
splited_log[0][0:2],
splited_log[0][3:5],
splited_log[1],
"",
"call start",
)
)
elif re.match(call_end_pattern, log):
print("call end data")
splited_log = re.split("\t", log)
logs.append(
Data(
date_.year,
date_.month,
date_.day,
splited_log[0][0:2],
splited_log[0][3:5],
splited_log[1],
"",
"call end",
)
)
elif re.match(file_pattern, log):
print("file data")
splited_log = re.split("\t", log)
logs.append(
Data(
date_.year,
date_.month,
date_.day,
splited_log[0][0:2],
splited_log[0][3:5],
"",
"",
"file",
)
)
elif re.match(album_build_pattern, log):
print("create album data")
splited_log = re.split("\t", log)
logs.append(
Data(
date_.year,
date_.month,
date_.day,
splited_log[0][0:2],
splited_log[0][3:5],
"",
"",
"album create",
)
)
elif re.match(note_pattern, log):
print("note data")
splited_log = re.split("\t", log)
logs.append(
Data(
date_.year,
date_.month,
date_.day,
splited_log[0][0:2],
splited_log[0][3:5],
"",
"",
"note",
)
)
elif re.match(message_pattern, log):
print("message data")
splited_log = re.split("\t", log)
logs.append(
Data(
date_.year,
date_.month,
date_.day,
splited_log[0][0:2],
splited_log[0][3:5],
splited_log[1],
splited_log[2],
"message",
)
)
# tabがない場合=メッセージが改行されて続いている場合
elif len(re.split("\t", log)) == 1:
splited_log = re.split("\t", log)
print("returned data")
logs[-1].payload += log
elif re.match(exit_pattern, log):
print("exit")
splited_log = re.split("\t", log)
logs.append(
Data(
date_.year,
date_.month,
date_.day,
splited_log[0][0:2],
splited_log[0][3:5],
splited_log[1][: splited_log[1].find("が退出")],
"",
"exit",
)
)
exit_list[splited_log[1][: splited_log[1].find("が退出")]] = 0
else:
pass
# print("\nNo classified data\n")
# Save as csv
with open("line.csv", "w", encoding="utf-8", newline="") as f:
for content in logs:
writer = csv.writer(f)
writer.writerow(
[
str(content.year),
str(content.month),
str(content.day),
str(content.hour),
str(content.minute),
str(content.person),
str(content.payload),
str(content.flag),
]
)
dic = {}
for content in logs:
if str(content.person) not in exit_list:
date_str = (
str(content.year)
+ str(f"{int(content.month):02}")
+ str(f"{int(content.day):02}")
)
dic[str(content.person)] = datetime.datetime.strptime(date_str, "%Y%m%d")
df = pd.DataFrame(list(dic.items()), columns=["Name", "Date"])
df.sort_values(by="Date", ascending=False, inplace=True)
df.to_csv("date.txt", encoding="utf_8_sig", index=False)