반응형
네이버 뉴스 수집 서비스 구현
네이버 뉴스 기사를 크롤링해 데이터를 수집하고 수집된 기사 내용을 통해 자연어 처리를 합니다.
크롤링 할 기사를 선택하고 개발자 모드로 html 소스를 분석해 봅니다.
네이버 기사 본문 시작점입니다.
package poly.service;
public interface INewsCollectService {
//네이버 뉴스 기사 크롤링으로 가져오기
String doNaverNewsContents(String url) throws Exception;
}
INewsCollectService
package poly.service.impl;
import org.apache.log4j.Logger;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;
import org.springframework.stereotype.Service;
import poly.service.INewsCollectService;
@Service("NewsCollectService")
public class NewsCollectService implements INewsCollectService {
private Logger log = Logger.getLogger(this.getClass());
@Override
public String doNaverNewsContents(String url) throws Exception {
//JSOUP 라이브러리를 통해 사이트에 접속되면 그 사이트의 전체 HTML 소스를 저장할 변수
Document doc = null;
//사이트 접속(http 프로토콜만 가능합니다, https 프로토콜은 보안상 안 됩니다.)
doc = Jsoup.connect(url).get();
//네이버 뉴스 본문 내용에 대한 div 소스를 가져옵니다.
// <div id="articleBodyContents" class="_article_body_contents">
Elements newsContent = doc.select("div._article_body_contents");
//태그 내 텍스트 문구만 가져옵니다.
String res = newsContent.text();
log.info(res);
doc = null;
return res;
}
}
NewsCollectService
package poly.service.impl;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.Resource;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Service;
import kr.co.shineware.nlp.komoran.constant.DEFAULT_MODEL;
import kr.co.shineware.nlp.komoran.core.Komoran;
import kr.co.shineware.nlp.komoran.model.KomoranResult;
import poly.service.INewsCollectService;
import poly.service.IWordAnalysisService;
import poly.util.CmmUtil;
@Service("WordAnalysisService")
public class WordAnalysisService implements IWordAnalysisService {
private Logger log = Logger.getLogger(this.getClass());
@Resource(name = "NewsCollectService")
private INewsCollectService newsCollectService; //뉴스 기사를 수집하기 위한 객체입니다.
//자연어 처리 - 형태소 분석기인 Komoran를 메모리에 올리기 위해 WordAnalysisService 클래스 내 전역 변수로 설정합니다.
Komoran nlp = null;
//생성자 사용함 - 톰켓에서 부팅할 때 @Service를 모두 메모리에 올립니다.
//톰켓이 메모리에 올릴 때, 생성자에 선언한 Komoran도 같이 메모리에 올라가도록 생성자에 코딩합니다.
//생성자에서 Komoran을 메모리에 올리면, 매번 메모리에 올려서 호출하는 것이 아니라,
// 메모리에 올리간 객체만 불러와서 사용할 수 있기 때문에 처리 속도가 빠릅니다.
public WordAnalysisService() {
log.info(this.getClass().getName() + ".WordAnalysisService creator Start !");
//NLP 분석 객체 메모리 로딩합니다.
this.nlp = new Komoran(DEFAULT_MODEL.LIGHT); // 학습데이터 경량화 버전( 웹 서비스에 적합합니다. )
//this.nlp = new Komoran(DEFAULT_MODEL.FULL); // 학습데이터 전체 버전(일괄처리 : 배치 서비스에 적합합니다.)
log.info("난 톰켓이 부팅되면서 스프링 프렝미워크가 자동 실행되었고, 스프링 실행될 때 nlp 변수에 Komoran 객체를 생성하여 저장하였다.");
log.info(this.getClass().getName() + ".WordAnalysisService creator End !");
}
@Override
public List<String> doWordNouns(String text) throws Exception {
log.info(this.getClass().getName() + ".doWordAnalysis Start !");
log.info("분석할 문장 : " + text);
//분석할 문장에 대해 정제(쓸데없는 특수문자 제거)
String replace_text = text.replace("[^가-힣a-zA-Z0-9", " ");
log.info("한국어, 영어, 숫자 제외 단어 모두 한 칸으로 변환시킨 문장 : " + replace_text);
//분석할 문장의 앞, 뒤에 존재할 수 있는 필요없는 공백 제거
String trim_text = replace_text.trim();
log.info("분석할 문장 앞, 뒤에 존재할 수 있는 필요 없는 공백 제거 : " + trim_text);
//형태소 분석 시작
KomoranResult analyzeResultList = this.nlp.analyze(trim_text);
//형태소 분석 결과 중 명삼나 가져오기
List<String> rList = analyzeResultList.getNouns();
if (rList == null) {
rList = new ArrayList<String>();
}
//분석 결과 확인을 위한 로그 찍기
Iterator<String> it = rList.iterator();
while (it.hasNext()) {
//추출된 명서
String word = CmmUtil.nvl(it.next());
log.info("word : " + word);
}
log.info(this.getClass().getName() + ".doWordAnalysis End !");
return rList;
}
@Override
public Map<String, Integer> doWordCount(List<String> pList) throws Exception {
log.info(this.getClass().getName() + ".doWordCount Start !");
if (pList ==null) {
pList = new ArrayList<String>();
}
//단어 빈도수(사과, 3) 결과를 저장하기 위해 Map객체 생성합니다.
Map<String, Integer> rMap = new HashMap<>();
//List에 존재하는 중복되는 단어들의 중복제거를 위해 set 데이터타입에 데이터를 저장합니다.
//rSet 변수는 중복된 데이터가 저장되지 않기 떄문에 중복되지 않은 단어만 저장하고 나머지는 자동 삭제합니다.
Set<String> rSet = new HashSet<String>(pList);
//중복이 제거된 단어 모음에 빈도수를 구하기 위해 반복문을 사용합니다.
Iterator<String> it = rSet.iterator();
while(it.hasNext()) {
//중복 제거된 단어
String word = CmmUtil.nvl(it.next());
//단어가 중복 저장되어 있는 pList로부터 단어의 빈도수 가져오기
int frequency = Collections.frequency(pList, word);
log.info("word :" + word);
log.info("frequency : " + frequency);
rMap.put(word, frequency);
}
log.info(this.getClass().getName() + ".doWordCount End !");
return rMap;
}
@Override
public Map<String, Integer> doWordAnalysis(String text) throws Exception {
//네이버 뉴스 내용을 가져옵니다.
String newContext = newsCollectService.doNaverNewsContents(
"https://news.naver.com/main/read.naver?mode=LSD&mid=shm&sid1=105&oid=366&aid=0000774467"
);
//문장의 명사를 추출하기 위한 형태소 분석 실행
List<String> rList = this.doWordNouns(newContext);
if(rList == null) {
rList = new ArrayList<String>();
}
//추출된 명사 모음(리스트)의 명사 단어별 빈도수 계산
Map<String, Integer> rMap = this.doWordCount(rList);
if(rMap == null) {
rMap = new HashMap<String, Integer>();
}
return rMap;
}
}
WordAnalysisService
이전 글에서 수정과 추가를 했습니다.
어노테이션 리소스 부분을 추가해주고
네이버 뉴스 내용을 가져오는 부분을 추가하고
형태소 분석 하는 부분을 수정해 줬습니다.
이렇게 정상적으로 네이버 기사를 웹 크롤링 해와서 형태소 분석하는 자연어 처리를 한 내용입니다.
정상적으로 완료했습니다.
반응형
'Framework & Library > Spring Framework' 카테고리의 다른 글
[Spring Framework] : MySQL 연동 Test Code 작성 및 확인 (0) | 2022.01.06 |
---|---|
[Spring Framework] : 스프링 프레임워크 자문 자답 16제 (0) | 2021.12.10 |
[Spring Framework] : 자연어처리 (1) | 2021.11.20 |
[Spring Framework] : Rest 기반 Open API Server 구현 (3부) (0) | 2021.11.03 |
[Spring Framework] : Rest 기반 Open API Server 구현 (2부) (0) | 2021.11.03 |
댓글