이 단어 추출 도구의 소스코드는 내가 Python으로 만든 쓸만한 도구중에 거의 첫번째로 작성한 코드이다. 아직 손에 익지 않았을 때 필요한 기능을 구현하는데에만 중점을 두다 보니 Python의 장점인 간결함과는 거리가 멀다. Python 스타일이라기 보다는 C 스타일에 가깝다.
텍스트 추출 결과, 단어 추출 결과를 별도의 class로 작성할까 하다가, 시험삼아 pandas의 DataFrame을 사용해 봤는데 생각보다 잘 동작해서 그냥 DataFrame을 사용했다. 덤으로 DataFrame에서 제공하는 groupby, to_excel 함수를 사용하여 구현하는데 시간을 많이 줄였다.
“2.1.2. 형태소 분석기 선택: Mecab“에서 언급했듯이, 단어 추출에 자연어 형태소 분석기 Mecab을 사용했다. 다른 형태소 분석기를 사용하려면 get_word_list 함수를 고쳐 사용하기 바란다.
본문에 삽입한 코드의 행 번호는 github에 업로드한 소스코드의 행번호와 같게 설정하였고, 주석도 가급적 제외하지 않고 모두 포함시켰다.
4.1.2.단어 추출 도구 함수 호출 관계
단어 추출 도구 함수 호출 관계
함수 전반적인 호출 관계는 위 도식과 아래 내용과 같이 요약할 수 있다.
main 함수에서 get_file_text 함수를 호출해서 각 파일로부터 행단위, 문단(paragraph) 단위의 텍스트를 추출한다.
get_file_text 함수 내에서 파일 확장자에 따라 get_doc_text, get_ppt_text, get_txt_text, get_db_comment_text 함수를 호출한다.
get_hwp_text, get_pdf_text 함수는 아직 구현하지 않았고 나중에 필요한 시점에 구현할 예정이다. (혹시 구현한 경험이 있거나 구현한 코드를 알고 있다면 댓글로 남겨주기 바란다.)
get_file_text 함수 실행결과를 get_word_list 함수에 전달하여 단어 후보군을 추출한다.
get_file_text 함수와 get_word_list 함수는 multiprocessing으로 처리한다.
make_word_cloud 함수를 호출하여 word cloud 이미지를 생성한다.
4.2. main 함수
4.2.1. argument parsing
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
defmain():
"""
지정한 경로 하위 폴더의 File들에서 Text를 추출하고 각 Text의 명사를 추출하여 엑셀파일로 저장
:return: 없음
"""
# region Args Parse & Usage set-up -------------------------------------------------------------
print('[%s] Finish Get File List.' % get_current_datetime())
print('--- File List ---')
print('\n'.join(file_list))
if db_comment_file isnotNone:
file_list.append(db_comment_file)
file_list = []
if in_path is not None and in_path.strip() != '':
print('[%s] Start Get File List...' % get_current_datetime())
in_abspath = os.path.abspath(in_path) # os.path.abspath('.') + '\\test_files'
file_types = ('.ppt', '.pptx', '.doc', '.docx', '.txt')
for root, dir, files in os.walk(in_abspath):
for file in sorted(files):
# 제외할 파일
if file.startswith('~'):
continue
# 포함할 파일
if file.endswith(file_types):
file_list.append(root + '\\' + file)
print('[%s] Finish Get File List.' % get_current_datetime())
print('--- File List ---')
print('\n'.join(file_list))
if db_comment_file is not None:
file_list.append(db_comment_file)
file_list = []
if in_path is not None and in_path.strip() != '':
print('[%s] Start Get File List...' % get_current_datetime())
in_abspath = os.path.abspath(in_path) # os.path.abspath('.') + '\\test_files'
file_types = ('.ppt', '.pptx', '.doc', '.docx', '.txt')
for root, dir, files in os.walk(in_abspath):
for file in sorted(files):
# 제외할 파일
if file.startswith('~'):
continue
# 포함할 파일
if file.endswith(file_types):
file_list.append(root + '\\' + file)
print('[%s] Finish Get File List.' % get_current_datetime())
print('--- File List ---')
print('\n'.join(file_list))
if db_comment_file is not None:
file_list.append(db_comment_file)
436행: 처리 대상 파일에 해당하는 파일 확장자 목록을 정의한다.
437~444행: 실행시 지정한 argument중 in_path 하위의 폴더 전체를 재귀 탐색하면서 각 파일이 대상 파일인지 판단하고 대상 파일이면 file_list에 추가한다.
451~452행: 실행시 지정한 argument중 db_comment_file이 있으면 file_list에 추가한다.
4.2.3. Multi processing으로 get_file_text 실행
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
print('[%s] Start Get File Text...' % get_current_datetime())
with multiprocessing.Pool(processes=multi_process_count)as pool:
print('[%s] Finish Get File Text.' % get_current_datetime())
# 여기까지 text 추출완료. 아래에 단어 추출 시작
print('[%s] Start Get File Text...' % get_current_datetime())
with multiprocessing.Pool(processes=multi_process_count) as pool:
mp_text_result = pool.map(get_file_text, file_list)
df_text = pd.concat(mp_text_result, ignore_index=True)
print('[%s] Finish Get File Text.' % get_current_datetime())
# 여기까지 text 추출완료. 아래에 단어 추출 시작
print('[%s] Start Get File Text...' % get_current_datetime())
with multiprocessing.Pool(processes=multi_process_count) as pool:
mp_text_result = pool.map(get_file_text, file_list)
df_text = pd.concat(mp_text_result, ignore_index=True)
print('[%s] Finish Get File Text.' % get_current_datetime())
# 여기까지 text 추출완료. 아래에 단어 추출 시작
455~456행: 실행시 지정한 multi_process_count 만큼 process를 실행하여 각 process에서 file_lsit를 입력으로 get_file_text 함수를 실행하고 그 결과를 mp_text_result에 담는다.
457행: DataFrame의 list 형태인 mp_text_result의 각 list item을 합쳐서(concat) 하나의 DataFrame인 df_text로 만든다.
4.2.4. Multi processing으로 get_word_list 실행
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
# ---------- 병렬 실행 ----------
print('[%s] Start Get Word from File Text...' % get_current_datetime())
print('[%s] Finish Get Word from File Text.' % get_current_datetime())
# ------------------------------
# ---------- 병렬 실행 ----------
print('[%s] Start Get Word from File Text...' % get_current_datetime())
df_text_split = np.array_split(df_text, multi_process_count)
# mp_result = []
with multiprocessing.Pool(processes=multi_process_count) as pool:
mp_result = pool.map(get_word_list, df_text_split)
df_result = pd.concat(mp_result, ignore_index=True)
if 'DB' not in df_result.columns:
df_result['DB'] = ''
df_result['Schema'] = ''
df_result['Table'] = ''
df_result['Column'] = ''
print('[%s] Finish Get Word from File Text.' % get_current_datetime())
# ------------------------------
# ---------- 병렬 실행 ----------
print('[%s] Start Get Word from File Text...' % get_current_datetime())
df_text_split = np.array_split(df_text, multi_process_count)
# mp_result = []
with multiprocessing.Pool(processes=multi_process_count) as pool:
mp_result = pool.map(get_word_list, df_text_split)
df_result = pd.concat(mp_result, ignore_index=True)
if 'DB' not in df_result.columns:
df_result['DB'] = ''
df_result['Schema'] = ''
df_result['Table'] = ''
df_result['Column'] = ''
print('[%s] Finish Get Word from File Text.' % get_current_datetime())
# ------------------------------
예를 들어, df_text에 1000개의 행이 있고 multi_process_count가 4인 경우라면, 각각 250개 행을 가진 4개의 DataFrame이 만들어지고 이 4개의 DataFrame을 item으로 가지는 df_text_split 변수가 만들어진다.
465~466행: 실행시 지정한 multi_process_count 만큼 process를 실행하여 각 process에서 df_text_split을 입력으로 get_word_list 함수를 실행하고 그 결과를 mp_result에 담는다.
468행: DataFrame의 list 형태인 mp_result의 각 list item을 합쳐서(concat) 하나의 DataFrame인 df_result로 만든다.
469~473행: df_result.columns에 ‘DB’가 없는 경우, 다시 말하여 db_comment_file 이 지정되지 않은 경우 후속 처리 로직을 단순화하고 오류를 방지하기 위하여 ‘DB’, ‘Schema’, ‘Table’, ‘Column’의 이름을 가진 열(column)을 빈 값으로 추가한다.
4.2.5. 단어 빈도를 구하고 make_word_cloud 실행
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
print('[%s] Start Get Word Frequency...' % get_current_datetime())
안녕하세요
올려주신 단어 추출 도구 소드코드와 ‘pdfplumber’를 활용하여 get_pdf_text 기능 만들어보았는데
댓글이나 메일로 보여드려도 될까요?
안녕하세요!
올려주신 단어 추출 도구 소스 코드를 활용하여 get_pdf_text 함수 구현해보았습니다.
기존 코드 중 파일 확장자 관련 부분에 pdf 추가하고 get_pdf_tex 함수 추가했을 때 작동하는 것은 확인했습니다.
수정해야 할 부분 알려주시면 처리하겠습니다.
pip install pdfplumber가 필요합니다.
import pdfplumber
def get_pdf_text(file_name) -> DataFrame:
start_time = time.time()
print(‘\r\nget_txt_text: ‘ + file_name)
df_text = pd.DataFrame()
pdf_file = pdfplumber.open(file_name)
page = 0
for pg in pdf_file.pages:
texts = pg.extract_text()
page += 1
for text in texts.split():
if text.strip() != ”:
sr_text = Series([file_name, ‘pdf’, page, text, f'{file_name}:{page}:{text}’],
index=[‘FileName’, ‘FileType’, ‘Page’, ‘Text’, ‘Source’])
df_text = df_text.append(sr_text, ignore_index=True)
print(‘text count: %s’ % str(df_text.shape[0]))
print(‘page count: %d’ % page)
pdf_file.close()
end_time = time.time()
elapsed_time = str(datetime.timedelta(seconds=end_time – start_time))
print(‘[pid:%d] get_pdf_text elapsed time: %s’ % (os.getpid(), elapsed_time))
return df_text
get_pdf_text 함수 소스코드 공유해 주셔서 감사합니다.
작성해주신 소스코드는 들여쓰기가 되어 있는데, WordPress 댓글에서 들여쓰기가 표시되지 않아 보기가 조금 불편하네요.
들여쓰기가 보여지도록 설정해 보겠습니다.
들여쓰기 보이게 설정하실 때 혹시 들여쓰기 되어있는 원본 소스코드 필요하시면 다시 올려드리겠습니다.