안녕하세요. 언제나 휴일, 언휴예요.
이전 강의에서 뉴스 크롤링 라이브러리 제작을 마쳤습니다.
이제 수집한 뉴스를 분석하는 코드를 작성할 시점이 왔어요.
이번에 문장으로 만들어진 콘텐츠를 분석할 때 가장 기초적인 형태소 분석을 해 볼 거예요.
자세한 내용은 동영상 강의를 참고하세요.
2020년 5월 4일 저녁 7시 30분 경에 “스포츠”로 검색하여 나오는 1100개의 기사 중에 가장 많이 나온 단어 BEST 50입니다. *참고로 각 기사의 앞 부분만 발췌하기 때문에 빈도 수가 크지 않습니다.*
- 스포티비뉴스:33
- KBO:33
- 손진아:33
- 첫:34
- 예정:34
- 최고:35
- 활동:35
- 트랙스:35
- 교육기부:36
- 모델:38
- 72개월:38
- 스포츠마케팅:39
- 한도:40
- 대표적인:40
- 후원:42
- 관계자:43
- 개막전:45
- 5일:46
- 사진:47
- SUV:47
- 개막:49
- 연계:50
- 지원:51
- 브랜드:51
- 옥영화:51
- 마케팅:52
- 잠실야구장에서:54
- 대비:55
- 오전:60
- 출시:60
- KBO리그:63
- 미국:64
- 경기:66
- 잠실:68
- 선수:69
- 렉스턴:69
- 트윈스:72
- 스포츠투데이:75
- 시즌:77
- 훈련:81
- 코로나19:82
- 두산:87
- LG:88
- 2020:93
- 프로야구:117
- 매경닷컴:127
- MK스포츠:130
- 기자:207
- 4일:216
- 스포츠:442
- Morpheme.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
using System; namespace 형태소_분석기_만들기 { /// <summary> /// 형태소 /// </summary> public class Morpheme:IComparable { /// <summary> /// 형태소 단어 - 가져오기 및 설정하기 /// </summary> public string Name { get; set; } /// <summary> /// 빈도수 - 가져오기 및 설정하기 /// </summary> public int Count { get; set; } /// <summary> /// 형태소 생성자 /// </summary> /// <param name="name">단어</param> /// <param name="count">빈도수</param> public Morpheme(string name,int count) { Name = name; Count = count; } /// <summary> /// ToString 재정의 /// </summary> /// <returns>단어</returns> public override string ToString() { return Name; } /// <summary> /// 비교 - 정렬을 위해 제공 /// </summary> /// <param name="obj">비교 대상 - 형태소 형식 개체여야 함</param> /// <returns>비교 결과</returns> public int CompareTo(object obj) { Morpheme mo = obj as Morpheme; if(mo == null) { throw new ApplicationException("비교 대상 개체는 Morpheme 형식이어야 합니다."); } return Count.CompareTo(mo.Count); } } } |
- MorphemeParser.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
using System; using System.Collections.Generic; namespace 형태소_분석기_만들기 { /// <summary> /// 형태소 분석기 - 정적 클래스 /// </summary> public static class MorphemeParser { static string[] filters = {"~","!","#","$","%","^","&","*","(",")","-","_","=","+","|",@"\", "{","}","[","]",";",":","\"","'","<",">",",",".","/","?"," ","","quot","amp","apos","lt","gt"}; static string[] pf_filters = { "는", "은", "을", "를", "가", "에", "게", "에게","의","들","있다.","없다","이다","입니다", "합니다" , "합시다"}; /// <summary> /// 형태소 분석 메서드 /// </summary> /// <param name="source">원본 문자열</param> /// <returns>형태소 컬렉션</returns> public static List<Morpheme> Parse(string source) { List<Morpheme> mlist = new List<Morpheme>(); string[] elems = source.Split(filters, StringSplitOptions.RemoveEmptyEntries); foreach(string elem in elems) { ParseElem(elem, mlist); } mlist.Sort(); return mlist; } private static void ParseElem(string elem, List<Morpheme> mlist) { if(elem == string.Empty) { return; } foreach(string pf_filter in pf_filters) { if(elem.EndsWith(pf_filter)) { MakeElem(pf_filter, elem, mlist); return; } } RecordElem(elem, mlist); } private static void RecordElem(string elem, List<Morpheme> mlist) { foreach(Morpheme mo in mlist) { if(mo.Name == elem) { mo.Count++; return; } } Morpheme mo2 = new Morpheme(elem, 1); mlist.Add(mo2); } private static void MakeElem(string pf_filter, string elem, List<Morpheme> mlist) { int pos = elem.Length - pf_filter.Length; string sub = elem.Substring(0, pos); RecordElem(sub, mlist); } /// <summary> /// 형태소 통합 메서드 /// </summary> /// <param name="src">원본 형태소 컬렉션</param> /// <param name="dest">타겟 형태소 컬렉션</param> /// <returns>타겟 형태소 컬렉션</returns> public static List<Morpheme> Merge(List<Morpheme> src, List<Morpheme> dest) { foreach(Morpheme mo in src) { RecordElem2(mo, dest); } dest.Sort(); return dest; } private static void RecordElem2(Morpheme mo, List<Morpheme> dest) { foreach(Morpheme mo2 in dest) { if(mo2.Name == mo.Name) { mo2.Count += mo.Count; return; } } dest.Add(mo); } } } |
- Program.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
using System; using System.Collections.Generic; using 네이버_뉴스_크롤링_라이브러리_제작; namespace 형태소_분석기_만들기 { class Program { static void Main(string[] args) { string id = [네이버 개발자센터에서 발급받은 애플리케이션 ID]; string secret = [네이버 개발자센터에서 발급받은 애플리케이션 Secret]; NaverNews nn = new NaverNews(id, secret); int total = nn.Find("스포츠"); Console.WriteLine(total); List<Morpheme> morphemes = new List<Morpheme>(); List<Morpheme> src_morphemes; List<News> nc; for (int start = 1; (start < 1000) && (start < total); start += 100) { nc = nn.FindNews(start, 100); foreach (News news in nc) { Console.WriteLine(news.Title); Console.WriteLine("=="); Console.WriteLine(news.Description); Console.WriteLine("=================================================="); src_morphemes = MorphemeParser.Parse(news.Description); MorphemeParser.Merge(src_morphemes, morphemes); } } foreach(Morpheme morpheme in morphemes) { Console.WriteLine("{0}:{1}", morpheme, morpheme.Count); } } } } |
*이전 강의에서 작성한 뉴스 크롤링 라이브러리를 참조 추가하셔야 합니다.*