기본 콘텐츠로 건너뛰기

방송대 오픈소스기반데이터분석 13강: 반정형 데이터 수집과 텍스트 분석 파이프라인

오픈소스기반데이터분석 13강 - 반정형 데이터 분석

방송대 오픈소스기반데이터분석 13강: 반정형 데이터 수집과 텍스트 분석 파이프라인

웹 페이지에서 게시글 제목을 보았다고 해서 곧바로 분석할 수 있는 것은 아니다. 브라우저가 보여 주는 화면을 수집하고, 문서 구조에서 필요한 텍스트를 골라내고, 언어 단위로 정제한 뒤에야 키워드와 분류 결과를 해석할 수 있다. 이 글은 그 변환 과정을 단계별로 추적하며 도구 선택과 오류 점검 기준을 함께 설명한다.

화면의 문장이 분석용 열이 되기까지 네 번 변환된다

학과 게시판의 글 제목을 분석한다고 가정해 보자. 사람이 보는 브라우저 화면에는 제목, 작성일, 메뉴와 버튼이 함께 있다. 분석 프로그램은 그중 제목만 자동으로 구분하지 못한다. 먼저 웹 페이지에 접근하고, HTML 구조에서 제목 요소를 선택하고, 불필요한 기호와 기능어를 정리한 뒤, 키워드 집계나 분류를 수행해야 한다.

변환 단계입력출력먼저 확인할 실패 신호
수집웹 주소와 사용자 동작HTML 문서로그인 화면, 로딩 전 빈 목록, 접근 실패
구조 추출HTML 요소 트리제목 문자열 목록선택 결과 0개, 메뉴 문구 혼입, 중복 추출
텍스트 정제원시 제목 문자열분석 가능한 토큰의미 있는 기호 삭제, 공백 결합, 불용어 잔존
분석정제된 토큰·문장빈도, 분류, 시각화범주 밖 출력, 희귀어 과대해석, 검증 없는 결론

판단 핵심: 오류를 발견하면 마지막 분석 단계만 의심하지 않는다. 누락은 수집에서, 엉뚱한 문구는 구조 추출에서, 단어 손실은 정제에서 생겼을 수 있으므로 출력에서 입력 방향으로 한 단계씩 거슬러 올라간다.

반정형 데이터는 표가 없다는 뜻이 아니라 구조가 문서 안에 있다는 뜻이다

반정형 데이터는 행과 열의 스키마가 고정된 정형 데이터와 달리, 태그·키·계층 같은 자체 표식을 통해 구조를 나타내는 데이터다. HTML, XML, JSON이 대표적인 예다. 형식마다 표시는 다르지만 “어디가 제목이고 어떤 항목이 서로 묶이는가”를 해석할 단서가 존재한다는 공통점이 있다.

웹 페이지에서는 HTML이 내용의 구조를, CSS가 표현 방식을, JavaScript가 동작을 담당한다. 분석자가 제목을 추출할 때 주로 읽는 것은 HTML 구조다. 글자 색이나 위치가 아니라 태그, 속성, 부모·자식 관계를 기준으로 선택해야 화면 디자인이 조금 바뀌어도 추출 논리를 설명할 수 있다.

다음은 학습을 위해 직접 구성한 최소 HTML이다. 두 게시글은 같은 post 계열에 속하고, 제목은 title 클래스를 가진 링크에 들어 있다.

<ul id="board">
  <li class="post notice">
    <a class="title" href="/101">시험 일정 안내</a>
  </li>
  <li class="post">
    <a class="title" href="/102">스터디원 모집</a>
  </li>
</ul>

이 문서는 완전한 표가 아니지만, ul → li → a라는 계층과 id·class 속성이 있다. 구조 추출은 바로 이 규칙을 분석용 열로 번역하는 작업이다.

수집 도구는 페이지가 만들어지는 시점에 맞춰 고른다

웹 스크래핑은 페이지를 내려받는 데서 끝나지 않고 원하는 정보를 정확히 추출하는 전 과정을 뜻한다. 먼저 필요한 내용이 최초 HTML 응답에 들어 있는지, 브라우저에서 JavaScript가 실행된 뒤 나타나는지 확인해야 한다. 후자이거나 로그인·클릭·입력이 필요한 경우에는 실제 브라우저 동작을 자동화하는 Selenium이 적합하다.

