[python] 파이썬 웹 크롤링(7): 데이터 클리닝

업데이트:

파이썬 웹 크롤링(7): 데이터 클리닝

본 포스팅은 Web Scraping with Python by Ryan Mitchell을 참고하였습니다.

참고 링크

Chapter 7: 데이터 클리닝

7.1 코드 내에서 클리닝하기

아래 코드는 위키피디아 문서에서 2-grams의 리스트를 찾아 리턴하는 코드 입니다. 언어학에서 n-grma이란 n개의 단어 시퀀스를 의미합니다.

from urllib.request import urlopen
from bs4 import BeautifulSoup

def ngrams(input, n):
  input = input.split(' ')
  output = []
  for i in range(len(input)-n+1):
    output.append(input[i:i+n])
  return output

html = urlopen("http://en.wikipedia.org/wiki/Python_(programming_language)")
bsObj = BeautifulSoup(html)
content = bsObj.find("div", {"id":"mw-content-text"}).get_text()
ngrams = ngrams(content, 2)
print(ngrams)
print("2-grams count is: "+str(len(ngrams)))

ngrams 함수는 인풋 문자를 가지고 단어의 시퀀스를 공백을 기준으로 분리합니다. 그리고 n-grma을 더합니다. 위 코드는 아래와 같은 결과를 보여주지만

['of', 'free'], ['free', 'and'], ['and', 'open-source'], ['open-source', 'software']

다음과 같은 쓸데없는 것도 많이 나옵니다.

['software\nOutline\nSPDX\n\n\n\n\n\n\n\n\nOperating', 'system\nfamilies\n\n\n\n
AROS\nBSD\nDarwin\neCos\nFreeDOS\nGNU\nHaiku\nInferno\nLinux\nMach\nMINIX\nOpenS
olaris\nPlan'], ['system\nfamilies\n\n\n\nAROS\nBSD\nDarwin\neCos\nFreeDOS\nGNU\
nHaiku\nInferno\nLinux\nMach\nMINIX\nOpenSolaris\nPlan', '9\nReactOS\nTUD:OS\n\n
\n\n\n\n\n\n\nDevelopment\n\n\n\nBasic'], ['9\nReactOS\nTUD:OS\n\n\n\n\n\n\n\n\n
Development\n\n\n\nBasic', 'For']

아래 코드와 같이 정규표현식을 이용하면 유니코드 문자를 제거할 수 있습니다.

def ngrams(input, n):
  content = re.sub('\n+', " ", content)
  content = re.sub(' +', " ", content)
  content = bytes(content, "UTF-8")
  content = content.decode("ascii", "ignore")
  print(content)
  input = input.split(' ')
  output = []
  for i in range(len(input)-n+1):
    output.append(input[i:i+n])
  return output

이는 결과를 개선해주지만 여전히 이슈가 남아있습니다.

['Pythoneers.[43][44]', 'Syntax'], ['7', '/'], ['/', '3'], ['3', '=='], ['==', '2']

이를 해결하기 위해 좀 더 여러가지 룰이 필요합니다.

  • i와 a를 제외한 오직 하나로 구성된 문자는 버립니다.
  • 위키피디아의 인용 마크는 버립니다.
  • 마침표는 버립니다.

자, 이제 cleaning task가 더 길어집니다.

from urllib.request import urlopen
from bs4 import BeautifulSoup
import re
import string

def cleanInput(input):
  input = re.sub('\n+', " ", input)
  input = re.sub('\[[0-9]*\]', "", input)
  input = re.sub(' +', " ", input)
  input = bytes(input, "UTF-8")
  input = input.decode("ascii", "ignore")
  cleanInput = []
  input = input.split(' ')
  for item in input:
    item = item.strip(string.punctuation)
    if len(item) > 1 or (item.lower() == 'a' or item.lower() == 'i'):
      cleanInput.append(item)
  return cleanInput

def ngrams(input, n):
  input = cleanInput(input)
  output = []
  for i in range(len(input)-n+1):
    output.append(input[i:i+n])
  return output
['Linux', 'Foundation'], ['Foundation', 'Mozilla'], ['Mozilla', 'Foundation'], 
['Foundation', 'Open'], ['Open', 'Knowledge'], ['Knowledge', 'Foundation'], 
['Foundation', 'Open'], ['Open', 'Source']

7.1.1 Data Normalization

데이터 표준화란 데이터의 형식을 맞추는 것을 말합니다. 예를 들어, 전화번호를 입력한다고 하면, (555) 123-4567 혹은 555.123.4567과 같이 똑같은 형태로 입력하는 것입니다. 전화번호의 경우 사람마다 입력하는 방식이 다르기 때문입니다.