출퇴근 정보 추출
Google Map을 활용하여 위치정보 추출하는 Python코드를 만드려 한다.
Google Map 타임 라인 정보는 안드로이드 또는 아이폰이나 상관 없이 자신의 위치 정보를 실시간으로 남길 수 있다.
위치정보를 기록하기 위한 설정으로 Google Map의 설정에서 위치정보를 항상으로 설정하여야 한다.
처리 순서
Google Map기반 출퇴근 정보 처리의 데이터 처리 순서는 다음과 같다.
- Google Map 정보 다운로드 : Google Takeout을 통한 위치 정보 download
- Google 계정 > 데이터 및 개인 정보 보호 > 데이터 다운로드 또는 삭제 > 데이터 다운로드 > 위치 기록(체크) , 다음 단계 진
- 한 번만 내보내기, 내보내기 생성
- takeout-YYYYMMDDTHHmmSSZ-001.zip 형식의 파일 다운로드
- 근무지 Zone 확인 : Google Map 의 위도 / 경도 정보를 통하여 위치 정보가 기록 되어 있으므로 이동 위치 정보가 근무지 Zone에 들어갔는지 나왔는지 확인 하기 위해 필요하다.
- 근무지가 지사나 이사를 통해 여러 군데 위치할 수 있다.
- 출근 일시 : 원하는 시작일자부터 종료 일자까지 근무지 Zone 에 들어간 날자가 바로 출근 증빙 자료가 된다.
- 휴일 또는 휴가 일정 확인 : 휴일이나 휴가 시에는 근무지 Zone에 들어가지 않는다.
구글 정보 Load
아래코드는 Google 위치 정보를 로드하는 코드이다.
g_pos = None with open('./Records.json', 'r') as fp: g_pos = json.load(fp)
휴일, 휴가, 재택, 증빙
근무지 Zone에 있지 않지만 출근으로 확인해야 하는 다른 상황에 대해 처리하는 로직은 다음과 같다.
- update_date_vacances :
date_vacances={ '2017-10-02~2017-10-06':'^추석', '2018-02-15~2018-02-16': '^설', '2018-03-01':'^삼일절', '2018-05-22':'^부처님오신날', '2018-09-24~2018-09-26': '^추석', '2018-02-27~2017-03-06':'출장(계약)', '2018-05-15' :'출근증빙사진(https://photos.google.com/photo/)', '2018-05-16' :'출근증빙사진(https://photos.google.com/photo/)', '2018-06-20~2018-06-24':'출장,---', '2018-07-13~2018-07-18':'휴가', '2018-09-24~2018-09-26':'^추석', '2018-10-30~2018-11-05':'출장,---', '2019-02-04~2019-02-06': '^설', '2019-09-12~2019-09-13':'^추석', '2019-12-25' : '^크리스마스', '2020-03-12':'출장,대전', '2020-03-16':'휴가', '2020-03-18':'출근증빙사진(https://photos.google.com/photo/)', '2020-03-19':'출근증빙사진(https://photos.google.com/photo/)', '2020-03-20':'휴가', '2020-03-24':'출근증빙사진(https://photos.google.com/photo/)', '2020-04-06':'출근증빙사진(https://photos.google.com/photo/)', '2020-04-07':'출근증빙사진(https://photos.google.com/photo/)', '2020-04-09':'출근증빙사진(https://photos.google.com/photo/)', '2020-06-05':'출근증빙사진(https://photos.google.com/photo/)', '2020-08-18~2020-08-21':'재택', '2020-08-24~2022-02-11':'재택', '2022-04-11~2022-04-18':'재택', '2022-07-18~2022-07-29':'휴가', } def update_date_vacances(): for key_vac in date_vacances.keys(): vac_value = date_vacances[key_vac] bHoly= True if vac_value.find('^')>=0 else False if bHoly == True: vac_value = vac_value[1:] if key_vac.find('~') >= 0: vac_dates = key_vac.split('~') date_start=datetime.datetime.strptime(vac_dates[0], '%Y-%m-%d') date_end=datetime.datetime.strptime(vac_dates[1], '%Y-%m-%d') temp_date = date_start while temp_date <= date_end: i_wday = temp_date.weekday() s_temp_date = temp_date.strftime('%Y-%m-%d') if i_wday < 5: update_date(s_temp_date, 'comment', vac_value) if bHoly == True: update_date(s_temp_date, 'is_wday', False) temp_date = temp_date + datetime.timedelta(days=1) else: update_date(key_vac, 'comment', vac_value) if bHoly == True: update_date(key_vac, 'is_wday', False)
일자 처리
아래 코드는 주중 인지 주말인지 예외(휴가등) 일자를 구분하는 함수와 결과를 프린트 함수이다.
- set_date : dict_date_zw_wk 에 중복 되지 않으면 요일정보 기록한다.
- update_date: dict_date_zw_wk에 일자 정보를 업데이트 한다.
- print_date : 결과 출력하는 함수.
s_date_zw_wk_list =[] dict_date_zw_wk ={} def set_date(key_date, i_wday): global s_date_zw_wk_list, dict_date_zw_wk if key_date not in dict_date_zw_wk.keys(): s_date_zw_wk_list.append({'date': key_date}) bool_iswday = True if i_wday<5 else False dict_date_zw_wk[key_date]={'is_wday':bool_iswday} def update_date(key_date, key_data, data_data): global s_date_zw_wk_list, dict_date_zw_wk if key_date in dict_date_zw_wk.keys(): dict_date_zw_wk[key_date][key_data]=data_data def print_date(): idx_gtime_wday_base =1 idx_gtime_wday_t =1 for it_date in s_date_zw_wk_list: temp_date =it_date['date'] b_wday = dict_date_zw_wk[temp_date]['is_wday'] list_keys =dict_date_zw_wk[temp_date].keys() # 데이터기반 총 근무일 일수 G타임기록이 있고, 근무일이면 카운트 (idx_gtime_wday_base) if 'n_day_gmap' in list_keys and b_wday == True: idx_gtime_wday_base +=1 if 'gowork' in list_keys or 'comment' in list_keys: idx_gtime_wday_t +=1 print(f'* 구글 타임라인 정보기반의 총 업무일(명절제외) :{idx_gtime_wday_base:,}일 중 {idx_gtime_wday_t}일 증빙일, 출근(증빙)일율: {(idx_gtime_wday_t*100/idx_gtime_wday_base):3.2f}% ') print() idx = 1 for it_date in s_date_zw_wk_list: temp_date =it_date['date'] b_wday = dict_date_zw_wk[temp_date]['is_wday'] list_keys =dict_date_zw_wk[temp_date].keys() b_target = 'O' if 'n_day_gmap' in list_keys and b_wday == True else 'X' b_gowork = 'O' if ('gowork' in list_keys or 'comment' in list_keys) and b_wday == True else 'X' n_timeline = f"{dict_date_zw_wk[temp_date]['n_day_gmap']}" if 'n_day_gmap' in list_keys else '' sd_datetime_gowork = f"{dict_date_zw_wk[temp_date]['datetime_gowork']}" if 'datetime_gowork' in list_keys else '' s_comment = f"{dict_date_zw_wk[temp_date]['comment']}" if 'comment' in list_keys else '' print(f'{idx} {temp_date} {dict_date_zw_wk[temp_date]}') idx +=1 with open('./google_timeline_gowork.csv', 'a', encoding='utf-8-sig') as fcsv: fcsv.write(f'{temp_date}, {b_target}, {b_gowork}, {sd_datetime_gowork}, {n_timeline}, {s_comment}\n')
구분 처리
아래 코드는 Google Map을 활용하여 위치정보 추출하는 Python코드의 메인 처리 코드이다.
처리순서는 근무시작일, 근무종료일을 설정하고 s_date_zw_wk_list에 구분하여 저장하여 테이블을 준비한다.
Google Map의 위치 정보(json파일 로드)를 순차적으로 읽어 처리를 한다.
다음은 메인 처리 순서 및 소스이다.
- load json : Google 계정의 Takeout으로 생성한 json 파일을 로드한다.
- 근무일 설정 : 출퇴근 정보를 추출할 시작일과 종료일을 설정한다.
- 근무일을 순차적으로 loop돌며 데이터를 정리한다(s_date_zw_wk_list(결과물), dict_date_zw_wk(처리를 위한 db))
- 구글위치정보를 순차적으로 처리하며 근무Zone에 드나드는 시간을 체크한다.
- 결과 출력 : s_date_zw_wk_list(결과물) 정보를 기반으로 출력한다.
- 이 부분을 확장하여 csv나 xls파일로 변환 시킬 수 있다.
import json, datetime # 1. load json g_pos = None with open('./Records.json', 'r') as fp: g_pos = json.load(fp) tot_n_rec = 1 wk_n_rec = 1 nwk_n_rec = 1 # 근무한 총 워크 데이 계산 tot_n_work = 1 wd_n_work = 1 nwd_n_work = 1 s_date_zw_start = '2017-09-01' s_date_zw_end = '2022-07-31' date_zw_start=datetime.datetime.strptime(s_date_zw_start, '%Y-%m-%d') date_zw_end=datetime.datetime.strptime(s_date_zw_end, '%Y-%m-%d') temp_date = date_zw_start while temp_date <= date_zw_end: i_wday = temp_date.weekday() if i_wday < 5: #주중 wd_n_work += 1 else: #주말 nwd_n_work += 1 s_temp_date = temp_date.strftime('%Y-%m-%d') set_date(s_temp_date, i_wday) # print(temp_date, date_zw_end) temp_date = temp_date + datetime.timedelta(days=1) tot_n_work += 1 print(f'* 총 XXXX 근무일: {tot_n_work:,} ({s_date_zw_start} ~ {s_date_zw_end}), 주중:{wd_n_work:,}, 주말:{nwd_n_work:,}') # 휴가정보 로드 update_date_vacances() # google json 데이터 파일 로드 및 처리 sDatetime_Start = None sDatetime_End = None s_date_last_proc = None tot_n_day_gmap = 1 tot_n_wd_day_gmap = 1 tot_n_nwd_day_gmap = 1 n_day_gmap = 1 bool_gowork = False datetime_gowork_start = None # 근무지1 영역 y1_s = 372987220 x1_s = 1270418450 y2_s = 372964600 x2_s = 1270462760 #근무지2 영역 y1_g = 374821150 x1_g = 1268715370 y2_g = 374766480 x2_g = 1268830200 for it_gpos in g_pos['locations']: s_datetime=it_gpos['timestamp'] temp_datetime= datetime.datetime.strptime(s_datetime, '%Y-%m-%dT%H:%M:%S.%fZ') if len(s_datetime) == 24 else datetime.datetime.strptime(s_datetime, '%Y-%m-%dT%H:%M:%SZ') # temp_datetime=s_datetime.strftime('%Y-%m-%dT%H:%M:%S_') # print(temp_datetime) #UTC 시간이므로 +9시간 로컬시간으로 temp_datetime = temp_datetime + datetime.timedelta(hours=9) # print(temp_datetime) s_datetime = temp_datetime.strftime('%Y-%m-%dT%H:%M:%S') if sDatetime_Start is None: sDatetime_Start=s_datetime sDatetime_End=s_datetime #요일별 구하기 list_datetime=s_datetime.split('T') stemp_datetime = f'{list_datetime[0]} {list_datetime[1]}' # temp_datetime = datetime.datetime.strptime(stemp_datetime, '%Y-%m-%d %H:%M:%S') # #UTC 시간이므로 +9시간 로컬시간으로 # temp_datetime = temp_datetime + datetime.timedelta(hours=9) i_wday = temp_datetime.weekday() if i_wday <5: wk_n_rec += 1 temp_lat=it_gpos['latitudeE7'] temp_long=it_gpos['longitudeE7'] temp_area = 's' if list_datetime[0] <= '2017-12-18' else 'g' # 근무지2(g)으로 이사 이전은 근무지1(s) 구 if ( temp_area == 's' and ((y1_s > temp_lat and x1_s < temp_long) and (y2_s < temp_lat and x2_s > temp_long))) \ or \ ( temp_area == 'g' and ((y1_g > temp_lat and x1_g < temp_long) and (y2_g < temp_lat and x2_g > temp_long))): bool_gowork = True if datetime_gowork_start is None: datetime_gowork_start = stemp_datetime update_date(list_datetime[0], 'datetime_gowork', datetime_gowork_start) update_date(s_date_last_proc, 'gowork', True) else: # 주말처리 nwk_n_rec += 1 if (s_date_last_proc is None) or (s_date_last_proc != list_datetime[0]): s_date_last_proc = list_datetime[0] tot_n_day_gmap += 1 if (i_wday < 5): tot_n_wd_day_gmap += 1 else: tot_n_nwd_day_gmap += 1 update_date(s_date_last_proc, 'n_day_gmap', n_day_gmap) # if bool_gowork == True: # update_date(s_date_last_proc, 'gowork', bool_gowork) n_day_gmap = 1 bool_gowork = False datetime_gowork_start = None # print(f'{idx} : {s_datetime}') tot_n_rec+=1 n_day_gmap +=1 print(f'* Google Map record ({sDatetime_Start[:19]} ~ {sDatetime_End[:19]})') print(f'\ttotal: {tot_n_rec:,} work day: {wk_n_rec:,}, weekend: {nwk_n_rec:,}') #XXXX 근무일의 업무가능일 대비, 타임라인에 있는 일수 p_gmap_rec = tot_n_wd_day_gmap*100/wd_n_work print(f'\ttotal day(구글타임라인) : {tot_n_day_gmap:,}, 주중: {tot_n_wd_day_gmap:,}({p_gmap_rec:2.2f}%), 주말: {tot_n_nwd_day_gmap:,}') print_date()
실행 결과는 다음과 같다.
* 총 XXXX 근무일: 1,795 (2017-09-01 ~ 2022-07-31), 주중:1,282, 주말:513 * Google Map record (2017-09-01T09:04:03 ~ 2022-08-01T08:33:19) total: 1,088,013 work day: 792,966, weekend: 295,048 total day(구글타임라인) : 1,423, 주중: 1,013, 주말: 411 * 구글 타임라인 정보기반의 총 업무일(명절제외) :995일 중 903일 증빙일, 출근(증빙)일율: 90.75% 1 2017-09-01 {'is_wday': True, 'datetime_gowork': '2017-09-01 09:05:08', 'n_day_gmap': 1, 'gowork': True} 2 2017-09-02 {'is_wday': False, 'n_day_gmap': 515} 3 2017-09-03 {'is_wday': False, 'n_day_gmap': 506} 4 2017-09-04 {'is_wday': True, 'n_day_gmap': 411, 'datetime_gowork': '2017-09-04 08:53:56', 'gowork': True} 5 2017-09-05 {'is_wday': True, 'n_day_gmap': 660, 'datetime_gowork': '2017-09-05 08:53:31', 'gowork': True} 6 2017-09-06 {'is_wday': True, 'n_day_gmap': 1671, 'datetime_gowork': '2017-09-06 08:48:05', 'gowork': True} 7 2017-09-07 {'is_wday': True, 'n_day_gmap': 2032, 'datetime_gowork': '2017-09-07 08:48:29', 'gowork': True} 8 2017-09-08 {'is_wday': True, 'n_day_gmap': 566, 'datetime_gowork': '2017-09-08 08:40:14', 'gowork': True} 9 2017-09-09 {'is_wday': False, 'n_day_gmap': 706} 10 2017-09-10 {'is_wday': False, 'n_day_gmap': 998} 11 2017-09-11 {'is_wday': True, 'n_day_gmap': 1123, 'datetime_gowork': '2017-09-11 08:53:52', 'gowork': True} 12 2017-09-12 {'is_wday': True, 'n_day_gmap': 1386, 'datetime_gowork': '2017-09-12 07:47:29', 'gowork': True} 13 2017-09-13 {'is_wday': True, 'n_day_gmap': 1208, 'datetime_gowork': '2017-09-13 10:50:25', 'gowork': True} 14 2017-09-14 {'is_wday': True, 'n_day_gmap': 1345, 'datetime_gowork': '2017-09-14 09:03:54', 'gowork': True} 15 2017-09-15 {'is_wday': True, 'n_day_gmap': 1251, 'datetime_gowork': '2017-09-15 08:59:05', 'gowork': True} 16 2017-09-16 {'is_wday': False, 'n_day_gmap': 1259} 17 2017-09-17 {'is_wday': False, 'n_day_gmap': 1905} 18 2017-09-18 {'is_wday': True, 'n_day_gmap': 1277, 'datetime_gowork': '2017-09-18 09:08:34', 'gowork': True} 19 2017-09-19 {'is_wday': True, 'n_day_gmap': 1542, 'datetime_gowork': '2017-09-19 08:59:20', 'gowork': True} 20 2017-09-20 {'is_wday': True, 'n_day_gmap': 1154, 'datetime_gowork': '2017-09-20 08:42:33', 'gowork': True} 21 2017-09-21 {'is_wday': True, 'n_day_gmap': 1388, 'datetime_gowork': '2017-09-21 08:08:41', 'gowork': True} 22 2017-09-22 {'is_wday': True, 'n_day_gmap': 1492, 'datetime_gowork': '2017-09-22 08:47:28', 'gowork': True} . . 249 2018-05-07 {'is_wday': True, 'n_day_gmap': 717} 250 2018-05-08 {'is_wday': True, 'n_day_gmap': 897, 'datetime_gowork': '2018-05-08 09:54:26', 'gowork': True} 251 2018-05-09 {'is_wday': True, 'n_day_gmap': 803, 'datetime_gowork': '2018-05-09 09:41:35', 'gowork': True} 252 2018-05-10 {'is_wday': True, 'n_day_gmap': 999, 'datetime_gowork': '2018-05-10 09:19:47', 'gowork': True} 253 2018-05-11 {'is_wday': True, 'n_day_gmap': 843, 'gowork': True} 254 2018-05-12 {'is_wday': False} 255 2018-05-13 {'is_wday': False} 256 2018-05-14 {'is_wday': True} 257 2018-05-15 {'is_wday': True, 'comment': '출근증빙사진(https://photos.google.com/photo/AF1QipMwd_mKMGz-5V72gWyKtBXo)'} 258 2018-05-16 {'is_wday': True, 'comment': '출근증빙사진(https://photos.google.com/photo/AF1QipPbcsuE3NZIKcCSzFV5IhDR)'} 259 2018-05-17 {'is_wday': True} 260 2018-05-18 {'is_wday': True} 261 2018-05-19 {'is_wday': False} 262 2018-05-20 {'is_wday': False} 263 2018-05-21 {'is_wday': True} 264 2018-05-22 {'is_wday': False, 'comment': '부처님오신날'} 265 2018-05-23 {'is_wday': True} 266 2018-05-24 {'is_wday': True} 267 2018-05-25 {'is_wday': True} 268 2018-05-26 {'is_wday': False} 269 2018-05-27 {'is_wday': False} . . 775 2022-07-11 {'is_wday': True, 'n_day_gmap': 149, 'datetime_gowork': '2022-07-11 13:22:38', 'gowork': True} 1776 2022-07-12 {'is_wday': True, 'n_day_gmap': 316, 'datetime_gowork': '2022-07-12 07:26:03', 'gowork': True} 1777 2022-07-13 {'is_wday': True, 'n_day_gmap': 347} 1778 2022-07-14 {'is_wday': True, 'n_day_gmap': 649, 'datetime_gowork': '2022-07-14 09:10:18', 'gowork': True} 1779 2022-07-15 {'is_wday': True, 'n_day_gmap': 230, 'datetime_gowork': '2022-07-15 08:48:26', 'gowork': True} 1780 2022-07-16 {'is_wday': False, 'n_day_gmap': 319} 1781 2022-07-17 {'is_wday': False, 'n_day_gmap': 239} 1782 2022-07-18 {'is_wday': True, 'comment': '휴가', 'n_day_gmap': 252} 1783 2022-07-19 {'is_wday': True, 'comment': '휴가', 'n_day_gmap': 438} 1784 2022-07-20 {'is_wday': True, 'comment': '휴가', 'n_day_gmap': 295} 1785 2022-07-21 {'is_wday': True, 'comment': '휴가', 'n_day_gmap': 368} 1786 2022-07-22 {'is_wday': True, 'comment': '휴가', 'n_day_gmap': 353} 1787 2022-07-23 {'is_wday': False, 'n_day_gmap': 635} 1788 2022-07-24 {'is_wday': False, 'n_day_gmap': 199} 1789 2022-07-25 {'is_wday': True, 'comment': '휴가', 'n_day_gmap': 197} 1790 2022-07-26 {'is_wday': True, 'comment': '휴가', 'n_day_gmap': 345} 1791 2022-07-27 {'is_wday': True, 'comment': '휴가', 'n_day_gmap': 331} 1792 2022-07-28 {'is_wday': True, 'comment': '휴가', 'n_day_gmap': 461} 1793 2022-07-29 {'is_wday': True, 'comment': '휴가', 'n_day_gmap': 317} 1794 2022-07-30 {'is_wday': False, 'n_day_gmap': 342} 1795 2022-07-31 {'is_wday': False, 'n_day_gmap': 243}
코드의 활용
Google Map을 활용하여 위치정보 추출하는 Python코드를 만들어 보았다.
Google Map 타임라인 정보를 황용하면 특정 Zone에 오간 통계나 실시간 알림을 보내는 프로그램도
만들 수 있겠다 생각해봤다.
감사합니다.
ChatGPT 4 탈옥 (DAN모드) 진입방법
ChatGPT는 다양한 지식을 유려한 문장으로 답변하여 준다. 이러한 방대한 지식도 19금 처럼 파인 튜닝 하며 등급을 정하여 필터링 하고 있다. 이 번 글은 ChatGPT의 19금 필터링을 해소하는 ChatGPT 4 탈옥 (DAN모드) 진입방법 에 대해서 알아보자. ChatGPT의 답변은 강화학습을 통하여 여러가지 불편한 부분(폭력, 공포, 성적 등등)을 필터링 하여 답변하고 있습니다. 이것을 DAN모드라고 한다. 이 DAN은 “Do Anything Now”의 준말입니다. 이는 윤리나 규칙에 어긋나지 않게 필터링 하는 부분을 걷어 낸 어두운 페르소나이다. DAN이 알려진 후, 폭발적인 사용자 접속으로 더욱 활성화 되었으며, Open AI는 DAN 시도를 방어하는 노력이 무색하게 새로운 DAN이 등장하는 등 숨바꼭질을 하고 있는 상황입니다. ChatGPT 4 탈옥 (DAN모드) 진입방법 ...
1 thought on “Google Map을 활용하여 위치정보 추출하는 Python코드”