관찰한 조건적합한 접근이유
응답 HTML에 목표 요소가 이미 존재문서를 직접 내려받아 파싱브라우저 동작을 재현할 필요가 없다.
스크롤·클릭 뒤 목록이 추가Selenium으로 동작과 대기를 구현화면 상태가 바뀐 뒤의 DOM을 읽어야 한다.
로그인 후에만 게시판 접근 가능허용 범위 안에서 세션과 입력 자동화인증된 브라우저 상태가 필요하다.
사이트 이용 조건이나 수집 허용 여부가 불명확수집을 멈추고 정책 확인기술적으로 가능하다는 사실이 이용 허가를 뜻하지 않는다.

Selenium은 브라우저를 사람처럼 제어할 수 있지만, 데이터가 나타날 시간을 기다리는 조건도 함께 설계해야 한다. 단순한 고정 시간 대기는 네트워크 상태에 따라 너무 짧거나 길어질 수 있으므로 “목표 요소가 나타났는가”처럼 상태를 기준으로 판단하는 편이 안정적이다.

lxml과 XPath는 문서 트리에서 필요한 위치를 질의한다

XPath는 XML·HTML 문서의 요소, 속성, 텍스트를 경로로 선택하는 표현 언어다. 강의의 핵심 기호를 경로 관점에서 읽으면 다음과 같다.

기호의미게시판 예시
/루트부터 잇는 절대 경로/html/body/...
//현재 범위 아래에서 조건에 맞는 모든 후손//a
.현재 노드.//a
@속성 선택//a/@href
text()요소의 직접 텍스트 노드 선택//a/text()
[ ]조건으로 후보 제한//a[@class='title']
*이름과 관계없이 모든 요소//*[@id='board']

앞의 학습용 HTML에서 게시글 제목과 링크를 함께 뽑는 코드는 다음과 같이 구성할 수 있다.

from lxml import html

document = html.fromstring(page_source)
rows = document.xpath("//ul[@id='board']/li[contains(@class, 'post')]")

records = []
for row in rows:
    title = " ".join(row.xpath(".//a[contains(@class, 'title')]//text()")).strip()
    href = row.xpath("string(.//a[contains(@class, 'title')]/@href)")
    records.append({"title": title, "href": href})

먼저 게시글 행을 고른 뒤 각 행을 현재 노드로 삼아 .//로 제목과 링크를 추출한다. 이렇게 묶으면 제목 목록과 링크 목록을 따로 뽑다가 서로 어긋나는 오류를 줄일 수 있다.

XPath의 목표는 짧은 경로가 아니라 의미가 안정적인 경로다

/html/body/div[2]/div[3]/a처럼 화면 위치를 그대로 적은 절대 경로는 중간 배너 하나만 추가되어도 깨질 수 있다. 반대로 //a는 너무 넓어 메뉴와 광고 링크까지 섞인다. 좋은 선택자는 게시판 영역과 제목의 의미 있는 속성을 함께 사용한다.

추출 결과는 단순히 “코드가 실행되었다”로 검증하지 않는다. 기대한 게시글 수와 실제 추출 수를 비교하고, 빈 제목 비율, 중복 링크, 메뉴 문구 포함 여부를 표본으로 확인해야 한다. 사이트 구조가 바뀌면 0개가 아니라 그럴듯한 오답 목록이 반환될 수도 있기 때문이다.

선택자 점검 순서: 범위를 게시판으로 좁힌다 → 게시글 한 건의 반복 단위를 잡는다 → 그 단위 안에서 제목과 속성을 함께 뽑는다 → 개수·빈값·중복을 검사한다.

정규표현식은 문자열 규칙을 다루지만 정제 목적을 먼저 정해야 한다

