전의 코드를 확장하여 모든 xml 파일을 돌면서 본문의 표 안에 있는 데이터를 추출한다. 이때 표는 column 방향으로 2칸 혹은 3칸으로 split된 표만 포함한다. 3칸으로 된 표 중에 필요한 데이터는 많이 없기 때문에 직접 몇 개의 xml 파일을 뽑았다. 코드는 아래와 같다.
import xml.etree.ElementTree as ET
import os
import csv
mStr0 = [] # 개정 전 약관 텍스트
mStr1 = [] # 개정 후 약관 텍스트
mStr2 = [] # 첫번째 칸 문자열
mStr3 = [] # 두번째 칸 문자열
mStr4 = [] # 세번째 칸 문자열
mFileList1 = []
mFileList2 = []
mFileList3 = [
'/Users/jason/Test/code/test1/term210.xml',
'/Users/jason/Test/code/test1/term55.xml',
'/Users/jason/Test/code/test1/term198.xml',
'/Users/jason/Test/code/test1/term79.xml',
'/Users/jason/Test/code/test1/term259.xml',
'/Users/jason/Test/code/test1/term23.xml',
'/Users/jason/Test/code/test1/term36.xml',
'/Users/jason/Test/code/test1/term110.xml',
'/Users/jason/Test/code/test1/term26.xml',
'/Users/jason/Test/code/test1/term300.xml',
'/Users/jason/Test/code/test1/term319.xml',
'/Users/jason/Test/code/test1/term297.xml',
'/Users/jason/Test/code/test1/term282.xml',
'/Users/jason/Test/code/test1/term186.xml',
'/Users/jason/Test/code/test1/term190.xml',
'/Users/jason/Test/code/test1/term64.xml',
'/Users/jason/Test/code/test1/term154.xml',
'/Users/jason/Test/code/test1/term169.xml',
'/Users/jason/Test/code/test1/term98.xml'
]
# 개정 전 약관과 개정 후 약관을 분류하여 mStr0과 mStr1에 저장하는 함수
def appendString(order, z, mFile):
mString = ''
for r in z.iter('Text'):
mString = mString + r.text
if order == 0:
mStr0.append(mString)
if order == 1:
mStr1.append(mString)
mFileList1.append(mFile)
if order == 2:
mStr2.append(mString)
if order == 3:
mStr3.append(mString)
if order == 4:
mStr4.append(mString)
mFileList2.append(mFile)
# 해당 파일의 데이터를 추출하여 string list에 append하는 함수
def makeDataList(mFile):
tree = ET.parse(mFile)
root = tree.getroot()
lineseg = [lineseg[0] for lineseg in root[2][0][6]]
tableBody = []
#2칸으로 나뉜 모든 테이블 노드 tableBody list에 저장하기
for x in lineseg:
if x.find('TableControl') != None: #모든 table에 접근
if x.find('TableControl').find('TableBody').attrib['cols'] == '2': #2개의 그룹으로 나뉜 table
tableBody.append(x.find('TableControl').find('TableBody'))
for x in tableBody:
for y in x.findall('TableRow'):
for z in y.findall('TableCell'):
if z.attrib['col'] == '0' and z.attrib['colspan'] == '1':
if z.attrib['rowspan'] == '1':
appendString(0, z, mFile)
else: #padding
for i in range(int(z.attrib['rowspan'])):
appendString(0, z, mFile)
if z.attrib['col'] == '1' and z.attrib['colspan'] == '1':
if z.attrib['rowspan'] == '1':
appendString(1, z, mFile)
else: #padding
for i in range(int(z.attrib['rowspan'])):
appendString(1, z, mFile)
def makeDataList3(mFile):
tree = ET.parse(mFile)
root = tree.getroot()
lineseg = [lineseg[0] for lineseg in root[2][0][6]]
tableBody = []
# 3칸으로 나뉜 모든 테이블 노드 tableBody list에 저장하기
for x in lineseg:
if x.find('TableControl') != None: #모든 table에 접근
if x.find('TableControl').find('TableBody').attrib['cols'] == '3': #3개의 그룹으로 나뉜 table
tableBody.append(x.find('TableControl').find('TableBody'))
for x in tableBody:
for y in x.findall('TableRow'):
for z in y.findall('TableCell'):
if z.attrib['col'] == '0' and z.attrib['colspan'] == '1':
if z.attrib['rowspan'] == '1':
appendString(2, z, mFile)
else: #padding
for i in range(int(z.attrib['rowspan'])):
appendString(2, z, mFile)
if z.attrib['col'] == '1' and z.attrib['colspan'] == '1':
if z.attrib['rowspan'] == '1':
appendString(3, z, mFile)
else: #padding
for i in range(int(z.attrib['rowspan'])):
appendString(3, z, mFile)
if z.attrib['col'] == '2' and z.attrib['colspan'] == '1':
if z.attrib['rowspan'] == '1':
appendString(4, z, mFile)
else: #padding
for i in range(int(z.attrib['rowspan'])):
appendString(4, z, mFile)
#main
path = '/Users/jason/Test/code/test1'
res = []
for root, dirs, files in os.walk(path):
rootpath = os.path.join(os.path.abspath(path), root)
for file in files:
filepath = os.path.join(rootpath, file)
res.append(filepath)
for mFile in res:
try:
makeDataList(mFile)
except:
continue
for mFile in mFileList3:
makeDataList3(mFile)
for v in [mStr0, mStr1, mStr2, mStr3, mStr4]:
print(len(v))
#2
with open('test.csv', 'w', newline='') as f:
writer = csv.writer(f)
writer.writerow(['번호', '수정 전 약관', '수정 후 약관'])
for i in range(len(mStr0)):
writer.writerow([i, mStr0[i], mStr1[i]])
#3
with open('test3.csv', 'w', newline='') as f:
writer = csv.writer(f)
writer.writerow(['번호', '약관1', '약관2', '약관3'])
for i in range(len(mStr2)):
writer.writerow([i, mStr2[i], mStr3[i], mStr4[i]])
2칸으로 된 표와 3칸으로 된 표를 tableBody에 저장하여 table의 attribute 중 col, row, colspan, rowspan을 이용하여 필요한 데이터들을 mStr 리스트에 appending한다. 그리고 저장이 완료되면 csv 파일로 변환하여 저장한다. 결과는 아래와 같다.
데이터 숫자 출력.
2 splited data
3 splited data
이제 여기서 pandas를 사용하여 필요한 데이터는 남기고 필요 없는 데이터는 삭제하는 과정을 진행할 것이다. 3 splited data도 2 splited로 변경해야 한다.
import numpy as np
import pandas as pd
df1 = pd.read_csv('/Users/jason/Test/code/test.csv').fillna('')
df3 = pd.read_csv('/Users/jason/Test/code/test3.csv').fillna('')
df1 = df1.drop_duplicates(['수정 전 약관', '수정 후 약관'], keep = 'first')
mIndex = df1[ (df1['수정 전 약관'].str.len() < 30) & (df1['수정 후 약관'].str.len() < 30) ].index
df1.drop(mIndex)
df1.to_csv('/Users/jason/Test/code/testlen1.csv', sep=',', encoding='utf-8')
df3 = df3.drop_duplicates(['약관1', '약관2', '약관3'], keep = 'first')
mIndex = df3[ (df3['약관1'].str.len() < 30) & (df3['약관2'].str.len() < 30) & (df3['약관3'].str.len() < 30) ].index
df3.drop(mIndex)
df3.to_csv('/Users/jason/Test/code/testlen3.csv', sep=',', encoding='utf-8')
df1 = pd.read_csv('/Users/jason/Test/code/testlen1.csv').fillna('')
df3 = pd.read_csv('/Users/jason/Test/code/testlen3.csv').fillna('')
mDF = pd.concat([df1, df3])
mDF.to_csv('/Users/jason/Test/code/mTermData.csv', sep=',', encoding='utf-8')
mDF["Term1"] = mDF["Term1"].str.replace('ㅇ','',regex=True)
mDF["Term2"] = mDF["Term2"].str.replace('ㅇ','',regex=True)
mDF["Term1"] = mDF["Term1"].str.replace(r'[^ㄱ-ㅎㅏ-ㅣ가-힣]', repl=r'', regex=True)
mDF["Term2"] = mDF["Term2"].str.replace(r'[^ㄱ-ㅎㅏ-ㅣ가-힣]', repl=r'', regex=True)
mDF.to_csv('/Users/jason/Test/code/mTermData2.csv', sep=',', encoding='utf-8')
데이터를 직접 정리하여 병합했다.
이제 띄어쓰기 검사기를 사용하고 토큰화를 진행할 것이다.
'프로젝트 > Project1' 카테고리의 다른 글
Toy Project 1 (8) - Text preprocessing - Tokenization (0) | 2021.10.09 |
---|---|
Toy Project 1 (7) - M1 mac 설정하기(삽질) (0) | 2021.09.21 |
Toy Project 1 (5) - HWP XML PARSING하기 1 (0) | 2021.06.11 |
Toy Project 1 (4) - HWP파일 XML로 바꾸기 (0) | 2021.05.30 |
Toy Project 1 (3) - CONDA PATH 설정하기 (0) | 2021.05.29 |