정규표현식은 문자 조합의 패턴을 찾고 바꾸는 체계다. 강의자료의 [^a-zA-Z0-9가-힣\s]는 영문자·숫자·한글·공백이 아닌 문자를 찾고, \s는 스페이스·탭·개행 같은 공백 문자를 가리킨다. 다만 제거 규칙은 분석 목적에 따라 정보 손실을 만들 수 있다. 예를 들어 C++, A/B, 날짜의 하이픈은 기호를 지우면 의미가 달라진다.

학습용 제목 네 개를 정제하는 최소 예시는 다음과 같다. 특수문자를 공백으로 바꾼 뒤 연속 공백을 하나로 합쳐 단어끼리 붙는 문제를 피한다.

import re

def clean_title(text):
    text = re.sub(r"[^a-zA-Z0-9가-힣\s]", " ", text)
    return re.sub(r"\s+", " ", text).strip()

titles = ["[공지] 시험 일정", "C++ 스터디", "과제 Q&A", "8/30 특강"]
cleaned = [clean_title(title) for title in titles]

이 규칙을 적용하면 검색용 일반 단어 집계에는 편리하지만 C++와 날짜 표기가 손상된다. 따라서 원문 열을 보존하고, 정제 열을 별도로 만든 뒤 전후 표본을 비교해야 한다.

<[^>]*> 패턴은 단순한 태그 모양을 제거하는 예로 이해할 수 있다. 실제 HTML은 속성·인용부호·깨진 마크업이 복잡할 수 있으므로, 구조를 이미 알고 있다면 정규표현식으로 HTML 전체를 해석하기보다 HTML 파서에서 텍스트를 추출하는 편이 역할에 맞다.

형태소 분석은 한국어 문장을 의미 단위 후보로 나눈다

형태소는 문법적 의미를 지닌 최소 단위다. 한국어는 어간에 조사와 어미가 결합하므로 띄어쓰기만으로 나눈 단어가 분석 단위와 일치하지 않을 수 있다. 강의에서는 Kiwi를 사용해 형태소와 품사를 확인하고, 문장의 핵심 주제를 찾기 위해 명사를 추출한다.

다음 코드는 실행 환경에 Kiwi가 설치되어 있다고 가정한 학습용 예다. 품사 태그가 일반명사나 고유명사인 토큰만 남긴다.

from kiwipiepy import Kiwi

kiwi = Kiwi()
text = "데이터분석 스터디원을 모집합니다"
tokens = kiwi.tokenize(text)
nouns = [token.form for token in tokens if token.tag in {"NNG", "NNP"}]
print(nouns)

형태소 분석기가 토큰을 만들었다고 해서 모두 키워드가 되는 것은 아니다. 분석 목적과 관계없는 자주 등장하는 말은 불용어로 정의할 수 있지만, 불용어도 문맥에 따라 달라진다. 학과 게시판에서 “안내”는 흔해 제거 후보일 수 있으나, 공지 유형을 분류할 때는 중요한 단서가 될 수 있다.

빈도와 워드 클라우드는 출현량을 보여 줄 뿐 중요도를 확정하지 않는다

정제된 토큰을 세면 단어 빈도를 얻을 수 있고, 워드 클라우드는 빈도가 높은 단어를 크게 표시한다. 이 시각화는 전체 어휘를 빠르게 훑는 데 유용하지만 단어 사이의 관계, 문장의 긍정·부정, 표본의 대표성을 보여 주지는 않는다.

예를 들어 “과제 제출 오류”, “과제 오류 해결”, “과제 없음”에서 ‘과제’가 가장 자주 나타나더라도 세 문장의 의미는 다르다. 빈도표에는 전체 문서 수, 분석 기간과 상위 단어의 실제 문장 예시를 함께 두어야 해석이 단순한 크기 비교에 머물지 않는다.

해석 핵심: 빈도는 “얼마나 자주 나타났는가”에 답한다. “왜 나타났는가”, “좋은 반응인가”, “어떤 범주인가”에 답하려면 원문 문맥이나 별도의 분류 기준이 필요하다.

LLM 분류는 범주 설계와 출력 검증이 있어야 분석 결과가 된다

텍스트 분류는 문서나 문장을 미리 정한 범주에 배정하는 작업이다. 대규모 언어 모델(LLM)은 문맥을 반영해 분류 후보를 생성할 수 있지만, 모델을 호출했다는 사실만으로 일관된 분석이 보장되지는 않는다. 범주 정의, 입력 형식, 허용 출력, 재검토 기준을 먼저 고정해야 한다.

강의 실습은 vLLM으로 모델을 불러오고, Hugging Face 모델 저장소의 EXAONE 3.5 2.4B 모델을 활용해 게시글을 분류하는 환경을 제시한다. 여기서 학습의 초점은 특정 모델 이름을 외우는 것이 아니라, 수집한 제목을 정제하고 정해진 범주로 분류한 뒤 결과를 시각화하는 연결 과정에 있다.

설계 항목점검 질문오류 예
범주범주가 서로 겹치지 않고 목적을 설명하는가?‘학사’와 ‘공지’가 같은 제목에 동시에 해당
입력원문과 정제문 중 무엇을 모델에 넣는가?날짜·과목명이 사라져 판단 단서 손실
출력허용 범주 하나만 반환하게 했는가?설명 문장이나 새 범주가 함께 출력
평가사람이 분류한 표본과 비교했는가?그럴듯한 결과를 정확도처럼 오해

범주가 학사, 취업, 스터디, 기타라면 모델 응답이 이 집합 안에 있는지 먼저 검사할 수 있다.

allowed_labels = {"학사", "취업", "스터디", "기타"}

label = model_output.strip()
if label not in allowed_labels:
    label = "검토필요"

result = {"title": original_title, "label": label}

이 검사는 분류의 의미가 맞는지까지 보장하지는 않지만, 범주 밖 응답을 정상 데이터에 섞는 일을 막는다. 이후에는 사람이 판정한 표본과 비교해 어떤 범주에서 혼동이 많은지 확인해야 한다.

학과게시판 프로젝트는 네 단계와 세 개의 검증 관문으로 읽는다

강의 실습 프로젝트는 방송통신대학교 학과게시판의 글 제목을 수집하여 분석하는 사례다. 단계는 수집·전처리, 텍스트 전처리, 키워드 분석, LLM 분류·시각화로 이어진다. 이를 단순 도구 목록이 아니라 데이터 상태의 변화로 재구성하면 다음과 같다.

단계핵심 작업남겨야 할 산출물통과 기준
수집·구조 추출Selenium 접근, lxml 파싱, XPath 제목 선택원문 제목, 링크, 수집 시점기대 범위와 건수·중복·빈값 확인
텍스트 전처리특수문자 정리, 형태소·품사 분리, 불용어 처리원문과 정제문, 토큰 목록의미 손실 표본 점검
키워드 분석빈도 계산, 워드 클라우드, 상위 단어 확인빈도표와 문맥 예시기간·문서 수와 함께 해석
분류·시각화LLM 분류, 범주별 집계, 결과 표현제목별 범주와 검토 상태허용 범주 검사와 표본 평가

세 검증 관문은 ① 수집 직후 원문 보존과 건수 점검, ② 정제 전후 의미 손실 점검, ③ 분류 후 허용 범주와 사람 표본 비교다. 각 관문을 통과해야 다음 단계의 숫자를 해석할 수 있다.

파이프라인은 중간 결과를 남겨야 고칠 수 있다

최종 워드 클라우드나 범주별 막대그래프만 저장하면 오류의 출처를 찾기 어렵다. 원본 HTML 전체를 장기간 보관할 필요가 있는지는 수집 정책과 개인정보를 고려해 판단하되, 최소한 수집 시각, 원문 제목, 추출 링크, 정제문, 토큰, 분류값과 검토 상태를 단계별로 연결해야 한다.

자가 점검을 해 보자. 추출 제목이 240개인데 정제 후 문장이 218개라면, 22개를 자동으로 ‘쓸모없는 데이터’라 결론 내리면 안 된다. 빈 문자열이 된 제목의 원문을 확인하고, 정규식이 모든 문자를 지웠는지, XPath가 제목이 아닌 아이콘을 선택했는지 구분해야 한다. 분석 품질은 복잡한 모델보다 이런 중간 관찰 가능성에서 먼저 결정된다.

핵심 개념 정리

  • 반정형 데이터는 고정된 표 대신 태그·속성·키·계층으로 구조를 표현한다.
  • Selenium은 브라우저 동작과 상태 변화가 필요한 수집에, lxml과 XPath는 문서 트리의 선택적 추출에 사용한다.
  • XPath는 게시판 범위, 반복 행, 행 내부 필드를 차례로 좁혀야 결과의 짝과 의미를 보존하기 쉽다.
  • 정규표현식 정제는 분석 목적에 따라 정보 손실을 만들 수 있으므로 원문을 보존하고 전후를 비교한다.
  • 형태소 분석은 한국어 문장을 품사 단위로 나누며, 불용어와 명사 선택은 분석 질문에 맞춰 결정한다.
  • 빈도·워드 클라우드와 LLM 분류는 각각 문맥과 범주 검증이라는 별도의 해석 조건이 필요하다.

새 웹 텍스트 분석을 만났을 때는 도구 이름부터 고르지 말고 데이터 상태를 따라간다. 페이지가 언제 만들어지는지 확인하고, 반복 단위와 필드를 구조적으로 추출하며, 원문을 보존한 채 정제하고, 토큰·빈도·분류 결과마다 검증 관문을 둔다. 이 순서를 지키면 최종 그림이 이상할 때 어느 변환을 고쳐야 하는지 설명할 수 있다.

예상문제 10선

1. 반정형 데이터에 대한 설명으로 가장 적절한 것은?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ②

  • ① 오답: 구조가 전혀 없는 데이터와 달리 반정형 데이터에는 해석 가능한 표식이 있다.
  • ② 정답: HTML의 태그·속성, JSON의 키처럼 문서 자체가 구조 단서를 제공한다.
  • ③ 오답: 반정형 여부는 수치형 열의 유무가 아니라 구조 표현 방식으로 구분한다.
  • ④ 오답: 저장 위치만으로 구조가 바뀌지 않으며 문서의 표현 규칙을 살펴야 한다.

2. JavaScript 실행과 클릭 후에 게시글 목록이 나타나는 페이지를 수집하려 할 때 가장 알맞은 판단은?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ④

  • ① 오답: 정규표현식은 문자열 패턴을 처리하며 브라우저 상태나 클릭을 제어하지 않는다.
  • ② 오답: XPath는 이미 존재하는 문서 노드를 선택하며 동적 목록을 생성하지 않는다.
  • ③ 오답: 워드 클라우드는 수집된 단어 빈도의 표현 수단이지 데이터 수집 도구가 아니다.
  • ④ 정답: 사용자 동작과 렌더링 이후 상태가 필요하므로 브라우저 자동화와 조건 대기가 맞다.

3. 현재 노드가 게시글 하나를 나타내는 li일 때, 그 안의 제목 링크 텍스트만 고르는 XPath는?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ①

  • ① 정답: 점은 현재 게시글을 기준으로 삼고, 제목 클래스의 링크 아래 텍스트를 선택한다.
  • ② 오답: 게시판 전체 요소를 고를 뿐 현재 행의 제목 텍스트까지 내려가지 않는다.
  • ③ 오답: 문서 전체 링크의 주소 속성을 선택하므로 범위와 반환값이 모두 다르다.
  • ④ 오답: 본문 직계 요소 전체를 선택해 제목이라는 의미를 제한하지 못한다.

4. //a가 정상 실행되었지만 메뉴와 광고 링크까지 추출되었다. 가장 적절한 수정은?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ③

  • ① 오답: 형태소 분석은 텍스트 단위 처리이며 잘못 선택한 HTML 요소의 의미를 교정하지 못한다.
  • ② 오답: 동일한 문서와 식은 같은 과다 선택을 되풀이할 뿐 범위를 줄이지 않는다.
  • ③ 정답: 게시판 컨테이너, 반복 게시글, 제목 필드 순으로 구조 조건을 명확히 해야 한다.
  • ④ 오답: 많은 결과는 완전성의 증거가 아니며 목표 밖 링크가 섞이면 정확성이 낮다.

5. 특수문자 제거 뒤 C++ 스터디C 스터디로 바뀌었다. 가장 적절한 대응은?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ②

  • ① 오답: 원문이 없으면 손실을 확인하거나 정제 규칙을 다시 적용할 근거가 사라진다.
  • ② 정답: 기호가 기술명에 의미를 가지므로 목적에 맞춰 보존 규칙을 수정해야 한다.
  • ③ 오답: 공백 제거는 단어 경계를 훼손해 형태소·빈도 분석을 더 어렵게 만든다.
  • ④ 오답: 추측은 원문 복원이 아니며 잘못된 정보를 새로 만들 수 있다.

6. 한국어 텍스트에서 형태소 분석이 중요한 이유로 가장 적절한 것은?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ①

  • ① 정답: 한국어의 결합 형태를 분석해 형태소와 품사를 구분하려는 것이 핵심이다.
  • ② 오답: 문서 구조 선택은 HTML 파서와 XPath가 담당하는 단계다.
  • ③ 오답: 사용자 동작 자동화는 Selenium과 같은 브라우저 자동화의 역할이다.
  • ④ 오답: 시각적 표현 설정은 형태소를 문법 단위로 나누는 목적과 다르다.

7. 워드 클라우드만 보고 “학생들이 과제를 가장 긍정적으로 평가했다”고 결론 내릴 수 없는 이유는?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ④

  • ① 오답: 표시 토큰은 전처리 설계에 따라 달라지며 핵심 한계는 품사 하나에 있지 않다.
  • ② 오답: XPath 사용 여부는 데이터 추출 문제이고 감정·문맥 해석의 근거가 되지 않는다.
  • ③ 오답: 구조에서 텍스트를 추출하고 정제하면 반정형 데이터도 빈도를 계산할 수 있다.
  • ④ 정답: ‘과제 없음’과 ‘과제 유익함’은 같은 단어를 포함해도 태도가 다르므로 원문 맥락이 필요하다.

8. 웹 게시글 제목 분석의 순서로 가장 적절한 것은?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ③

  • ① 오답: 시각화할 데이터가 만들어지기 전에 결과 표현을 먼저 수행할 수 없다.
  • ② 오답: 범주와 입력 기준은 분류 전에 정하고, 원문은 변환 이전에 확보해야 한다.
  • ③ 정답: 페이지를 얻은 뒤 목표 문자열을 고르고 정제해야 분석 입력이 만들어진다.
  • ④ 오답: 불용어 제거는 텍스트 확보 이후이며 수집 정책은 접근 전에 확인해야 한다.

9. LLM이 허용 범주에 없는 설명 문장을 반환했다. 파이프라인의 첫 대응으로 가장 적절한 것은?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ④

  • ① 오답: 모델의 자유 응답을 자동 범주로 만들면 미리 정의한 분류 체계가 무너진다.
  • ② 오답: 임의 치환은 오류율을 감추고 첫 범주의 빈도를 부풀린다.
  • ③ 오답: 숫자 추출은 허용 범주 위반의 원인을 해결하지 못한다.
  • ④ 정답: 범주 밖 출력을 격리한 뒤 입력 지시와 출력 제약을 수정해야 추적 가능하다.

10. 정제 후 제목 수가 240개에서 218개로 줄었다. 가장 타당한 조사 순서는?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ①

  • ① 정답: 중간 결과를 연결하면 누락이 구조 추출인지 정제 규칙인지 원인을 분리할 수 있다.
  • ② 오답: 불용어는 토큰 판단이며 제목 행 전체의 소실을 자동 정당화하지 않는다.
  • ③ 오답: 분류 범주는 이미 사라진 입력 레코드를 복원하지 못한다.
  • ④ 오답: 표현 크기 변경은 데이터 건수의 실제 차이를 해결하지 않는다.

참고 자료와 작성 기준

이 글은 해당 차시 강의자료를 바탕으로 학습 목적에 맞게 재구성한 비공식 학습자료입니다. 개념 관계, 학습용 예제와 문제 해설은 학습자의 이해를 돕도록 구성하고 검토했습니다.

댓글