728x90
반응형

안녕하세요! 요즘 몸이 별로 좋지 않아서 블로그 글을 거의 쓰지 못했네요ㅠㅠ

오늘은 빅쿼리(BigQuery)와 파이썬을 연동하는 방법에 대해서 포스팅 하겠습니다.

 

  • 빅쿼리(BigQuery) 란?

구글 클라우드 플랫폼에서 제공하는 클라우드 기반의 데이터웨어 하우스 서비스입니다.

구글 계정으로 관리하기 쉽기 때문에 요즘 다양한 회사에서 빅쿼리를 사용하고 있습니다.

 

  • 파이썬이랑 연동하는 이유
  1. 대용량 결과물 저장
    빅쿼리에서는 기본적으로 결과물을 csv 파일로 저장하거나, 스프레드 시트로 저장하는 기능을 제공하고 있습니다.
    하지만 데이터 결과물의 용량이 너무 클 경우에는 일부 데이터를 소실할 수 있는데, 데이터 분석의 특성 상 대용량의 데이터를 다루는 경우가 많기 때문에 생각보다 데이터가 소실되는 경우를 자주 경험할 수 있습니다.
    이런 경우 빅쿼리와 파이썬을 연동하여 로컬 PC에 바로 csv 혹은 xlsx 파일로 결과물을 저장할 수 있습니다!
  2. 쿼리로 해결하기 힘든 데이터  처리
    쿼리에서는 데이터의 직접적인 비교 등 진행하기 어려운 작업들이 있기 때문에 파이썬과 연동하여 데이터를 원하는 목적에 맞게 정제할 수 있습니다.
  3. 데이터 시각화
    데이터 분석은 쿼리를 통해 데이터를 집계하는 것 뿐만 아니라, 보고서 등을 위해서 데이터를 시각화 하는 작업이 빈번하게 발생합니다.
    요즘은 파이썬에서 데이터 시각화를 많이 진행하기 때문에 연동하여 진행하면, 시각화 작업을 수월하기 진행할 수 있습니다.

  • 필요한 라이브러리 설치하기

빅쿼리와 파이썬을 연결하기 위해서는 먼저 pandas-gbq 라는 라이브러리를 설치해야 합니다.

일반 라이브러리 설치하시는 것처럼 설치해주시면 됩니다!

pip install pandas-gbq

 

  • 코드 작성

파이썬 코드를 실행할 수 있는 실행기에서 아래 코드처럼 빅쿼리에서 실행이 가능한 쿼리와 함께 코드를 작성해주시면 손쉽게 빅쿼리 결과물을 로컬에 저장할 수 있습니다!

query="""
	빅쿼리에서 실행할 쿼리
"""

purchase_log = pd.read_gbq(query=query, dialect='standard', project_id='빅쿼리 프로젝트 이름', auth_local_webserver=True)
purchase_log.to_csv(f"저장하고자 하는 파일 경로", sep=",", index=False, encoding='cp949')

 

※주의 ※

데어터의 양이 많을 경우 코드가 실행되는 시간이 길기 때문에 반드시 쿼리를 먼저 빅쿼리에서 확인 후에 파이썬에서 실행해주세요!

한글 데이터가 포함되는 경우 encoding='cp949'를 포함하지 않으면, 한글이 깨질 수 있습니다.

데이터의 양이 많다면 파일의 경로는 D드라이브로 하는 것을 추천합니다!

 

 

  • 계정 선택

해당 코드를 처음 실행을 할 경우에는 크롬이 자동으로 뜨면서, 빅쿼리와 연결된 계정 선택 및 엑세스 요청 허가를 확인합니다.

알맞은 계정과 엑세스 허용을 하시면, 정상적으로 코드가 실행됩니다!

계정 선택의 과정은 컴퓨터마다 한 번만 진행이 됩니다.

 

실행이 완료되면, pandas를 이용해서 데이터를 정상적으로 로드할 수 있습니다.

1500만 정도 되는 데이터도 아주 잘 로드가 되는 것을 볼 수 있습니다!

 

빅쿼리는 파이썬과 연동하지 않으면 대용량 데이터를 저장하는 방법이 빅쿼리 자체에 테이블로 저장하는 방법 밖에 없기 때문에 파이썬에서 실행하는 방법을 익혀두시는 걸 추천드립니다!

 

궁금한 부분이 있으신 분들은 댓글로 남겨주시면, 답변 드리도록 하겠습니다.

★읽어주셔서 감사합니★

728x90
반응형
728x90
반응형

안녕하세요! 오늘은 원신 나무위키에 플레이어블 캐릭터성유물 카테고리의 글을 크롤링하는 코드에 대해 포스팅 진행하겠습니다.

해당 포스팅에서는 전체 코드와 결과물 이미지만 첨부합니다.

크롤링의 자세한 과정은 추후에 포스팅 진행하도록 하겠습니다.

 

해당 크롤링은 원신 각 캐릭터의 성유물 추천 옵션과 세트를 빠르게 파악하기 위한 데이터 수집을 목적으로 하고 있습니다!

나무위키에서 수집할 정보는 아래와 같습니다.

※ 사진 속 정보는 나히다를 예시로 한 것입니다.

1. 캐릭터의 이름, 속성, 무기

 

2. 권장 성유물 옵션

 

3. 추천 성유물 세트 및 설명

 

4. 성유물 이름, 세트 효과, 획득처

 

  • 크롤링 진행 방식

크롤링은 총 3개의 코드로 진행을 합니다.

 

  • 첫 번째 코드
  1. 원신 캐릭터의 상세 정보가 담긴 링크를 전부 긁어옵니다.
  2. 캐릭터의 이름과 링크만 저장하여 하나의 엑셀 파일로 저장합니다.
  • 두 번째 코드
  1. 첫 번째 코드에서 저장한 엑셀 파일에서 각 캐릭터의 상세 정보 링크를 가져옵니다.
  2. 캐릭터의 속성, 무기, 권장 성유물 옵션, 추천 성유물 세트 및 상세 설명의 내용을 가지고 옵니다.
  3. 캐릭터의 이름, 속성, 무기 권장 성유물 옵션을 저장하여 하나의 엑셀 파일로 저장합니다.
  4. 캐릭터의 이름, 추천 성유물 세트, 상세 설명을 저장하여 하나의 엑셀 파일로 저장합니다.

엑셀 파일을 두 개로 나눈 이유는 이후에 원신 캐릭터 성유물을 조회하는 엑셀 파일을 쉽게 만들기 위해서 입니다!

  • 세번째 코드
  1. 성유물 세트 이름, 2세트, 4세트, 획득처의 내용을 가지고 옵니다.
  2. 획득처에서 비경의 이름을 분리합니다.
  3. 성유물 세트 이름, 2세트, 4세트, 획득처, 비경의 이름을 저장하여 하나의 엑셀 파일로 저장합니다.

비경 이름을 분리한 이유는 이후 원신 캐릭터 성유물을 조회하는 엑셀 파일을 쉽게 만들기 위해서 입니다!

 

[실제 코드 및 결과물]

  • 첫 번째 코드
import pandas as pd
from selenium import webdriver
import time
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as E
from openpyxl import *

# 원신/캐릭터 나무위키 링크
link = 'https://namu.wiki/w/%EC%9B%90%EC%8B%A0/%EC%BA%90%EB%A6%AD%ED%84%B0'

# 나무위키는 BeautifulSoup이 먹히지 않기 때문에 동적 크롤링으로 진행
driver = webdriver.Chrome('chromedriver.exe')
driver.get(link)
time.sleep(3)

# '원소별' 버튼 클릭
button = list(driver.find_elements(By.CLASS_NAME, "_3xTXXXtF"))
button[1].click()
time.sleep(3)

Character = pd.DataFrame({'캐릭터 이름' : [], '링크' : []})

character_info = driver.find_elements(By.CLASS_NAME, "s3zppxXT")

for i in range(len(character_info)) :
    character = character_info[i]
    # 캐릭터 이름만 담기 위해서 데이터를 정제하는 부분
    # 캐릭터의 소개가 끝나는 부분
    if character.text == '취소선' :
        break
    # 주인공 캐릭터인 아이테르와 루미네는 데이터 수집에서 제외
    # 캐릭터 이름이 아닌데, 들어온 정보는 모두 제외
    if character.text == '' or  '원신' in character.text or '아이테르' in character.text or character.text in ['불', '물', '바람', '번개', '풀', '얼음', '바위'] :
        pass
    else :
    	# 캐릭터의 이름
        name = character.text
        # 캐릭터의 이름이 길 경우, 엔터로 구분이 되어있기 때문에 이를 띄어쓰기로 변경
        if '\n' in name :
            name = name.replace('\n', ' ')
        Char = [name, str(character.get_attribute('href'))]
        Character.loc[i] = Char

with pd.ExcelWriter('genshin_link.xlsx') as writer :
    Character.to_excel(writer, sheet_name='링크', index=False)

 

  • 첫 번째 코드 결과물

 

  • 두 번째 코드
import pandas as pd
from selenium import webdriver
import time
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as E
from openpyxl import *

# 캐릭터의 이름과 상세정보 링크가 담긴 엑셀 파일
link = pd.read_excel('genshin_link.xlsx')
Main_link = list(link['링크'])
Character = list(link['캐릭터 이름'])

Information = pd.DataFrame({'캐릭터 이름' : [], '무기' : [], '시간의 모래' : [], '공간의 성배' : [], '이성의 왕관' : [], '부옵션' : []})
Relic_Information = pd.DataFrame({'캐릭터 이름' : [], '성유물' : [], '평가': []})

driver = webdriver.Chrome('chromedriver.exe')

# 엑셀 전체 인덱스를 의미
# 저장할 엑셀이 두 개이기 때문에 인덱스도 두 개가 필요
total_index = 0
relic_index = 0

# 특정 캐릭터의 상세정보에서 오류가 발생할 경우을 대비
try :
    for k in range(len(Main_link)) :
        driver.get(Main_link[k])
        time.sleep(3)
        
        # 캐릭터의 무기 수집 과정
        attack = driver.find_elements(By.CLASS_NAME, 'cIflhYhI')
        for i in range(len(attack)) :
            if '무기' == attack[i].text :
                attack_index = i+1
                break
        weapon = attack[attack_index].text
        
        # 캐릭터의 성유물 수집 과정
        info = driver.find_elements(By.CLASS_NAME, 'D7SMSdcV')
        for i in range(len(info)) :
        	# 권장 성유물 옵션을 파악하기 위해 위치를 저장
            if '권장 성유물' in info[i].text :
                index = i
                break
        # 권성유물의 정보가 담긴 공간
        sung = info[index]
        
        # 권장 성유물 옵션 수집 과정
        options = sung.find_elements(By.CLASS_NAME, 'cIflhYhI')
        Option = [Character[k], weapon]
        for j in range(len(options)) :
        	# 권장 성유물 옵션에서 필요한 정보가 들어있는 부분
            if j in [4, 5, 6, 8] :
                option = options[j].text
                # 옵션이 여러 개일 경우, 줄바꿈으로 구분하기 때문에 이를 / 구분으로 변경
                if '\n' in option :
                    option = option.replace('\n', ' / ')
                Option.append(option)
        # 권장 성유물의 옵션만 담는 부분
        Information.loc[total_index] = Option
        total_index = total_index+1
        
        # 추천 성유물 세트 및 상세 설명 수집 과정
        sets = sung.find_elements(By.CLASS_NAME, 'W078FM6Z')
        # 성유물 세트는 캐릭터마다 여러 개 존재하기 때문에 이를 구분하기 위한 부분
        character_number = 1
        for j in range(len(sets)) :
            # li로 구분되어 있는데, 그 안에 div가 같이 들어가 있기 때문에 문제가 발생한다.
            relic_info = list(sets[j].text.split('\n'))
            for m in range(len(relic_info)) :
            	# 실제 정보가 들어가 있는 부분
                if m%2 == 1:
                    one_set = relic_info[m-1]
                    set_info =relic_info[m]
                    character_name = Character[k]+'%d' %(character_number)
                    Option = [character_name, one_set, set_info]
                    Relic_Information.loc[relic_index] = Option
                    character_number = character_number+1
                    relic_index = relic_index+1
except Exception as e :
    print(e)
    print(Main_link[k])
        
with pd.ExcelWriter('genshin.xlsx') as writer :
    Information.to_excel(writer, sheet_name='성유물 옵션', index=False)

with pd.ExcelWriter('genshin_set_relic.xlsx') as writer :
    Relic_Information.to_excel(writer, sheet_name='성유물', index=False)

 

  • 두 번째 코드 결과물

 

  • 세 번째 코드
import pandas as pd
from selenium import webdriver
import time
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as E
from openpyxl import *

# 원신/성유물 나무위키 링크
link = 'https://namu.wiki/w/%EC%9B%90%EC%8B%A0/%EC%84%B1%EC%9C%A0%EB%AC%BC'

driver = webdriver.Chrome('chromedriver.exe')
driver.get(link)
time.sleep(3)

Relic = pd.DataFrame({'성유물 세트' : [], '2세트' : [], '4세트' : [], '획득처' : [], '비경' : []})
total_index = 0

# 성유물 세트 효과 수집 과정
info = driver.find_elements(By.CLASS_NAME, 'TiHaw-AK._6803dcde6a09ae387f9994555e73dfd7')
for i in range(len(info)) :
    # 첫 번째 성유물이 검투사의 피날레이기 때문에 해당 부분이 기준
    # 여기서부터 끝까지가 성유물에 대한 정보가 존재
    if '검투사' in info[i].text :
        index_start = i
        break
# 전체적으로 3단위로 원하는 정보가 있음
for i in range(index_start, len(info), 3) :
    relic_info = info[i].text.split('\n')
    # 1세트 효과가 있는 4성 성유물은 생략한다.
    if '모시는 자' in relic_info[0] :
        continue
    # 획득처에서 비경을 구분하는 과정
    if '비경' in  relic_info[7] :
        place_index_start = relic_info[7].index(':')
        place = relic_info[7][place_index_start+2:]
        if ',' in place :
            place_end_index = place.index(',')
            place = place[:place_end_index]
    else :
        place = ''
    relic = [relic_info[0], relic_info[3], relic_info[5], relic_info[7], place]
    Relic.loc[total_index] = relic
    total_index = total_index+1

with pd.ExcelWriter('genshin_relic.xlsx') as writer :
    Relic.to_excel(writer, sheet_name='성유물', index=False)

 

  • 세 번째 코드 결과물

 

해당 데이터를 활용하여 원신 캐릭터의 성유물을 엑셀에서 쉽게 조회하는 포스팅은 아래에서 확인해주세요!

https://yhj9855.com/entry/%EC%9B%90%EC%8B%A0-%EC%84%B1%EC%9C%A0%EB%AC%BC-%EC%84%B8%ED%8C%85-%EC%97%91%EC%85%80%EB%A1%9C-%EC%89%BD%EA%B2%8C-%EB%B3%B4%EA%B8%B0-45-%EC%97%85%EB%8D%B0%EC%9D%B4%ED%8A%B8-%EA%B8%B0%EC%A4%80-%EC%B9%98%EC%98%A4%EB%A6%AC-%ED%8F%AC%ED%95%A8

 

[원신] 성유물 세팅 엑셀로 쉽게 보기 (4.5 업데이트 기준, 치오리 포함)

안녕하세요! 오늘은 원신 4.5 업데이트 모든 캐릭터 성유물 세팅 포스팅을 진행하겠습니다. 4.5 업데이트는 간단한 업데이트여서 호다닥 갖고 왔습니다. 캐릭터의 성유물 세팅은 엑셀 내 저장되

yhj9855.com

 

코드에 대해 궁금한 부분이 있으신 분들은 댓글로 남겨주시면, 답변 드리도록 하겠습니다!

★읽어주셔서 감사합니다★

728x90
반응형
728x90
반응형

안녕하세요! 네이버 뉴스가 24년 1월 25일부터 페이지가 보여주는 방식이 변경되면서, 이전 포스팅에서 진행했던 첫 번째 코드를 사용할 수 없게 되었습니다.

 

그래서 변경된 페이지에서 적용되는 크롤링 코드를 새로 가지고 왔습니다!

※ 두 번째 코드는 동일하게 적용됩니다.

 

해당 포스팅에서는 전체 코드만 첨부합니다.

크롤링할 페이지의 설명, 크롤링 진행 방식, 이전 크롤링 코드가 궁금하신 분들은 아래 링크에서 확인하실 수 있습니다.

https://yhj9855.com/entry/Crawling-%EB%84%A4%EC%9D%B4%EB%B2%84-%EB%89%B4%EC%8A%A4-%ED%81%AC%EB%A1%A4%EB%A7%81-1

 

[Crawling] 네이버 뉴스 크롤링 - 1

안녕하세요. 크롤링에서 가장 첫 포스팅을 네이버 뉴스 크롤링으로 하게 되었어요. 아무래도 바쁜 일상 속에서 매일 뉴스 기사를 파악하는 부분이 시간적으로 힘들었는데, 크롤링하고 데이터

yhj9855.com

 

크롤링의 자세한 과정이 궁금하신 분들은 아래 링크를 봐주시면 됩니다!

 

첫 번째 코드의 자세한 과정은 다음 포스팅에서 진행하겠습니다.

 

<두 번째 코드의 자세한 과정>

https://yhj9855.com/entry/Crawling-%EB%84%A4%EC%9D%B4%EB%B2%84-%EB%89%B4%EC%8A%A4-%ED%81%AC%EB%A1%A4%EB%A7%81-3

 

[Crawling] 네이버 뉴스 크롤링 - 3

안녕하세요. 오늘은 기존에 작성한 네이버 뉴스 크롤링 코드에서 두 번째 코드의 자세한 크롤링 과정을 포스팅 하겠습니다. 네이버 뉴스 크롤링 전체 코드를 확인하고 싶으신 분들은 아래 링크

yhj9855.com


[첫 번째 코드]

전체 코드

import pandas as pd
from selenium import webdriver
import time
from selenium.webdriver.common.by import By
from openpyxl import *

# 2024.01.25 부터 변경된 네이버 기사를 새로 크롤링하기 위해 만든 코드

link = 'https://news.naver.com/main/list.naver?mode=LS2D&sid2=229&sid1=105&mid=shm&date='
# 스크랩 하고 싶은 날짜를 년도월일 나열
# 날짜를 쉽게 바꾸기 위해 date를 따로 선언
date = '20240205'

# 메인 링크는 링크에 날짜가 붙은 구조이기 때문에 이렇게 작성해준다.
main_link = link + date
# number: 기사의 수, title: 기사 제목, link: 기사 링크
Main_link = pd.DataFrame({'number' : [], 'title' : [], 'link' : []})

# 크롬드라이버 실행
driver = webdriver.Chrome('chromedriver.exe')
driver.get(main_link)
time.sleep(3)

# 기사 더보기 버튼
more_button = driver.find_element(By.CLASS_NAME, 'section_more_inner._CONTENT_LIST_LOAD_MORE_BUTTON')

# 기사 더보기가 몇 개가 있을지 모르기 때문에 오류가 날 때까지 누르는 것으로 한다.
# 여기서 발생하는 오류란 버튼을 찾을 수 없다 즉, 버튼이 없을 때 발생하는 오류
while True :
    try :
        more_button.click()
        time.sleep(3)
    except :
        break

# 기사들의 정보가 담겨져 있는 곳
articles = driver.find_elements(By.CLASS_NAME, 'sa_text_title')
for i in range(len(articles)) :
	# 각 기사의 제목과 링크를 추출
    title = articles[i].text.strip()
    link = articles[i].get_attribute('href')
    li = [i+1, title, link]
    Main_link.loc[i] = li

# 엑셀 파일이 헷갈리지 않기 위해 엑셀 이름에 날짜를 넣음
excel_name = 'news_' + date + '.xlsx'
with pd.ExcelWriter(excel_name) as writer :
    Main_link.to_excel(writer, sheet_name='링크', index=False)

[두 번째 코드]

전체 코드

from bs4 import BeautifulSoup
import requests
import pandas as pd
from openpyxl import *
import time
import urllib

# 첫 번째 코드에서 지정한 뉴스의 링크들이 담긴 파일
link = pd.read_excel('news_20231222.xlsx')
# 엑셀 파일이 헷갈리지 않게 최종 결과파일에도 날짜를 넣어줌
excel_name = 'news_detail_20231222.xlsx'
Main_link = list(link['link'])
# number: 기사의 수, title: 기사의 제목, information: 본문 내용, link: 기사의 링크
Information = pd.DataFrame({'number' : [], 'title' : [], 'information' : [], 'link' : []})
# 본문 내용만 추가하면 되기 때문에 데이터 프레임에 미리 나머지 내용을 담아줌
Information['number'] = link['number']
Information['title'] = link['title']
Information['link'] = link['link']
information = []

for main_link in Main_link :
	# 기사가 전체적으로 2개의 구조를 가지고 있음 (게임/리뷰 카테고리에 한하여)
    # 하나의 구조를 기준으로 삼고, 해당 부분에서 오류가 발생하면 다음 구조의 기사로 판단
    try :
        response = requests.get(main_link, headers={'User-Agent':'Moailla/5.0'})
        if response.status_code == 200 :
            html = response.content
            soup = BeautifulSoup(html, 'html.parser')
            # 기사의 본문 내용만 담고 있는 부분
            info = soup.find('div', {'id' : 'newsct_article'}).text.strip()
            # 기사 내용 데이터 분석을 위해서 줄바꿈을 띄어쓰기로 변경
            info = info.replace('\n', '')
            information.append(info)
    except :
    	# 다른 구조의 기사 크롤링 코드
        # 여기서 오류가 나는 경우는 게임/리뷰 기사가 아닌 다른 카테고리의 기사로 판단
        try :
            response = requests.get(main_link, headers={'User-Agent':'Moailla/5.0'})
            if response.status_code == 200 :
                html = response.content
                soup = BeautifulSoup(html, 'html.parser')
                # 기사의 본문 내용을 담고 있는 부분
                info = soup.find('div', {'id' : 'newsEndContents'}).text.strip()
                info = info.replace('\n', '')
                # 해당 구조의 기사는 기자의 정보가 본문과 무조건 같이 존재
                # 기자의 정보 부분은 필요가 없기 때문에 기자 정보의 기준점이 되는 부분을 찾음
                # 기자의 정보 기준이 기사제공이라는 단어이기 때문에 그 이후는 삭제
                end = info.index('기사제공')
                info = info[:end]
                information.append(info)
        # 다른 카테고리의 기사가 들어올 경우에는 정보를 담지 않는 것으로 함
        except Exception as e :
        	info = ''
            information.append(info)
            # 오류가 발생하는 이유와 발생하는 링크를 출력하여 오류를 확인하는 장치
            #print(e)
            #print(main_link)

Information['information'] = information

with pd.ExcelWriter(excel_name) as writer :
    Information.to_excel(writer, sheet_name='결과값', index=False)

 

뉴스 크롤링 데이터를 이용한 워드클라우드 포스팅은 아래에서 확인해주세요!

https://yhj9855.com/entry/%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%B6%84%EC%84%9D-%ED%95%9C%EA%B8%80%EB%A1%9C-%EC%9B%8C%EB%93%9C%ED%81%B4%EB%9D%BC%EC%9A%B0%EB%93%9C-%EB%A7%8C%EB%93%A4%EA%B8%B0-feat%EB%84%A4%EC%9D%B4%EB%B2%84-%EB%89%B4%EC%8A%A4-%ED%81%AC%EB%A1%A4%EB%A7%81

 

[데이터 분석] 한글로 워드클라우드 만들기 (feat.네이버 뉴스 크롤링)

안녕하세요. 오늘은 크롤링 데이터로 워드클라우드(wordcloud)를 만드는 방법에 대해 포스팅 하겠습니다. 크롤링 데이터는 네이버 뉴스 크롤링을 사용할 예정입니다! 네이버 뉴스 크롤링 과정이

yhj9855.com

 

뉴스 크롤링 데이터를 이용한 토픽모델링 포스팅은 아래세어 확인해주세요!

https://yhj9855.com/entry/%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%B6%84%EC%84%9D-%ED%95%9C%EA%B8%80-%EB%8D%B0%EC%9D%B4%ED%84%B0-%ED%86%A0%ED%94%BD-%EB%AA%A8%EB%8D%B8%EB%A7%81-%EC%A7%84%ED%96%89%ED%95%98%EA%B8%B0

 

[데이터 분석] 한글 데이터 토픽 모델링 진행하기

안녕하세요! 오늘은 한글 데이터로 토픽 모델링(topic modeling)을 하는 방법에 대해 포스팅 하겠습니다. 한글 데이터는 네이버 뉴스 크롤링 데이터를 사용할 예정입니다. 네이버 뉴스 크롤링 과정

yhj9855.com

코드에 대해 궁금한 부분이 있으신 분들은 댓글로 남겨주시면, 답변 드리도록 하겠습니다.

★읽어주셔서 감사합니다★

728x90
반응형
728x90
반응형

안녕하세요!

오늘은 한국어 데이터 분석을 위해 꼭 필요한 Konlpy(코엔엘파이) 라이브러리에 대해서 포스팅 하겠습니다.

 

  • Konlpy 란?

한국어 자연어 처리를 위한 파이썬 라이브러리 입니다.

 

  • Konlpy의 특징

Konlpy은 다양한 한국어 형태소 분석기를 지원하기 때문에 같은 문장을 다른 방식으로 분석을 하는 것이 가능합니다.

※ Konlpy는 설치 및 사용 환경을 설정하는 과정이 조금 복잡하기 때문에 따로 포스팅을 진행하도록 하겠습니다!

 

  • Konlpy이 제공하는 형태소 분석기 종류

Konlpy은 아래 5가지 형태소 분석기를 제공합니다.

  1. Kkma
  2. Komoran
  3. Hannaum
  4. Okt (구 Twittrer)
  5. Mecab: 일본어 형태소 분석기를 한국어로 변경한 분석기로, 세종 말뭉치로 만들어진 CSV 형태의 사전 (Windows에서 잘 지원이 되지 않음)

Mecab은 Windows에서 잘 지원이 되지 않기 때문에 나머지 4개의 형태소 분석기만 비교를 해보도록 하겠습니다!

 

  • Kkma

서울대 지능형 데이터 시스템 연구실에서 개발한 형태소 분석기 입니다.

비교적 정확한 품사를 구분하는 형태소 분석기로 띄어쓰기 오류에 강하고, 다의어 처리에 효과적이지만, 단어의 수가 증가할수록 분석을 진행하는 시간이 가장 크게 느려지는게 특징입니다.

Kkma는 4가지의 함수를 제공합니다.

아래는 4가지 함수와 코드 예시입니다.

from konlpy.tag import Kkma

kkma = Kkma()
text = "꼬꼬마 형태소 분석기를 사용해 봅시다."

 

  • morphs: 문장을 형태소 단위로 추출
morphs_result = kkma.morphs(text)

Output: ['꼬꼬마', '형태소', '분석', '기', '를', '사용', '하', '어', '보', 'ㅂ시다', '.']

 

  • nouns: 문장을 명사 단위로 추출
nouns_result = kkma.nouns(text)

Output: ['꼬꼬마', '형태소', '분석', '분석기']

 

  • pos: 문장을 형태소 단위로 추출, 각 형태소의 품사와 함께 반환
pos_result = kkma.pos(text)

Output: [('꼬꼬마', 'NNG'), ('형태소', 'NNG'), ('분석', 'NNG'), ('기', 'NNG'), ('를', 'JKO'), ('사용', 'NNG'), ('하', 'XSV'), ('어', 'ECS'), ('보', 'VXV'), ('ㅂ시다', 'EFN'), ('.', 'SF')]

 

  • sentences : 여러 문장으로 이루어진 텍스트를 문장 단위로 추출
text = "꼬꼬마 형태소 분석기를 사용해 봅시다. 이것은 간단한 예시입니다."
sentences_result = kkma.sentences(text)

Output: ['꼬꼬마 형태소 분석기를 사용해 봅시다.', '이것은 간단한 예시입니다.']

 

 

  • Komoran

Shineware에서 개발한 형태소 분석기 입니다.

대용량 말뭉치를 학습하여 품사 태깅에 높은 정확도를 보이며, 빠른 분석 속도높은 성능을 보유하고 있습니다.

Komoran은 3가지의 함수를 제공합니다.

아래는 3가지 함수와 코드 예시입니다.

from konlpy.tag import Komoran

komoran = Komoran()
text = "코모란 형태소 분석기를 사용해 봅시다."

 

  • morphs: 문장을 형태소 단위로 추출
morphs_result = komoran.morphs(text)

Output: ['코모란', '형태소', '분석', '기', '를', '사용', '하', '아', '보', 'ㅂ시다', '.']

 

  • nouns: 문장을 명사 단위로 추출
nouns_result = komoran.nouns(text)

Output: ['코모란', '형태소', '분석', '기']

 

  • pos: 문장을 형태소 단위로 추출, 각 형태소의 품사와 함께 반환
pos_result = komoran.pos(text)

Output: [('코모란', 'NNP'), ('형태소', 'NNG'), ('분석', 'NNG'), ('기', 'NNG'), ('를', 'JKO'), ('사용', 'NNG'), ('하', 'XSV'), ('아', 'EC'), ('보', 'VX'), ('ㅂ시다', 'EF'), ('.', 'SF')]

 

  • Hannaum

국립 국어원에서 개발한 형태소 분석기 입니다.

복합 명사를 적절하게 처리하고, 복잡한 구조의 문장에서도 안정적으로 형태소 분석을 수행합니다.

Hannaum은 3가지의 함수를 제공합니다.

아래는 3가지 함수와 코드 예시입니다.

from konlpy.tag import Hannanum

hannanum = Hannanum()
text = "한나눔 형태소 분석기를 사용해 봅시다."

 

  • morphs: 문장을 형태소 단위로 추출
morphs_result = hannanum.morphs(text)

Output: ['한나눔', '형태소', '분석', '기', '를', '사용', '하', '어', '보', 'ㅂ시다', '.']

 

  • nouns: 문장을 명사 단위로 추출
nouns_result = hannanum.nouns(text)

Output: ['한나눔', '형태소', '분석', '기']

 

  • pos: 문장을 형태소 단위로 추출, 각 형태소의 품사와 함께 반환
pos_result = hannanum.pos(text)

Output: [('한나눔', 'N'), ('형태소', 'N'), ('분석', 'N'), ('기', 'N'), ('를', 'J'), ('사용', 'N'), ('하', 'X'), ('어', 'E'), ('보', 'P'), ('ㅂ시다', 'E'), ('.', 'S')]

 

 

  • Okt

Twitter에서 개발한 형태소 분석기 입니다.

복합 명사 분석에 우수하며, 속도가 빠르고 경량화된 형태로 제공되어 다양한 환경에서 사용할 수 있습니다.

Okt는 4가지의 함수를 제공합니다.

아래는 4가지 함수와 코드 예시입니다.

from konlpy.tag import Okt

okt = Okt()
text = "Okt 형태소 분석기를 사용해 봅시다."

 

  • morphs: 문장을 형태소 단위로 추출
morphs_result = okt.morphs(text)

Output: ['Okt', '형태소', '분석기', '를', '사용', '해', '봅시다', '.']

 

  • nouns: 문장을 명사 단위로 추출
nouns_result = okt.nouns(text)

Output: ['Okt', '형태소', '분석기']

 

  • pos: 문장을 형태소 단위로 추출, 각 형태소의 품사와 함께 반환
pos_result = okt.pos(text)

Output: [('Okt', 'Alpha'), ('형태소', 'Noun'), ('분석기', 'Noun'), ('를', 'Josa'), ('사용', 'Noun'), ('해', 'Verb'), ('봅시다', 'Verb'), ('.', 'Punctuation')]

 

  • phrases: 문장을 어구 단위로 추출
phrases_result = okt.phrases(text)

Output: ['Okt', 'Okt 형태소', '형태소', '분석기', '사용', 'Okt 형태소 분석기', '분석']

 

Konlpy를 활용하여 한국어 데이터 기반 워드 클라우드, 토픽 모델링 데이터 분석을 진행한 예시는 아래 페이지에서 확인하실 수 있습니다!

https://yhj9855.com/entry/%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%B6%84%EC%84%9D-%ED%95%9C%EA%B8%80%EB%A1%9C-%EC%9B%8C%EB%93%9C%ED%81%B4%EB%9D%BC%EC%9A%B0%EB%93%9C-%EB%A7%8C%EB%93%A4%EA%B8%B0-feat%EB%84%A4%EC%9D%B4%EB%B2%84-%EB%89%B4%EC%8A%A4-%ED%81%AC%EB%A1%A4%EB%A7%81

 

[데이터 분석] 한글로 워드클라우드 만들기 (feat.네이버 뉴스 크롤링)

안녕하세요. 오늘은 크롤링 데이터로 워드클라우드(wordcloud)를 만드는 방법에 대해 포스팅 하겠습니다. 크롤링 데이터는 네이버 뉴스 크롤링을 사용할 예정입니다! 네이버 뉴스 크롤링 과정이

yhj9855.com

 

https://yhj9855.com/entry/%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%B6%84%EC%84%9D-%ED%95%9C%EA%B8%80-%EB%8D%B0%EC%9D%B4%ED%84%B0-%ED%86%A0%ED%94%BD-%EB%AA%A8%EB%8D%B8%EB%A7%81-%EC%A7%84%ED%96%89%ED%95%98%EA%B8%B0

 

[데이터 분석] 한글 데이터 토픽 모델링 진행하기

안녕하세요! 오늘은 한글 데이터로 토픽 모델링(topic modeling)을 하는 방법에 대해 포스팅 하겠습니다. 한글 데이터는 네이버 뉴스 크롤링 데이터를 사용할 예정입니다. 네이버 뉴스 크롤링 과정

yhj9855.com

 

궁금한 부분이 있으신 분들은 댓글로 남겨주시면, 답변 드리도록 하겠습니다!

★읽어주셔서 감사합니★

728x90
반응형
728x90
반응형

안녕하세요! 오늘은 데이터 분석에서 자주 활용하는 주피터 노트북(Jupyter Notebook) 을 사용하는 방법에 대해서 포스팅 하겠습니다.

 

  • 주피터 노트북이란?

대화형 컴퓨팅 환경을 제공하는 오픈 소스 웹 기반 플랫폼입니다.

 

  • 주피터 노트북의 장점

1. 주피터 노트북은 대화형 인터페이스를 제공하고 있기 때문에 결과를 즉시 확인할 수 있습니다.

※ 사진 속 예시는 제가 작성한 웹툰 데이터 분석 코드의 일부입니다.

 

2. 주피터 노트북은 시각화 및 그래프를 지원하고 있기 때문에 노트북에 바로 결과가 표시되어 시각적으로 확인하기 쉽습니다.

※ 사진 속 예시는 제가 작성한 웹툰 데이터 분석 코드의 일부입니다.

 

3. 주피터 노트북은 다른 사용자와 공유하기 쉽습니다.

 기본적인 파일 형태인 ipynb는 GitHub 등의 협업 플랫폼에서 공유가 가능하기 때문에 협업하기 어렵지 않습니다.

또한 HTML 파일로 내보내기가 가능하기 때문에 결과물과 함께 공유가 가능하며, HTML 파일이기 때문에 다른 사용자가 열어보기 쉽습니다.

 

 

  • 주피터 노트북의 사용처

주피터 노트북은 데이터 분석 라이브러리를 모두 사용할 수 있고, 분석 후 시각화 작업이 수월하기 때문에 데이터 분석에서 많이 활용되고 있습니다.

또한 머신 러닝, 딥러닝 모델 학습이 가능하기 때문에 해당 분야에서도 자주 활용하고 있습니다.

 

  • 주피터 노트북 설치 및 실행하기

파이썬이 설치되신 분들은 아주 쉽게 주피터 노트북을 설치할 수 있습니다!

설치 및 실행 과정은 아래와 같습니다.

 

1. cmd 창을 여신 후에 pip install jupyter notebook 을 실행해주시면 됩니다.

※ cmd 창은 윈도우 검색에서 cmd라고 검색하시면 나오는 명령 프롬포트를 의미합니다.

 

2. 주피터 노트북을 실행하고자 하는 폴더로 이동합니다.

주피터 노트북은 같은 폴더에 함께 있는 파일만 인식하는 경우가 많기 때문에 폴더를 잘 선택해야 합니다.

 

3. 폴더의 빈 공간에 Shift+마우스 우클릭을 실행한 후, Power Shell 창을 열어줍니다.

※ 높은 버전의 Window에서는 '더 많은 옵션 표시'를 누르면 Power Shell 창 열기 버튼이 나타납니다.

4. Power Shell 창에 jupyter notebook 을 입력 후 실행해주시면 됩니다.

cmd에서 바로 실행하는 경우도 있는데, cmd보다 Power Shell의 기능이 더 강력하고 확장성이 뛰어나기 때문에 Power Shell로 실행하시는 것을 추천합니다!

 

5. 자동으로 주피터 노트북과 연결된 인터넷 창이 뜨면 실행 완료입니다!

만약 자동으로 연결된 인터넷 창이 뜨지 않는다면, Power Shell 창에 나와있는 인터넷 주소를 복사하여 입력하시면 됩니다.

 

 

  • 주피터 노트북에 코드 작성하기

이제 주피터 노트북을 실행하였으니, 코드를 작성해보도록 하겠습니다.

저는 보통 Python(파이썬) 코딩을 진행합니다만, R과 같이 다른 프로그래밍 언어도 사용가능합니다!

하지만 이 글에서는 파이썬 코드를 작성하는 법만 다루도록 하겠습니다.

주피터 노트북에서 파이썬 코드를 작성하는 방법은 아래와 같습니다.

 

1. 'New' 버튼을 클릭하여 파이썬 코드를 작성할 파일을 생성한다.

파일의 이름은 기본적으로 Untitled으로 생성되기 때문에 파일의 이름은 변경해주셔야 합니다.

※ Untitled을 더블 클릭하면 이름을 바로 변경할 수 있습니다.

2. 코드 셀에 원하는 코드를 작성해줍니다.

주피터 노트북은 기본적으로 코드를 실행하는 코드 셀을 제공해주고 있기 때문에 코드를 바로 작성해주시면 됩니다!

만약 코드가 아닌 일반 텍스트로 작성하고 싶은 경우에는 'm' 단축키를 누르거나, 상단의 'Code'를 'Markdown'으로 변경하여 코드 셀을 텍스트 셀로 변환해주시면 됩니다.

 

3. 코드가 작성 완료된 셀을 실행시켜줍니다.

코드 셀을 실행하는 방법은 총 3가지 방법이 있습니다.

  1. Ctrl+Enter: 현재의 코드 셀만 실행을 하고, 새로운 코드 셀을 추가하지 않습니다.
  2. 주피터 노트북의 실행 키를 누르는 방법: 현재의 코드 셀만 실행을 하고, 새로운 코드 셀을 추가합니다.
    ※ ▶Run 버튼이 실행 키 입니다.
  3. Shift+Enter: 현재의 코드 셀만 실행을 하고, 새로운 코드 셀을 추가합니다.

▶▶ 이렇게 생긴 버튼을 누르게 되면 처음 코드 셀부터 마지막 코드 셀까지 순차적으로 실행이 됩니다.

실행된 순서는 In [ ]에서 [ ] 안의 숫자로 확인할 수 있고, 굳이 순서대로가 아닌 제가 원하는 셀만 실행시킬 수 있기 때문에 실행 순서를 잘 이용하면 코드를 효율적으로 작성할 수 있습니다!

 

4. 완성된 코드 저장합니다.

주피터 노트북에 코드를 모두 작성했다면, Ctrl+s 단축키를 사용하여 저장해주면 됩니다.

주피터 노트북은 어느 정도 실시간 저장이 보장되지만, 저장하는 습관 길러두시는 편이 좋습니다!

저장된 파일은 .ipynb 라는 확장자를 가지는데요.

더블 클릭으로 여는 것은 조금 어렵고, 주피터 노트북에서 열어보시거나 Github에 올려서 확인하실 수 있습니다!

 

주피터 노트북은 활용을 잘하면 정말 유용한 코드 플랫폼이기 때문에 사용법을 익혀두시는 걸 정말 추천드립니다!

 

제가 주피터 노트북을 활용하여 워드 클라우드, 토픽 모델링 데이터 분석을 진행한 예시는 아래 페이지에서 확인하실 수 있습니다!

https://yhj9855.com/entry/%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%B6%84%EC%84%9D-%ED%95%9C%EA%B8%80%EB%A1%9C-%EC%9B%8C%EB%93%9C%ED%81%B4%EB%9D%BC%EC%9A%B0%EB%93%9C-%EB%A7%8C%EB%93%A4%EA%B8%B0-feat%EB%84%A4%EC%9D%B4%EB%B2%84-%EB%89%B4%EC%8A%A4-%ED%81%AC%EB%A1%A4%EB%A7%81

 

[데이터 분석] 한글로 워드클라우드 만들기 (feat.네이버 뉴스 크롤링)

안녕하세요. 오늘은 크롤링 데이터로 워드클라우드(wordcloud)를 만드는 방법에 대해 포스팅 하겠습니다. 크롤링 데이터는 네이버 뉴스 크롤링을 사용할 예정입니다! 네이버 뉴스 크롤링 과정이

yhj9855.com

https://yhj9855.com/entry/%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%B6%84%EC%84%9D-%ED%95%9C%EA%B8%80-%EB%8D%B0%EC%9D%B4%ED%84%B0-%ED%86%A0%ED%94%BD-%EB%AA%A8%EB%8D%B8%EB%A7%81-%EC%A7%84%ED%96%89%ED%95%98%EA%B8%B0

 

[데이터 분석] 한글 데이터 토픽 모델링 진행하기

안녕하세요! 오늘은 한글 데이터로 토픽 모델링(topic modeling)을 하는 방법에 대해 포스팅 하겠습니다. 한글 데이터는 네이버 뉴스 크롤링 데이터를 사용할 예정입니다. 네이버 뉴스 크롤링 과정

yhj9855.com

 

궁금한 부분이 있으신 분들은 댓글로 남겨주시면, 답변 드리도록 하겠습니다.

★읽어주셔서 감사합니다★

 

728x90
반응형
728x90
반응형

안녕하세요! 오늘은 한글 데이터로 토픽 모델링(topic modeling)을 하는 방법에 대해 포스팅 하겠습니다.

 

한글 데이터는 네이버 뉴스 크롤링 데이터를 사용할 예정입니다.

네이버 뉴스 크롤링 과정이 궁금하신 분은 아래 링크를 확인해주세요:)

https://yhj9855.tistory.com/entry/Crawling-%EB%84%A4%EC%9D%B4%EB%B2%84-%EB%89%B4%EC%8A%A4-%ED%81%AC%EB%A1%A4%EB%A7%81-1

 

[Crawling] 네이버 뉴스 크롤링 - 1

안녕하세요. 크롤링에서 가장 첫 포스팅을 네이버 뉴스 크롤링으로 하게 되었어요. 아무래도 바쁜 일상 속에서 매일 뉴스 기사를 파악하는 부분이 시간적으로 힘들었는데, 크롤링하고 데이터

yhj9855.com


  • 토픽 모델링이란?

비지도 학습으로, 텍스트 문서 집합을 하나 이상의 추상적인 주제(=토픽)로 분류하는 작업을 말합니다.

텍스트의 구조를 파악하거나, 다량의 텍스트를 분석할 때 자주 사용되는 데이터 분석 방법입니다!

 

토픽 모델링을 진행하는 건 Jupyter Notebook에서 하시는 걸 추천드립니다.

Jupyter Notebook를 설치하고 사용하는 방법은 아래 링크에서 확인해주세요!

https://yhj9855.tistory.com/entry/%EC%A3%BC%ED%94%BC%ED%84%B0-%EB%85%B8%ED%8A%B8%EB%B6%81Jupyter-Notebook-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0

 

주피터 노트북(Jupyter Notebook) 사용하기

안녕하세요! 오늘은 데이터 분석에서 자주 활용하는 주피터 노트북(Jupyter Notebook) 을 사용하는 방법에 대해서 포스팅 하겠습니다. 주피터 노트북이란? 대화형 컴퓨팅 환경을 제공하는 오픈 소스

yhj9855.com


  • 필요한 라이브러리 설치

토픽 모델링은 머신러닝 모델 중 LDA 모델을 사용합니다.

LDA 모델에 대한 자세한 설명은 아래 링크에서 확인해주세요!

https://ko.wikipedia.org/wiki/%EC%9E%A0%EC%9E%AC_%EB%94%94%EB%A6%AC%ED%81%B4%EB%A0%88_%ED%95%A0%EB%8B%B9

 

잠재 디리클레 할당 - 위키백과, 우리 모두의 백과사전

위키백과, 우리 모두의 백과사전. 자연어 처리에서 잠재 디리클레 할당(Latent Dirichlet allocation, LDA)은 주어진 문서에 대하여 각 문서에 어떤 주제들이 존재하는지를 서술하는 대한 확률적 토픽 모

ko.wikipedia.org

 

저는 머신러닝을 sklearn 라이브러리를 사용했기 때문에 sklearn 라이브러리를 설치해주시면 됩니다!

sklearn 라이브러리 설치가 어려우신 분들은 colab에서 진행해주셔도 됩니다.

colab의 자세한 사용법은 추후 따로 포스팅을 진행하도록 하겠습니다!

 

또한, 한글 텍스트 데이터를 다루고 있기 때문에 이를 다루는 라이브러리가 필요합니다.

저는 한글 텍스트를 다루는 라이브러리 중 Konply 라이브러리를 사용했습니다.

 

Konply 라이브러리와 관련된 자세한 설명은 아래 포스팅을 확인해주세요!

https://yhj9855.tistory.com/entry/%ED%95%9C%EA%B5%AD%EC%96%B4-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%B6%84%EC%84%9D-%ED%95%84%EC%88%98-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC-Konlpy%EC%BD%94%EC%97%94%EC%97%98%ED%8C%8C%EC%9D%B4

 

한국어 데이터 분석 필수 라이브러리 Konlpy(코엔엘파이)

안녕하세요! 오늘은 한국어 데이터 분석을 위해 꼭 필요한 Konlpy(코엔엘파이) 라이브러리에 대해서 포스팅 하겠습니다. Konlpy 란? 한국어 자연어 처리를 위한 파이썬 라이브러리 입니다. Konlpy의

yhj9855.com

 

  • 데이터 로드 후 정제하기

필요한 라이브러리를 설치한 후에는 pandas를 사용하여 데이터를 불러옵니다.

저는 2024년 01월 17일 네이버 게임/리뷰 카테고리의 기사 크롤링 데이터를 불러와 정제를 진행하도록 하겠습니다.

# 파일 이름만 적을 때는 파일이 실행 파일과 같은 곳에 저장되어 있어야 한다.
result = pd.read_excel('파일 이름')
# 기사의 제목 데이터
Title = list(result['title'])
# 기사의 내용 데이터
Information = list(result['information'])
# 기사의 제목과 내용을 하나의 리스트에 담았다.
Total = []
for i in range(len(result)) :
    Total.append(Title[i]+' '+Information[i])

※ Total 데이터의 양이 너무 많아서 데이터 확인은 진행하지 않겠습니다.

명사로 데이터 분류하기

토픽을 제대로 분류하기 위해서는 데이터를 의미 있는 데이터만 남기는 것이 중요합니다.

그 중 가장 빠른 방법이 명사인 데이터만 남기는 것인데요.

 

명사로 분류를 하지 않을 경우, '있다', '있는' 과 같이 보기만 하면 이해하지 못하는 단어들이 높은 비중을 차지하는 경우가 많기 때문에 제대로 데이터 분석이 되지 않는 경우가 많이 발생합니다.

 

명사로 분류하기 위해 Konpy 라이브러리를 사용하려고 하는데요.

Konply가 지원하는 형태소 분석 중 저는 Komoran을 사용하였습니다.

Konply이 지원하는 다른 형태소 분석은 추후에 포스팅 진행하도록 하겠습니다!

 

명사로 형태소 분석을 하는 코드는 아래와 같습니다.

# 형태소 분석기로 Komoran을 사용
komoran = Komoran()
# Total 데이터를 명사로 분류한 후에 띄어쓰기로 붙여넣기 진행
# 줄바꿈으로 진행하도 상관없으나, 줄바꿈으로 진행 시, 이후 띄어쓰기 대신 모두 줄바꿈으로 변경해야한다.
total_nouns = [' '.join(komoran.nouns(doc)) for doc in Total]
  • 추가 전처리 진행하기

total_nouns 데이터는 이제 명사로만 이루어진 데이터입니다.

그대로 토픽 모델링을 진행해도 되지만, 생각보다 의미 없는 데이터가 많이 존재하기 때문에 추가적으로 데이터 전처리를 진행해주는 것이 좋습니다.

예를 들면 '것', '이', '등' 과 같은 단어를 삭제하기 위해서 두 글자 명사만 넣어준다거나, 특정 카테고리의 뉴스이기 때문에 자주 등장하는 명사는 제거한다거나, 기업의 이름들이 명사로 이상하게 분류되어 있는 부분을 원래 기업 이름으로 변경을 해준다거나 하는 방법으로 데이터 전처리를 진행해주시면 됩니다.

 

제가 진행한 전처리 코드는 아래와 같습니다.

# 추가 데이터 전처리 과정
for i in range(len(total_nouns)) :
    
    # 자주 등장하는 단어들을 꾸준히 붙여준다. (기업 이름 등)
    # total_nouns[i]]가 하나의 문자열이기 때문에 reaplace를 통해 변경한다.
    total_nouns[i] = total_nouns[i].replace('위 메이드', '위메이드')
    total_nouns[i] = total_nouns[i].replace('위 믹스', '위믹스')
    total_nouns[i] = total_nouns[i].replace('컴투스 홀', '컴투스홀딩스')
    total_nouns[i] = total_nouns[i].replace('개발 사', '개발사')
    total_nouns[i] = total_nouns[i].replace('펄 어비스', '펄어비스')
    total_nouns[i] = total_nouns[i].replace('콜 라보', '콜라보')
    total_nouns[i] = total_nouns[i].replace('카 테 고리', '카테고리')
    total_nouns[i] = total_nouns[i].replace('확률 형', '확률형')
    total_nouns[i] = total_nouns[i].replace('역대 급', '역대급')
    total_nouns[i] = total_nouns[i].replace('마비 노기', '마비노기')
    total_nouns[i] = total_nouns[i].replace('게임 위', '게임위')
    total_nouns[i] = total_nouns[i].replace('컬 래 버 레이 션', '콜라보레이션')
    total_nouns[i] = total_nouns[i].replace('콜 라보 레이 션', '콜라보레이션')
    total_nouns[i] = total_nouns[i].replace('빅 게임', '빅게임')
    total_nouns[i] = total_nouns[i].replace('엔 씨', '엔씨')
    total_nouns[i] = total_nouns[i].replace('스타트 업', '스타트업')
    total_nouns[i] = total_nouns[i].replace('디바 이스', '디바이스')
    total_nouns[i] = total_nouns[i].replace('선택 지', '선택지')
    total_nouns[i] = total_nouns[i].replace('치지 직', '치지직')
    total_nouns[i] = total_nouns[i].replace('어 플리 케이 션', '어플리케이션')
    total_nouns[i] = total_nouns[i].replace('게임 쇼', '게임쇼')
    total_nouns[i] = total_nouns[i].replace('아스 달', '아스달')
    total_nouns[i] = total_nouns[i].replace('김실 장', '김실장')
    total_nouns[i] = total_nouns[i].replace('행 안부', '행안부')
    
    # 게임 뉴스이기 때문에 게임과 관련된 부분, 뉴스와 관련된 부분은 제거한다.
    total_nouns[i] = total_nouns[i].replace('게임', '')
    total_nouns[i] = total_nouns[i].replace('기자', '')
    total_nouns[i] = total_nouns[i].replace('기사', '')
    total_nouns[i] = total_nouns[i].replace('진행', '')
    total_nouns[i] = total_nouns[i].replace('이용자', '')
    total_nouns[i] = total_nouns[i].replace('플레이', '')
    total_nouns[i] = total_nouns[i].replace('이번', '')

	# 매일매일 기사에서 반복되는 단어들을 삭제한다.
    # 의미가 없는 단어들은 아니지만, 지속적으로 나오면서 의미를 부여하기 어려운 단어가 되었다.
    total_nouns[i] = total_nouns[i].replace('지난해', '')
    total_nouns[i] = total_nouns[i].replace('전년', '')
    total_nouns[i] = total_nouns[i].replace('콘텐츠', '')
    total_nouns[i] = total_nouns[i].replace('출시', '')
    total_nouns[i] = total_nouns[i].replace('서비스', '')
    total_nouns[i] = total_nouns[i].replace('모바일', '')
    total_nouns[i] = total_nouns[i].replace('제공', '')
    total_nouns[i] = total_nouns[i].replace('예정', '')
	
    # 단어가 두 글자 이상인 것만 토픽 모델링을 진행할 데이터에 넣어준다.
	a = total_nouns[i].split(' ')
    data = ''
    for j in a :
        if len(j) >= 2 :
            # 동일한 이유로 띄어쓰기로 붙여 넣는다.
            # 마찬가지로 줄바꿈으로 진행해도 된다.
            data = data+' '+j
    total_nouns[i] = data

저는 total_nouns의 일부를 확인하고 진행을 하고 있기 때문에 여러분들은 여러분들의 데이터에 맞게 전처리를 진행하시면 됩니다!

  • LDA 모델에 학습하기 알맞게 데이터 변형하기

데이터 전처리가 끝난 후에는 LDA 모델에 학습하기 알맞게 데이터를 변형해야 합니다.

데이터를 변형하는 코드는 아래와 같습니다.

# CountVectorizer 객체 생성
# CountVectorizer는 문서에서 단어의 빈도수를 계산하는 도구이다.
CV_vectorizer = CountVectorizer()

# total_nouns에 있는 단어의 빈도수를 행렬로 변경한다.
X = CV_vectorizer.fit_transform(total_nouns)

 

  • LDA 모델 생성 및 데이터 학습

이제 데이터가 완성되었으니, LDA 모델을 만들어 데이터를 학습시키도록 하겠습니다!!

LDA 모델을 만드는 코드는 아래와 같습니다.

# 토픽의 개수를 지정한다.
num_topics = 6

# LDA 모델을 생성한다.
# 동일한 결과물을 얻기 위해서 random_state(난수)를 42로 고정한다.
lda = LatentDirichletAllocation(n_components=num_topics, random_state=42)

# 위에서 만든 데이터 X를 LDA 모델에 학습을 시킨다.
# 이제 lda는 데이터 X가 6개의 토픽으로 분류된 정보가 담겨있다.
lda.fit(X)
  • 각 토픽 내 주요 키워드 찾기

토픽으로 분류를 완료하였으니, 각 토픽이 어떤 키워드를 가지고 있는지 확인해보도록 하겠습니다.

저는 각 토픽마다 7개의 키워드를 추출해서 데이터 프레임을 새로 만들었습니다!

키워드의 수는 원하는대로 지정하시면 됩니다.

키워드를 추출하는 코드는 아래와 같습니다.

# CountVectorizer를 통해 추출된 단어의 목록을 얻는다.
# 단어의 목록은 array로 저장되어 있다.
CV_feature_names = CV_vectorizer.get_feature_names_out()

# 각 토픽의 키워드를 담을 리스트
# 여기에 초기화를 진행해주지 않으면, 다른 날짜의 기사를 진행할 때 진행이 잘 되지 않을 수 있다.
topic_keywords = []

# 토픽 수를 구분하는 변수
topic_index = 1

# 키워드 수를 구분하는 변수
# 키워드 수를 변경하고 싶다면, 숫자를 원하는 키워드 수로 변경하면 된다.
num_word = 7

# lda.components_가 이중 array로 되어 있기 때문에 데이터를 쉽게 다루기 위해수 enumerate로 데이터를 가져온다.
for topic_idx, topic in enumerate(lda.components_):
    # topic에는 단어의 빈도 확률이 들어있기 때문에 가장 높은 빈도 확률 7개의 인덱스를 추출한다.
    top_keywords_idx = topic.argsort()[::-1][:num_word]
    # 단어 목록에서 빈도 확률과 동일한 인덱스를 가진 단어를 추출한다.
    top_keywords = [CV_feature_names[i] for i in top_keywords_idx]
    # 토픽을 구분하는 값을 맨 앞에 삽입해준다.
    top_keywords.insert(0, 'Topic %d' %(topic_index))
    topic_index = topic_index+1
    topic_keywords.append(top_keywords)

# 추출한 7개의 키워드를 데이터 프레임으로 변경한다.
df_topic_keywords = pd.DataFrame(topic_keywords, columns=["Topic"]+ [f"Keyword {i+1}" for i in range(num_word)])

이렇게 만들어진 df_topic_keywords의 결과물은 아래와 같습니다!

저는 6개의 토픽과 7개의 키워드로 진행을 했기 때문에 이런 결과가 나왔습니다.

실제 토픽의 수와 비슷할수록 정확하게 토픽을 구분하지만, 실제 토픽의 수를 알 수 없으니 다양하게 해보시길 바랍니다.

전체코드

import pandas as pd
from konlpy.tag import *
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.decomposition import LatentDirichletAllocation

result = pd.read_excel('파일 이름')
Title = list(result['title'])
Information = list(result['information'])

Total = []
for i in range(len(result)) :
    Total.append(Title[i]+' '+Information[i])
    
komoran = Komoran()
total_nouns = [' '.join(komoran.nouns(doc)) for doc in Total]

# 전처리 과정
for i in range(len(total_nouns)) :
    total_nouns[i] = total_nouns[i].replace('위 메이드', '위메이드')
    total_nouns[i] = total_nouns[i].replace('위 믹스', '위믹스')
    total_nouns[i] = total_nouns[i].replace('컴투스 홀', '컴투스홀딩스')
    total_nouns[i] = total_nouns[i].replace('개발 사', '개발사')
    total_nouns[i] = total_nouns[i].replace('펄 어비스', '펄어비스')
    total_nouns[i] = total_nouns[i].replace('콜 라보', '콜라보')
    total_nouns[i] = total_nouns[i].replace('카 테 고리', '카테고리')
    total_nouns[i] = total_nouns[i].replace('확률 형', '확률형')
    total_nouns[i] = total_nouns[i].replace('역대 급', '역대급')
    total_nouns[i] = total_nouns[i].replace('마비 노기', '마비노기')
    total_nouns[i] = total_nouns[i].replace('게임 위', '게임위')
    total_nouns[i] = total_nouns[i].replace('컬 래 버 레이 션', '콜라보레이션')
    total_nouns[i] = total_nouns[i].replace('콜 라보 레이 션', '콜라보레이션')
    total_nouns[i] = total_nouns[i].replace('빅 게임', '빅게임')
    total_nouns[i] = total_nouns[i].replace('엔 씨', '엔씨')
    total_nouns[i] = total_nouns[i].replace('스타트 업', '스타트업')
    total_nouns[i] = total_nouns[i].replace('디바 이스', '디바이스')
    total_nouns[i] = total_nouns[i].replace('선택 지', '선택지')
    total_nouns[i] = total_nouns[i].replace('치지 직', '치지직')
    total_nouns[i] = total_nouns[i].replace('어 플리 케이 션', '어플리케이션')
    total_nouns[i] = total_nouns[i].replace('게임 쇼', '게임쇼')
    total_nouns[i] = total_nouns[i].replace('아스 달', '아스달')
    total_nouns[i] = total_nouns[i].replace('김실 장', '김실장')
    total_nouns[i] = total_nouns[i].replace('행 안부', '행안부')
    total_nouns[i] = total_nouns[i].replace('게임', '')
    total_nouns[i] = total_nouns[i].replace('기자', '')
    total_nouns[i] = total_nouns[i].replace('기사', '')
    total_nouns[i] = total_nouns[i].replace('진행', '')
    total_nouns[i] = total_nouns[i].replace('이용자', '')
    total_nouns[i] = total_nouns[i].replace('플레이', '')
    total_nouns[i] = total_nouns[i].replace('이번', '')
    total_nouns[i] = total_nouns[i].replace('지난해', '')
    total_nouns[i] = total_nouns[i].replace('전년', '')
    total_nouns[i] = total_nouns[i].replace('콘텐츠', '')
    total_nouns[i] = total_nouns[i].replace('출시', '')
    total_nouns[i] = total_nouns[i].replace('서비스', '')
    total_nouns[i] = total_nouns[i].replace('모바일', '')
    total_nouns[i] = total_nouns[i].replace('제공', '')
    total_nouns[i] = total_nouns[i].replace('예정', '')
    a = total_nouns[i].split(' ')
    data = ''
    for j in a :
        if len(j) >= 2 :
            data = data+' '+j
    total_nouns[i] = data
    
CV_vectorizer = CountVectorizer()
X = CV_vectorizer.fit_transform(total_nouns)

num_topics = 6

lda = LatentDirichletAllocation(n_components=num_topics, random_state=42)
lda.fit(X)

CV_feature_names = CV_vectorizer.get_feature_names_out()

topic_keywords = []
topic_index = 1
num_word = 7

for topic_idx, topic in enumerate(lda.components_):
    top_keywords_idx = topic.argsort()[::-1][:num_word]
    top_keywords = [CV_feature_names[i] for i in top_keywords_idx]
    top_keywords.insert(0, 'Topic %d' %(topic_index))
    topic_index = topic_index+1
    topic_keywords.append(top_keywords)

df_topic_keywords = pd.DataFrame(topic_keywords, columns=["Topic"]+ [f"Keyword {i+1}" for i in range(num_word)])
  • 활용하기

제가 개인적으로 토픽 모델링과 다른 시각화를 활용하여 네이버 기사를 분석한 예시입니다.

예시에서 활용한 파이 차트 및 바 차트, 네트워트 분석은 다음 포스팅에서 진행하겠습니다!!

 

한글 데이터로 워드클라우드를 만드는 방법이 궁금하신 분들은 아래 링크를 확인해주세요:)

https://yhj9855.tistory.com/entry/%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%B6%84%EC%84%9D-%ED%95%9C%EA%B8%80%EB%A1%9C-%EC%9B%8C%EB%93%9C%ED%81%B4%EB%9D%BC%EC%9A%B0%EB%93%9C-%EB%A7%8C%EB%93%A4%EA%B8%B0-feat%EB%84%A4%EC%9D%B4%EB%B2%84-%EB%89%B4%EC%8A%A4-%ED%81%AC%EB%A1%A4%EB%A7%81

 

[데이터 분석] 한글로 워드클라우드 만들기 (feat.네이버 뉴스 크롤링)

안녕하세요. 오늘은 크롤링 데이터로 워드클라우드(wordcloud)를 만드는 방법에 대해 포스팅 하겠습니다. 크롤링 데이터는 네이버 뉴스 크롤링을 사용할 예정입니다! 네이버 뉴스 크롤링 과정이

yhj9855.com

 

코드에 대해 궁금한 부분이 있으신 분들은 댓글로 남겨주시면, 답변 드리도록 하겠습니다.

★읽어주셔서 감사합니다★

728x90
반응형
728x90
반응형

안녕하세요. 오늘은 크롤링 데이터로 워드클라우드(wordcloud)를 만드는 방법에 대해 포스팅 하겠습니다.

 

크롤링 데이터는 네이버 뉴스 크롤링을 사용할 예정입니다!

네이버 뉴스 크롤링 과정이 궁금하신 분은 아래 링크를 확인해주세요:)

https://yhj9855.com/entry/Crawling-%EB%84%A4%EC%9D%B4%EB%B2%84-%EB%89%B4%EC%8A%A4-%ED%81%AC%EB%A1%A4%EB%A7%81-1

 

[Crawling] 네이버 뉴스 크롤링 - 1

안녕하세요. 크롤링에서 가장 첫 포스팅을 네이버 뉴스 크롤링으로 하게 되었어요. 아무래도 바쁜 일상 속에서 매일 뉴스 기사를 파악하는 부분이 시간적으로 힘들었는데, 크롤링하고 데이터

yhj9855.com


  • 워드클라우드(wordcloud)란?

자료의 빈도를 시각적으로 나타내는 방법 중 하나로, 텍스트 데이터 분석을 진행할 때 많이 사용됩니다.

위의 그림처럼 글자 크기를 빈도수에 비례하여 나타내주기 때문에 어떤 단어가 중요한지 한 눈에 알기 편합니다.

만들기 어려워 보이지만, 파이썬은 워드 클라우드를 만드는 라이브러리를 제공해주기 때문에 굉장히 쉽게 만들 수 있습니다!

 

워드 클라우드를 만드는 건 Jupyter Notebook에서 하시는 걸 추천드립니다.

Jupyter Notebook을 설치하고 사용하는 방법은 아래 링크에서 확인해주세요!

https://yhj9855.com/entry/%EC%A3%BC%ED%94%BC%ED%84%B0-%EB%85%B8%ED%8A%B8%EB%B6%81Jupyter-Notebook-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0

 

주피터 노트북(Jupyter Notebook) 사용하기

안녕하세요! 오늘은 데이터 분석에서 자주 활용하는 주피터 노트북(Jupyter Notebook) 을 사용하는 방법에 대해서 포스팅 하겠습니다. 주피터 노트북이란? 대화형 컴퓨팅 환경을 제공하는 오픈 소스

yhj9855.com

 

그럼 한글 텍스트 데이터로 워드 클라우드를 만들어보도록 하겠습니다.

 


  • 필요한 라이브러리 설치

워드 클라우드는 텍스트 데이터를 다루기 때문에 텍스트 데이터를 다루는 라이브러리가 필요합니다.

파이썬은 텍스트 데이터가 영어냐, 한글이냐에 따라서 필요한 라이브러리가 다른데요.

저희는 한글 텍스트 분석을 진행할 것이기 때문에 Konply 라이브러리를 설치합니다.

 

Konply 라이브러리와 관련된 자세한 설명은 아래 포스팅에서 확인해주세요!
https://yhj9855.com/entry/%ED%95%9C%EA%B5%AD%EC%96%B4-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%B6%84%EC%84%9D-%ED%95%84%EC%88%98-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC-Konlpy%EC%BD%94%EC%97%94%EC%97%98%ED%8C%8C%EC%9D%B4

 

한국어 데이터 분석 필수 라이브러리 Konlpy(코엔엘파이)

안녕하세요! 오늘은 한국어 데이터 분석을 위해 꼭 필요한 Konlpy(코엔엘파이) 라이브러리에 대해서 포스팅 하겠습니다. Konlpy 란? 한국어 자연어 처리를 위한 파이썬 라이브러리 입니다. Konlpy의

yhj9855.com

 

그 다음 워드 클라우드를 만들기 위한 라이브러리 wordcloud를 설치해줍니다.

# cmd 창에서 wordcloud 라이브러리 설치
pip install wordcloud
  • 데이터 로드 후 정제하기

필요한 라이브러리를 설치한 후에는 pandas를 사용하여 데이터를 불러옵니다.

저는 2024년 01월 17일 네이버 게임/리뷰 카테고리의 기사 크롤링 데이터를 불러와 정제를 진행하도록 하겠습니다.

result = pd.read_excel('news_detail_20240117.xlsx')
# 기사의 제목 데이터
Title = list(result['title'])
# 기사의 내용 데이터
Information = list(result['information'])
Total = []
# 기사의 제목과 내용을 하나의 리스트에 담았다.
for i in range(len(result)) :
    Total.append(Title[i]+' '+Information[i])

※ Total 데이터의 양이 너무 많아서 데이터 확인은 진행하지 않겠습니다.

  • 명사로 데이터 분류하기

워드 클라우드를 만들기 위해서는 데이터를 의미 있는 데이터만 남겨야 합니다.

그 중 가장 빠른 방법이 명사인 데이터만 남기는 것인데요.

 

생각보다 동사는 '이다', '한다', '있다', '었다' 와 같이 보기만 하면 이해하지 못하는 단어의 빈도수가 높은 경우가 많습니다.

그 외에 다른 형태소를 사용하거나, 범위를 넓힐 경우 워드 클라우드로 만들었을 때, 깔끔하게 나오지 않는 경우가 많아 명사로 진행하도록 하겠습니다.

 

Konply가 지원하는 형태소 분석 종류가 몇 가지 있는데, 저는 그 중에서 Komoran을 사용하였습니다.

다른 종류나 종류별 차이에 대한 포스팅은 추후에 진행하도록 하겠습니다!

 

명사로 형태소 분석을 하는 코드는 아래와 같습니다.

# 형태소 분석기로 Komoran을 사용
komoran = Komoran()
# Total 데이터를 명사로 분류한 후에 띄어쓰기로 붙여넣기 진행
# 줄바꿈으로 진행해도 상관없으나, 보기에 띄어쓰기가 더 편하기 때문에 띄어쓰기로 진행
total_nouns = [' '.join(komoran.nouns(doc)) for doc in Total]

  • 추가 전처리 진행하기

total_nouns 데이터는 이제 명사로만 이루어진 데이터입니다.

그대로 워드 클라우드로 진행을 해도 되지만, 생각보다 의미 없는 데이터가 워드 클라우드에 들어가는 경우가 많기 때문에 추가적으로 데이터 전처리를 진행하는 것이 좋습니다.

예를 들면 한 글자 '것', '이', '등' 이런 단어의 빈도수가 높은 경우가 많기 때문에 두 글자 명사만 데이터를 넣어준다거나, 특정 카테고리의 뉴스이기 때문에 자주 등장하는 명사는 제거한다거나 하는 방법으로 데이터 전처리를 진행해주시면 됩니다.

제가 진행한 전처리 코드는 아래와 같습니다.

# 추가 데이터 전처리 과정
for i in range(len(total_nouns)) :
    # 게임 뉴스이기 때문에 게임과 관련된 부분, 뉴스와 관련된 부분은 제거한다.
    # total_nouns[i]가 하나의 문자열이기 때문이 replace를 통해 제거한다.
    total_nouns[i] = total_nouns[i].replace('게임', '')
    total_nouns[i] = total_nouns[i].replace('기자', '')
    total_nouns[i] = total_nouns[i].replace('기사', '')
    total_nouns[i] = total_nouns[i].replace('진행', '')
    total_nouns[i] = total_nouns[i].replace('이용자', '')
    total_nouns[i] = total_nouns[i].replace('플레이', '')
    total_nouns[i] = total_nouns[i].replace('이번', '')
    
    # 단어를 구분해야 하기 때문에 띄어쓰기로 나누어준다.
    # 만약 줄바꿈으로 데이터를 붙여 넣었다면, 줄바꿈으로 나누어주어야 한다.
    a = total_nouns[i].split(' ')

	# 단어가 두 글자 이상인 것만 워드 클라우드를 진행할 데이터에 넣어준다.
    data = ''
    for j in a :
        if len(j) >= 2 :
        	# 이전 코드와 동일한 이유로 띄어쓰기로 붙여 넣는다.
            # 마찬가지로 줄바꿈으로 진행해도 상관없다.
            data = data+' '+j
    total_nouns[i] = data
  • 워드 클라우드 만들기

이제 데이터 전처리가 완료되었으니, 워드 클라우드를 만들어보겠습니다!

워드 클라우드를 만드는 코드는 아래와 같습니다.

# 워드 클라우드를 위한 작업
wordcloud = []
for i in total_nouns :
	# 문자열로 된 데이터를 단어로 판단해야 하기 때문에 띄어쓰기로 나눈다.
    # 줄바꿈으로 붙여 넣기를 진행했다면, 줄바꿈으로 나누어야 한다.
    i = i.split(' ')
    # wordcloud라는 리스트에 모든 단어를 넣어준다.
    for j in i :
        wordcloud.append(j)

# Counter 함수를 사용하여 wordcloud 내 단어와 단어의 수를 wordcloud_data에 dictionary 형태로 저장한다.
wordcloud_data = dict(Counter(wordcloud))

# 워드 클라우드의 모양 이미지 변경하고 싶을 경우 파일 경로를 저장한다.
# 기본 네모로 진행할 경우 해당 부분은 지우면 된다.
Naver = np.array(Image.open("파일 경로"))
# 워드 클라우드의 크기를 결정한다.
plt.figure(figsize=(30,30))
wc = WordCloud(        # 워드 클라우드의 모양을 결정한다.
		       # 기본 네모로 진행할 경우 해당 부분을 지우면 된다.
		       relative_scaling=0.2,mask = Naver,
                       # 기본적으로 한글은 지원하지 않기 때문에 한글의 폰트를 지정해야한다.
                       # 워드 클라우드는 함수 안에서 폰트를 지정하기 때문에 다른 그래프보다 폰트 자유도가 높다.
                       font_path="폰트 경로",
                       # 워드 클라우드 배경색
                       background_color="white",
                       # 가장 작은 폰트 사이즈
                       min_font_size=1,
                       # 가장 큰 폰트 사이즈
                       max_font_size=50,
                       # 워드 클라우드 진행하고 싶은 단어의 수
                       max_words=100,
                       colormap = 'coolwarm'
                     ).generate_from_frequencies(wordcloud_data)
plt.imshow(wc)
plt.axis('off')
plt.show()

위의 있는 코드로 실행했을 때의 결과물은 아래와 같습니다!

※ 실행할 때마다 색상이 일부 달라지기 때문에 원하는 색상이 나올 때까지 진행하시면 됩니다.

저는 오른쪽 이미지를 사용했기 때문에 해당 모양의 워드 클라우드가 만들어졌습니다.

생각보다 이미지 적용이 잘되기 때문에 원하시는 이미지로 해보시길 바랍니다.

 

전체코드

import pandas as pd
import numpy as np
from konlpy.tag import *
from collections import Counter
from wordcloud import WordCloud
from wordcloud import ImageColorGenerator
from PIL import Image
import matplotlib.pyplot as plt

result = pd.read_excel('파일 이름')
Title = list(result['title'])
Information = list(result['information'])

Total = []
for i in range(len(result)) :
    Total.append(Title[i]+' '+Information[i])

komoran = Komoran()
total_nouns = [' '.join(komoran.nouns(doc)) for doc in Total]

for i in range(len(total_nouns)) :
    total_nouns[i] = total_nouns[i].replace('게임', '')
    total_nouns[i] = total_nouns[i].replace('기자', '')
    total_nouns[i] = total_nouns[i].replace('기사', '')
    total_nouns[i] = total_nouns[i].replace('진행', '')
    total_nouns[i] = total_nouns[i].replace('이용자', '')
    total_nouns[i] = total_nouns[i].replace('플레이', '')
    total_nouns[i] = total_nouns[i].replace('이번', '')
    a = total_nouns[i].split(' ')
    data = ''
    for j in a :
        if len(j) >= 2 :
            data = data+' '+j
    total_nouns[i] = data

wordcloud = []
for i in total_nouns :
    i = i.split(' ')
    for j in i :
        wordcloud.append(j)

wordcloud_data = dict(Counter(wordcloud))

Naver = np.array(Image.open("파일 경로"))
plt.figure(figsize=(30,30))
wc = WordCloud(        relative_scaling=0.2,mask = Naver,
                       font_path="폰트 경로",
                       background_color="white",
                       min_font_size=1,
                       max_font_size=50,
                       max_words=100,
                       colormap = 'coolwarm'
                     ).generate_from_frequencies(wordcloud_data)
plt.imshow(wc)
plt.axis('off')
plt.show()

 

  • 활용하기

제가 개인적으로 워드클라우드와 다른 시각화를 활용하여 네이버 기사를 분석한 예시입니다.

예시에서 사용한 파이 차트 및 바 차트, 네트워크 분석은 다음 포스팅에서 진행하겠습니다!!

 

한글 데이터로 토픽모델링을 하는 방법이 궁금하신 분들은 아래 링크를 확인해주세요:)

https://yhj9855.com/entry/%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%B6%84%EC%84%9D-%ED%95%9C%EA%B8%80-%EB%8D%B0%EC%9D%B4%ED%84%B0-%ED%86%A0%ED%94%BD-%EB%AA%A8%EB%8D%B8%EB%A7%81-%EC%A7%84%ED%96%89%ED%95%98%EA%B8%B0

 

[데이터 분석] 한글 데이터 토픽 모델링 진행하기

안녕하세요! 오늘은 한글 데이터로 토픽 모델링(topic modeling)을 하는 방법에 대해 포스팅 하겠습니다. 한글 데이터는 네이버 뉴스 크롤링 데이터를 사용할 예정입니다. 네이버 뉴스 크롤링 과정

yhj9855.com

 

코드에 대해 궁금한 부분이 있으신 분들은 댓글로 남겨주시면, 답변 드리도록 하겠습니다.

★ 읽어주셔서 감사합니다★

728x90
반응형
728x90
반응형

안녕하세요.
오늘은 크롤링을 진행하기 위해 반드시 필요한 개발자 도구를 사용하는 법에 대해서 포스팅 하겠습니다.
 

  • 크롬 개발자 도구란?

크롬 브라우저에 직접 내장된 웹 개발 도구로, 웹 페이지의 HTML 구조를 빠르게 확인할 수 있습니다.
크롤링을 진행할 때, 웹 페이지의 HTML 구조를 꼭 알아야하기 때문에 크롬 개발자 도구를 자주 사용합니다.
 

  • 크롬 개발자 도구 여는 방법
  1. 마우스 우클릭 → '검사' 클릭
  2. '제어' → '도구 더보기' → '개발자 도구'
  3. 여기서 제어는 크롬 내 X(창닫기 버튼) 아래에 있는 세로로 된 . 세 개를 의미합니다.
  4. F12 버튼 클릭
  5. Ctrl+Shift+I

이렇게 총 4가지 방법이 있는데, 저는 F12를 가장 많이 사용합니다!

 

 

 

 

  • 개발자 도구로 빠르게 원하는 구간 찾기

개발자 도구 태그를 하나씩 열며, 구조를 확인하는 것도 좋지만 원하는 부분을 빨리 찾고 싶을 때는 아래의 그림처럼 사용합니다.
아래 그림은 네이버 뉴스에서 개발자 도구를 연 상태입니다.

  1. 개발자 도구를 연 후, 그림에서 보이는 부분을 클릭 혹은 Ctrl+Shift+C
  2. HTML 구조 확인을 원하는 구간 클릭
  3. 개발자 도구에서 파란색으로 표시된 부분 확인

 

  • 개발자 도구에서 원하는 HTML 요소 가지고 오기

개발자 도구에서 원하는 구간의 HTML 구조를 찾았으면, 해당 구조에서 원하는 요소를 가져올 수 있습니다.
 
class, id, href 등 개발자 도구 내 직접 적혀 있는 부분을 가져오고 싶을 경우에는 해당 부분 더블 클릭 → 복사를 통해 받아올 수 있습니다.

 
해당 부분의 요소 전체, HTML 구조 전체, selector, XPath 등 내용이 많거나, 위치를 가져오고 싶은 경우에는 마우스 우클릭 → Copy(복사) → 원하시는 부분을 클릭을 통해 받아올 수 있습니다.

 

 

  • 개발자 도구 꺼짐 현상 해결

개발자 도구가 유지되지 않고 꺼지는 현상이 나타나는 경우가 있습니다.
이런 경우는 대부분 크롬 자체 문제인 경우가 많습니다.

  1. 크롬을 껐다가 다시 시작
  2. 크롬을 최신으로 업데이트
  3. 크롬을 삭제했다가 다시 설치

위의 3가지 방법이면 개발자 도구 꺼짐 현상을 해결할 수 있습니다.
저는 개인적으로 크롬 업데이트로 가장 많이 해결을 했던 것 같아요!
 

TIP : HTML 요소 내 띄어쓰기 처리

class, id 등 요소의 이름을 사용하여 크롤링을 진행할 때, 그대로 복사 → 붙여 넣기를 진행해도 요소를 찾을 수 없다는 오류가 나오는 경우가 있습니다.
그럴 경우는 보통 이름 내 띄어쓰기 때문일 확률이 높습니다.
개발자 도구에서는 띄어쓰기를 그대로 사용하는 것처럼 보이지만, 실제로는 띄어쓰기 대신 '.' 을 사용하고 있습니다.
해당 부분은 개발자 도구에서도 확인할 수 있는데요

위의 그림처럼 개발자 도구 내에서는 class의 이름이 'section_list_ranking_press _rankingList' 으로 띄어쓰기가 존재하지만, 영역을 표시해보면 'section_list_ranking_press._rankingList' 으로 표기되는 것을 볼 수 있습니다.
파이썬(python)으로 크롤링을 진행할 때, 요소의 이름 내 띄어쓰기가 있다면 띄어쓰기 → . 으로 교체해야 오류 없이 진행할 수 있습니다.
.
개발자 도구를 활용해서 네이버 뉴스를 크롤링 하는 예시는 아래 페이지에서 확인할 수 있습니다!
https://yhj9855.com/entry/Crawling-%EB%84%A4%EC%9D%B4%EB%B2%84-%EB%89%B4%EC%8A%A4-%ED%81%AC%EB%A1%A4%EB%A7%81-1

 

[Crawling] 네이버 뉴스 크롤링 - 1

안녕하세요. 크롤링에서 가장 첫 포스팅을 네이버 뉴스 크롤링으로 하게 되었어요. 아무래도 바쁜 일상 속에서 매일 뉴스 기사를 파악하는 부분이 시간적으로 힘들었는데, 크롤링하고 데이터

yhj9855.com

 
궁금한 부분이 있으신 분들은 댓글로 남겨주시면, 답변 드리도록 하겠습니다.

★읽어주셔서 감사합니다★

728x90
반응형
728x90
반응형

안녕하세요. 오늘은 기존에 작성한 네이버 뉴스 크롤링 코드에서 두 번째 코드의 자세한 크롤링 과정을 포스팅 하겠습니다.
 
네이버 뉴스 크롤링 전체 코드를 확인하고 싶으신 분들은 아래 링크를 확인해주세요!
<네이버 뉴스 크롤링 전체 코드>
https://yhj9855.com/entry/Crawling-%EB%84%A4%EC%9D%B4%EB%B2%84-%EB%89%B4%EC%8A%A4-%ED%81%AC%EB%A1%A4%EB%A7%81-1

 

[Crawling] 네이버 뉴스 크롤링 - 1

안녕하세요. 크롤링에서 가장 첫 포스팅을 네이버 뉴스 크롤링으로 하게 되었어요. 아무래도 바쁜 일상 속에서 매일 뉴스 기사를 파악하는 부분이 시간적으로 힘들었는데, 크롤링하고 데이터

yhj9855.com

 
두 번째 코드는 첫 번째 코드의 결과물을 로드하는 것부터 시작하기 때문에 첫 번째 코드를 먼저 봐주세요!
<네이버 뉴스 크롤링 첫 번째 코드의 자세한 과정>
https://yhj9855.com/entry/Crawling-%EB%84%A4%EC%9D%B4%EB%B2%84-%EB%89%B4%EC%8A%A4-%ED%81%AC%EB%A1%A4%EB%A7%81-2

 

[Crawling] 네이버 뉴스 크롤링 - 2

안녕하세요. 오늘은 기존에 작성한 네이버 뉴스 크롤링 코드에서 첫 번째 코드의 자세한 크롤링 과정을 포스팅 하겠습니다. 네이버 뉴스 크롤링 전체 코드를 확인하고 싶으신 분들은 아래 링크

yhj9855.com

 

두 번째 코드는 Python으로 첫 번째 코드에서 크롤링한 기사의 링크 내 기사 본문을 가지고 오는 코드였습니다.


  • 크롤링 진행한 링크 가져오기

가장 먼저 이전에 크롤링했던 결과 엑셀 파일을 로드합니다.
해당 파일에는 기사의 수, 기사의 제목, 기사의 링크가 들어가 있습니다.
저는 두 번째 코드의 결과물 엑셀 파일에 기사의 수, 기사의 제목, 기사의 본문, 기사의 링크을 담을 예정입니다.
해당 부분은 코드로 변경하면 아래와 같습니다.

# 기존에 크롤링했던 결과물 엑셀 파일
# 엑셀 파일의 이름은 첫 번째 코드에서 저장한 부분이기 때문에 코드마다 달라질 수 있다.
link = pd.read_excel('news_20240104.xlsx')

# 기사의 본문까지 포함한 크롤링 결과물을 저장할 엑셀 파일의 이름
# 파일 관리를 쉽게 하기 위해서 날짜를 넣었다.
excel_name = 'news_detail_20240104.xlsx'

# 기사들의 링크를 리스트화
Main_link = list(link['link'])

# 기사의 수, 기사의 제목, 기사의 본문, 기사의 링크 정보를 담아줄 데이터 프레임을 생성한다.
Information = pd.DataFrame({'number' : [], 'title' : [], 'information' : [], 'link' : []})

# 기사의 수, 기사의 제목, 기사의 링크는 이전 크롤링 결과물에 동일하게 존재하기 때문에 바로 정보를 담는다.
Information['number'] = link['number']
Information['title'] = link['title']
Information['link'] = link['link']

# 기사의 본문을 담을 변수
information = []

기사의 링크들도 동적 페이지가 존재하지 않기 때문에 첫 번째 코드와 동일한 이유로 정적 크롤링을 진행하겠습니다.

  • 기사의 본문 가져오기 - 1

네이버 게임/리뷰 카테고리의 기사는 크게 2종류의 구조를 가지고 있습니다.

  1. 뉴스에서 IT/과학으로 분류되는 기사
  2. 스포츠에서 e스포츠로 분류되는 기사

두 종류의 네이버 기사는 서로 다른 HTML 구조를 가지고 있기 때문에 다른 방식으로 크롤링을 진행해야 합니다.
첫 번째로 뉴스에서 IT/과학으로 분류되는 기사의 본문을 크롤링해보도록 하겠습니다.
 
먼저 개발자도구(F12)를 열어, 기사의 본문이 어떤 HTML 구조를 가지고 있는지 확인해봅니다.

①번의 아이콘을 클릭한 후, ②번(=원하는 정보)을 클릭하면 원하는 정보의 HTML 구조로 바로 이동이 됩니다.
여기서는 원하는 정보가 기사의 본문이기 때문에 기사의 본문이 전부 들어가 있는 HTML 구조를 확인해보니, 아래와 같이 나왔습니다.

<개발자 도구 사용 Tip>

더보기

개발자 도구에서 원하는 영역을 클릭할 때 등장하는 파란 네모 박스를 잘 이용해야 합니다.

HTML의 경우, 가장 큰 범위부터 시작해서 점점 작은 단위로 들어가는 구조를 가진 경우가 대부분인데, 이 때 큰 단위의 범위를 선택할 경우 원하지 않는 정보까지 함께 들어올 가능성이 높습니다.

원하지 않는 정보를 제거하는 과정이 생각보다 쉽지 않을 수 있기 때문에 파란 네모 박스를 잘 활용하여 원하는 정보가 모두 들어가 있는 가장 작은 크기의 파란 네모 박스를 찾는게 좋습니다.

기사의 본문만 존재하는 영역을 찾는 것이 기사 전체의 영역을 선택해서 데이터를 정제하는 것보다 쉽다.

<div id="newsct_article" class="newsct_article _article_body">...</div>
 
해당 HTML 구조는 안에 본문이 생략된 HTML 구조로, 기사의 본문이 모두 들어가 있는 전체 HTML 코드가 확인하고 싶으신 분들은 더보기를 확인해주세요!

더보기

<div id="newsct_article" class="newsct_article _article_body">
<article id="dic_area" class="go_trans _article_content" style="-webkit-tap-highlight-color: rgba(0,0,0,0)">
인터넷 게임에 중독되면 실제로 뇌 인지 기능과 감정 처리 능력이 떨어진다는 연구 결과가 나왔다.<br><br><span class="end_photo_org"><div class="nbd_im_w _LAZY_LOADING_WRAP ">
<div class="nbd_a _LAZY_LOADING_ERROR_HIDE" id="img_a1">
<img id="img1" class="_LAZY_LOADING" src="https://imgnews.pstatic.net/image/031/2024/01/04/0000802219_001_20240104215001106.jpg?type=w647">
</div>
</div><em class="img_desc">서울의 한 <span data-type="ore" data-lang="en">PC</span>방 [사진=뉴시스]</em></span><br><br>4일 삼성서울병원에 따르면 이 병원의 최정석 정신건강의학과 교수팀은 18∼39세 인터넷 게임 중독 치료를 받은 적 있는 환자 26명과 정상 대조군 25명을 대상으로 기능적 자기공명영상(<span data-type="ore" data-lang="en">MRI</span>)과 사건 관련 전위 뇌파 검사 등을 통해 게임 중독이 뇌 기능에 미치는 영향을 확인했다.<br><br>여기서 인터넷 게임 중독 환자는 하루에 4시간 이상, 1주일에 30시간 이상 게임을 하는 사람을 말한다. 정상 대조군은 하루 2시간 미만으로 게임 시간을 조절할 줄 아는 사람들로 구성했다.<br><br>검사 결과 게임 중독 환자들은 정상 대조군들에 비해 기능적 <span data-type="ore" data-lang="en">MRI</span> 검사에서 전두엽과 두정엽 부위 뇌 활성이 증가했고, 청각 자극에 대한 뇌파 신호 진폭은 감소하는 모습을 보였다.<br><br>또 우측 하측두회와 우측 안와회, 일부 후두부에서 기능적 <span data-type="ore" data-lang="en">MRI</span>와 뇌파검사 모두 반응이 유의미한 양의 상관관계를 보였다. 반면 좌측 해마와 우측 편도체에서는 유의미한 음의 상관관계를 보였다.<br><br>이처럼 특정 부위는 양의 상관관계로 과민하게 반응하거나 일부는 음의 상관관계로 둔감하게 반응한다는 것은 게임 중독자들의 뇌 구조 간 정보 처리가 불균형하다는 의미로 해석된다.<br><br>또 시각 중추가 있는 후두엽, 인지 기능에서 중심 역할을 수행하는 측두엽 등 여러 뇌 영역의 피질에서 뇌 활성의 변화가 관찰되고, 기능적 <span data-type="ore" data-lang="en">MRI</span>와 뇌파검사 반응이 상호작용을 보였다.<br><br>이는 인지 처리 능력이 비효율적으로 발휘돼 결과적으로 뇌의 기능이 저하되었음을 의미한다.<br><br>해마와 편도체 사이 상호관계는 감정에 대한 기억과 학습에 중요한 영향을 미치는데, 게임 중독자들은 해마와 편도체 기능이 약화된 것으로 확인됐다.<br><br>최 교수는 "이번 연구를 통해 게임에 중독되면 실제 뇌 인지 기능과 감정 처리 능력 저하에 영향을 미친다는 것을 확인했다"며 "게임 중독이 실제 뇌 기능에 영향을 미치는 만큼 게임에 과도하게 빠져들지 말고 건강한 취미생활로 활용되길 바란다"고 말했다.<br><br>
</article>
</div>

저희는 지금 기사의 본문만 알고 싶기 때문에 id가 newsct_article이고, div태그인 HTML구조의 텍스트를 가져와야 합니다.

<class 이름이 아닌 id 이름을 사용하는 이유>

더보기

태그 내 class의 이름과 id의 이름이 모두 존재할 경우에는 id의 이름을 사용하는 것이 좋습니다.

id의 이름은 고유한 것이 많기 때문에 중복값이 잘 발생하지 않기 때문에 원하는 태그를 정확하게 지정할 가능성이 높습니다.

※ article로 접근해도 동일한 결과를 가져올 수 있습니다만, article 태그를 잘 인식하지 못하는 경우가 있어서 div 태그로 진행하였습니다.
해당 부분을 코드로 변경하면 아래와 같습니다.

response = requests.get(main_link, headers={'User-Agent':'Moailla/5.0'})

# response.status_code가 200이라는 의미는 페이지의 로드가 잘 되었다는 것을 의미한다.
if response.status_code == 200 :
    html = response.content
    soup = BeautifulSoup(html, 'html.parser')
    # strip을 사용하여 눈으로 확인할 수 없는 양 끝의 공백을 잘라준다.
    info = soup.find('div', {'id' : 'newsct_article'}).text.strip()
    # 엑셀 내 칸을 크게 차지하는 것을 방지하기 위해 줄바꿈을 띄어쓰기로 변경한다.
    # 크롤링에서 필요한 코드는 아니기 때문에 생략해도 상관없다.
    info = info.replace('\n', '')
    information.append(info)
  • 기사의 본문 가져오기 - 2

두 번째로 스포츠에서 e스포츠로 분류되는 기사의 본문을 크롤링해보도록 하겠습니다.
위의 과정과 동일하게 개발자 도구를 열어, 기사의 본문이 어떤 HTML 구조를 가지고 있는지 확인해봅니다.

저희가 원하는 정보는 기사의 본문이기 때문에 기사의 본문이 전부 들어가 있는 HTML 구조를 확인해보니, 아래와 같이 나왔습니다.
<div class="news_end font1 size3" id="newsEndContents">... </div>
 
해당 HTML 구조는 안에 본문이 생략된 HTML 구조로, 기사의 본문이 모두 들어가 있는 전체 HTML 코드가 확인하고 싶으신 분들은 더보기를 확인해주세요!

더보기

<div class="news_end font1 size3" id="newsEndContents">
  2024년 '청룡의 해'를 맞이해 국내 주요 게임사 경영진들은 '내실 강화'와 '선택과 집중'를 주요 키워드로 제시하며 실적 개선을 위한 새로운 도약을 예고했다. 시장의 변화에 맞춘 각각의 경영 전략으로 위기를 극복하고 성장과 발전을 이끌어내기 위해 박차를 가하는 모습이다.<br><br><span class="end_photo_org"><img src="https://imgnews.pstatic.net/image/347/2024/01/04/2024010419525603012a7a3ff81e61839820248_20240104200201410.jpg?type=w647" alt=""><em class="img_desc">넷마블 방준혁 의장(제공=넷마블).</em></span>먼저 넷마블 방준혁 의장은 2일 시무식을 통해 직원들에게 '체질개선', '선택과 집중'을 강조했다. 이를 통해 위기를 돌파하고 회사 본연의 경쟁력 강화에 나선다는 전략이다.<br><br>방준혁 의장은 "올해는 새로운 변화를 위한 전환점을 마련해 위기를 극복하고 경쟁력을 회복해야 한다"며, "이를 위해 모두가 긍정적, 능동적 자세로 임해 넷마블 본연의 가치를 다시금 찾는데 모든 역량을 집중해 주길 바란다"고 당부했다.<br><br>넷마블은 올해 상반기 '아스달 연대기', '나혼자만 레벨업: 어라이즈' 등 다양한 신작들을 선보일 계획이다. 지난 '지스타 2023'서 인기를 얻으며 '게임 오브 지스타'에도 선정된 오픈월드 액션 RPG '일곱 개의 대죄: 오리진'도 올해 글로벌 출시를 목표로 개발 중이다.<br><br><span class="end_photo_org"><img src="https://imgnews.pstatic.net/image/347/2024/01/04/2024010419534106326a7a3ff81e61839820248_20240104200201430.jpg?type=w647" class="imageLazyLoad" lazy-src="https://imgnews.pstatic.net/image/347/2024/01/04/2024010419534106326a7a3ff81e61839820248_20240104200201430.jpg?type=w647" alt=""><em class="img_desc">위메이드 장현국 대표.</em></span>위메이드 장현국 대표는 임직원 대상 신년사를 전하며 '내실 다지기'를 주요 키워드로 제시했다. <br><br>장현국 대표는 "지난 3년 동안의 공격적인 실행력을 유지하면서도, 내실을 다지는 한 해로 만들어야 한다"며, "그 동안 해왔던 일들의 비용효과를 분석하고, 일의 우선순위를 정하는 일들을 연중 내내 진행하게 될 것"을 예고했다.<br><br>이어 "실행이 전부"라고 강조하면서, "지난 몇 년 동안 우리의 계획과 실행이 성과가 될 수 있도록 최선을 다해주길 바란다"고 직원들을 독려했다.<br><br>위메이드는 올해 1분기 블록체인 버전의 '나이트 크로우' 글로벌 출시를 시작으로 올해 신작 PC MMORPG '레전드 오브 이미르', 신작 야구게임 '판타스틱4베이스볼' 출시, '미르4'와 '미르M' 중국 서비스 등 새로운 도전을 앞두고 있다.<br><br><span class="end_photo_org"><img src="https://imgnews.pstatic.net/image/347/2024/01/04/2024010419593302525a7a3ff81e61839820248_20240104200201440.jpg?type=w647" class="imageLazyLoad" lazy-src="https://imgnews.pstatic.net/image/347/2024/01/04/2024010419593302525a7a3ff81e61839820248_20240104200201440.jpg?type=w647" alt=""><em class="img_desc">컴투스 이주환 대표.</em></span>컴투스 이주환 대표는 '도전과 개척 정신'을 핵심으로 내세웠다. 그는 "당장의 결과보다는 긴 호흡으로 시대를 조망하고, 새로움에 주저하지 않는 도전과 개척 정신이 우리의 가장 큰 경쟁력"이라며, "컴투스의 도전과 혁신 DNA는 우리를 더욱 단단하게 성장시킬 것"이라 강조했다.<br><br>이주환 대표는 올해 비전으로 "전 세계 많은 이용자들이 인정하는 재밌는 게임을 만들기 위해 노력하고, 우수 개발사들의 게임 퍼블리싱도 확대해 나갈 것"이라며, "부진을 겪었던 미디어 부문도 냉정하게 시장을 분석하고 경쟁력을 강화하며 새로운 성장 전기를 맞이할 것"이라 제시했다.<br><br>NHN 정우진 대표는 올해 최우선 과제로 회사의 안정적 수익 창출과 장기적 성장 기반 마련을 제시했다. 그는 임직원 대상 경영진 메시지를 통해 "지금의 위기를 새로운 도약의 기회로 만들어 가기 위한 여정에 동참해줄 것"을 직원들에게 당부했다.<br><br>정우진 대표는 "2024년에도 우리가 영위 중인 사업의 경쟁 상황은 더욱 치열해질 것"이라며, "급변하는 경영 환경에 선제적으로 대비해 왔음에도, 저성장 시대의 위기에서 살아남기 위해서는 더 많은 노력과 집중이 필요하다"고 강조했다.
<p class="source"><b>기사제공</b> 데일리e스포츠</p>
<p class="byline">이학범 ethic95@dailygame.co.kr</p>
<!-- /* 기자 카드 + 본문 내 기자 정보 -->
<div class="reporter_area">
<div class="reporter _type_journalist _JOURNALIST_79338">
<div class="reporter_profile">
<a href="https://media.naver.com/journalist/347/79338" class="link_thumbnail" onclick="clickcr(this, 'art.more', '', '', event);">
<div class="thumbnail">
<!-- [D] 이미지 원본 사이즈 : 40x40 -->
<img src="https://mimgnews.pstatic.net/image/upload/spubs/T9G0000347/profile/2023/03/30/profile_173002096.jpg" onerror="$(this).parent().hide();" width="40" height="40" alt=""></div></a>
<div class="reporter_info">
<div class="profile_info">
<a href="https://media.naver.com/journalist/347/79338" class="link_press" onclick="clickcr(this, 'art.more', '', '', event);">
<div class="press"><img src=" https://mimgnews.pstatic.net/image/upload/office_logo/347/2020/07/28/logo_347_6_20200728202552.png " height="20" alt="데일리e스포츠" title="" class="press_img" onerror="$(this).parent().hide();"></div>
<div class="name">이학범 기자</div></a>
<div class="subscribe">
<button type="button" class="button_subscribe _reporter_subscribe_btn" data-journalist-id="79338">구독</button>
<!-- <button type="button" class="button_subscribe is_on">구독중</button> -->
<!-- [D] 레이어 토글 -->
<div class="subscribe_layer" style="display: none">
<p><strong>이학범 기자의 구독을 <br>취소하시겠습니까?</strong><br>구독에서 해당 기자의 기사가 제외됩니다.</p>
<div class="button_group">
<button type="button" class="button_layer _btn_y" data-journalist-id="79338">예</button>
<button type="button" class="button_layer _btn_n">아니오</button></div>
<button type="button" class="button_layer_close"><span class="blind">닫기</span></button></div></div></div>
<div class="subscribe_info">
<dl class="subscribe_info_list">
<div class="subscribe_info_item" style="">
<dt>구독자</dt>
<dd class="_reporter_subscribe_count">25</dd></div>
<div class="subscribe_info_item _reactionModule" data-sid="JOURNALIST" data-cid="79338" data-ccounttype="period" style="visibility: visible;" data-loaded="1" data-facetype="0">
<dt>응원수</dt>
<dd class="_reporter_cheer_count">126</dd></div></dl></div></div></div>
<div class="reporter_morenews">
<ul class="morenews_list">
<li class="morenews_item">
<a href="/news.nhn?oid=347&aid=0000177496" class="link_morenews" onclick="clickcr(this, 'art.bestart', '', '', event);">'철권8'부터 '낙원'까지, 2024년 신작 게임 쏟아진다</a></li>
<li class="morenews_item">
<a href="/news.nhn?oid=347&aid=0000177554" class="link_morenews" onclick="clickcr(this, 'art.bestart', '', '', event);">[주간모바일순위] 니케, 새해 맞이 업데이트로 차트 역주행</a></li></ul></div></div>
<div class="reporter_recommend" style="display:none"></div></div>
<!-- 카피라이트 배너 -->
<div class="copyright">
<p>Copyright ⓒ 데일리e스포츠. All rights reserved. 무단 전재 및 재배포 금지.</p></div>
<!-- 기사 분류 -->
<div class="categorize" id="_article_section_guide">
<a href="#wa_categorize_tooltip" class="btn_guide_categorize" role="button" aria-describedby="wa_categorize_tooltip">기사 섹션 분류 가이드</a>
<div class="guide_categorize" style="display: none;">
<em class="guide_title">기사 섹션 분류 안내</em>
<p class="guide_text" role="tooltip" id="wa_categorize_tooltip">스포츠 기사 섹션(종목) 정보는 언론사 분류와 기술 기반의 자동 분류 시스템을 따르고 있습니다. 오분류에 대한 건은 네이버스포츠로 제보 부탁드립니다.</p>
<a href="https://help.naver.com/alias/contents2/sports/sports_7.naver" class="btn_report" target="_blank" title="새창">오분류 제보하기</a>
<button type="button" class="btn_close"><span class="blind">가이드 닫기</span></button></div></div>
<!-- 언론사 프로모션 링크 -->
<div class="promotion">
<ul class="promotion_list">
<li class="promotion_item">
<a href="https://unse.dailyesports.com" class="link_promotion">2024년 사주·운세·토정비결 확인!!</a></li>
<li class="promotion_item">
<a href="https://m.dailyesports.com/brdlist.php?bct=1" class="link_promotion">정치·혐오글NO! 순도100% 유머게시판</a></li></ul></div></div>

저희는 지금 기사의 본문만 알고 싶기 때문에 id가 newsEndContents이고, div태그인 HTML구조의 텍스트를 가져와야 합니다.
이 때, 문제가 하나 발생하게 되는데, 바로 기자의 정보까지 함게 크롤링이 된다는 점입니다.

 
위의 사진처럼 기사의 본문이 포함된 가장 작은 영역에 기자와 관련된 내용도 포함이 되기 때문인데요.
이런 경우에는 기자와 관련된 내용의 시작점을 찾는 것이 가장 좋습니다.
기자와 관련된 내용의 시작점은 바로 "기사제공" 이라는 문구이기 때문에 이를 기준으로 이후의 내용은 가져오지 않는 방법으로 크롤링을 진행하겠습니다.

<기자와 관련된 내용의 시작점을 찾아야 하는 이유>

더보기

기사 본문의 마지막을 찾는 것이 아니고, 기자와 관련된 내용의 시작점을 찾아야 하는 이유는 시작점이 동일할 가능성이 높기 때문입니다.

기사 본문의 경우, 내용에 따라 마지막 부분이 달라지기 때문에 해당 부분을 코드에 적용할 수 없습니다.

하지만, 기사라는 글의 특성상 기자의 정보를 적는 부분이 형식화 되어 있을 가능성이 높습니다.

그렇기 때문에 기자와 관련된 내용의 시작점을 찾는 것이 코드에 적용하기 훨씬 수월합니다.

해당 부분을 코드로 변경하면 아래와 같습니다.

response = requests.get(main_link, headers={'User-Agent':'Moailla/5.0'})
if response.status_code == 200 :
    html = response.content
    soup = BeautifulSoup(html, 'html.parser')
    info = soup.find('div', {'id' : 'newsEndContents'}).text.strip()
    info = info.replace('\n', '')
    # 기자의 정보가 '기사제공' 이후부터 나오기 때문에 전체 본문에서 해당 글을 찾는다.
    end = info.index('기사제공')
    # '기사제공' 이전에 등장하는 문자 즉, 기사의 본문만 변수에 저장하여, 본문과 기자를 분리한다.
    info = info[:end]
    information.append(info)
  • 기사의 본문 가져오기 - 3
  1. 뉴스에서 IT/과학으로 분류되는 기사
  2. 스포츠에서 e스포츠로 분류되는 기사

위의 두 종류가 아닌 기사도 가끔 게임/리뷰 카테고리에 존재하는 경우가 있습니다.
하지만, 해당 기사들의 소속 카테고리가 규칙적이지 않고, 네이버 기사의 경우 기사의 소속 카테고리에 따라 서로 다른 HTML 구조를 가지고 있기 때문에 모든 구조를 크롤링 진행할 수는 없습니다.
또한, 그 수가 전체 기사 중에 차지하는 비율이 10% 미만이기 때문에 해당 부분은 수집하지 않는 것으로 진행했습니다.

  • 엑셀 파일로 저장

크롤링 작업은 완료하였습니다.
이제 크롤링한 데이터프레임을 엑셀 파일로 저장하도록 하겠습니다.

with pd.ExcelWriter(excel_name) as writer :
    Information.to_excel(writer, sheet_name='결과값', index=False)

 
이런 과정을 통해서 특정 날짜의 모든 기사의 링크 내 기사의 본문을 크롤링하는 코드가 완성되었습니다!!
위의 과정은 하나의 링크를 크롤링하는 코드이기 때문에 해당 과정을 링크 수 만큼 반복 진행을 해야 합니다.
또한 It/과학 카테고리, e스포츠 카테고리, 수집하지 않는 기사의 구분을 오류 처리로 구분하였습니다.
이러한 부분이 모두 포함된 전체 코드입니다.

더보기
from bs4 import BeautifulSoup
import requests
import pandas as pd
from openpyxl import *
import urllib

link = pd.read_excel('news_20240104.xlsx')
excel_name = 'news_detail_20240104.xlsx'
Main_link = list(link['link'])
Information = pd.DataFrame({'number' : [], 'title' : [], 'information' : [], 'link' : []})
Information['number'] = link['number']
Information['title'] = link['title']
Information['link'] = link['link']
information = []

# 기사의 본문을 크롤링하는 과정을 전체 링크에서 진행해야 한다.
for main_link in Main_link :
    try :
        response = requests.get(main_link, headers={'User-Agent':'Moailla/5.0'})
        if response.status_code == 200 :
            html = response.content
            soup = BeautifulSoup(html, 'html.parser')
            info = soup.find('div', {'id' : 'newsct_article'}).text.strip()
            info = info.replace('\n', '')
            information.append(info)
    # IT/과학 카테고리에서 오류가 발생한다는 의미는 e스포츠 카테고리 기사라는 의미이다.
    except :
        try :
            response = requests.get(main_link, headers={'User-Agent':'Moailla/5.0'})
            if response.status_code == 200 :
                html = response.content
                soup = BeautifulSoup(html, 'html.parser')
                info = soup.find('div', {'id' : 'newsEndContents'}).text.strip()
                info = info.replace('\n', '')
                end = info.index('기사제공')
                info = info[:end]
                information.append(info)
        # e스포츠 카테고리 기사에서도 오류가 발생한다는 의미는 수집할 필요가 없는 기사라는 의미이다.
        except Exception as e :
            info = ''
            information.append(info)

Information['information'] = information

with pd.ExcelWriter(excel_name) as writer :
    Information.to_excel(writer, sheet_name='결과값', index=False)

<코드 작성 Tip>

더보기

보통 크롤링을 진행할 때, 크롤링을 원하는 모든 웹 페이지를 확인하는 것은 물리적으로 불가능합니다.

그렇기 때문에 보통 이러한 순서로 코드 작성이 진행됩니다.

  1. 가장 처음 보이는 페이지의 HTML 구조에 맞게 코드를 작성
  2. 코드에 작성한 HTML 구조가 존재하지 않는 오류가 발생
  3. try~except 구조를 사용하여 오류가 발생하는 웹 페이지의 링크를 확인
  4. 오류가 발생하는 웹 페이지 HTML 구조를 확인
  5. 처음 보이는 페이지와 다른 HTML 구조라면, 오류가 발생하는 웹 페이지 HTML 구조에 맞게 추가 코드 작성
    해당 코드는 try~except를 활용하여 작성
  6. 2~5번을 반복하여 크롤링 원하는 웹 페이지를 모두 크롤링 진행

이런 순서로 진행을 하면, 모든 웹 페이지를 확인하지 않아도 HTML 구조가 다른 웹 페이지를 확인할 수 있습니다.

이렇게 네이버 뉴스 게임/리뷰 카테고리 기사 크롤링을 모두 완료하였습니다!!
코드의 원리를 이해하신다면, 다른 카테고리의 네이버 뉴스 크롤링도 충분히 가능하실 겁니다:)
다른 카테고리로 실습해보시는 걸 추천드리고, 궁금한 점이 있으신 분들은 댓글로남겨주시면 답변 드리겠습니다
 
다음에는 크롤링한 데이터를 활용하여 데이터 분석을 진행하는 포스팅을 진행하겠습니다.

★ 읽어주셔서 감사합니다★

728x90
반응형
728x90
반응형

안녕하세요. 오늘은 기존에 작성한 네이버 뉴스 크롤링 코드에서 첫 번째 코드의 자세한 크롤링 과정을 포스팅 하겠습니다.
 
네이버 뉴스 크롤링 전체 코드를 확인하고 싶으신 분들은 아래 링크를 확인해주세요!
https://yhj9855.com/entry/Crawling-%EB%84%A4%EC%9D%B4%EB%B2%84-%EB%89%B4%EC%8A%A4-%ED%81%AC%EB%A1%A4%EB%A7%81-1

 

[Crawling] 네이버 뉴스 크롤링 - 1

안녕하세요. 크롤링에서 가장 첫 포스팅을 네이버 뉴스 크롤링으로 하게 되었어요. 아무래도 바쁜 일상 속에서 매일 뉴스 기사를 파악하는 부분이 시간적으로 힘들었는데, 크롤링하고 데이터

yhj9855.com

 
첫 번째 코드는 Python으로 특정 날짜의 네이버 게임/리뷰 카테고리의 기사들을 크롤링하는데, 제목과 링크만 가지고 오는 코드였습니다.


  • 기본 링크 설정하기

크롤링을 시작할 때 크롤링하고자 하는 페이지의 링크를 설정하는 것이 가장 중요합니다.

위의 그림처럼 2024년 1월 4일의 게임/리뷰 카테고리의 뉴스를 크롤링하고자 한다면 원하는 정보가 담긴 링크는
아래 링크와 같습니다.
 
https://news.naver.com/main/list.naver?mode=LS2D&mid=shm&sid2=229&sid1=105&date=20240104
 
해당 링크에서 가장 중요한 것은 바로 date=20240104 부분인데요
네이버 뉴스의 경우 날짜를 링크 자체에서 구분할 수 있게 되어 있습니다.
그렇기 때문에 특정 날짜의 기사들을 크롤링하고 싶다면 date 뒤에 연도+월+일 붙이면 된다는 사실을 알 수 있습니다.
해당 부분을 코드로 변경하면 아래와 같습니다.

# 수집하고자 하는 메인 링크
link = 'https://news.naver.com/main/list.naver?mode=LS2D&sid2=229&sid1=105&mid=shm&date='
# 크롤링하고 싶은 날짜를 년도월일 나열해준다.
# 날짜를 쉽게 바꾸기 위해 date를 따로 선언해준다.
date = '20240104'
# 메인 링크는 링크에 날짜가 붙은 구조이기 때문에 이렇게 작성해준다.
main_link = link + date

<크롤링 하고자 하는 URL 찾기 Tip>

더보기

링크를 확인할 때 오늘 날짜, 첫 페이지와 같이 기본적으로 접속하면 바로 볼 수 있는 URL로 확인하는 건 피하시는게 좋습니다.

기본으로 설정된 URL은 해당 URL만 특별하게 설정되어 있거나, 보이는 링크와 실제 링크가 다른 경우도 종종 있기 때문에 오류가 발생하기 쉽습니다.

아래 그림처럼 '오늘' 날짜의 뉴스 기사에는 date 표시가 되어있지 않기 때문에 초기 링크를 설정할 때 어려움이 있을 수 있습니다.

'오늘' 날짜의 뉴스 URL
  • 페이지 링크 확인하기

원하는 날짜의 모든 기사를 크롤링하기 위해서는 모든 페이지의 기사를 크롤링할 수 있어야 합니다.
그러기 위해서 페이지가 변경될 때 어떤 링크의 변화가 있는지 확인해보도록 하겠습니다.

위의 그림처럼 동일 날짜 내 페이지가 2페이지로 변경되면 바뀌는 URL은 아래와 같습니다.
※ 1페이지의 링크는 초기 1페이지에서는 확인할 수 없지만 다른 페이지 → 1페이지 실행 시, 다른 페이지와 동일한 방식의 링크를 보여주는 것을 확인할 수 있습니다.
 
https://news.naver.com/main/list.naver?mode=LS2D&sid2=229&sid1=105&mid=shm&date=20240104&page=2
 
해당 링크에서 중요한 부분은 '&page=2' 부분입니다.
네이버 뉴스의 경우 페이지를 링크 자체에서 구분할 수 있게 되어 있습니다!
그렇기 때문에 페이지를 변경하고 싶을 경우, &page=페이지 번호 을 붙이면 된다는 사실을 알 수 있습니다.
 
저희가 크롤링하고자 하는 기사들은 모두 날짜, 페이지에 따라서 달라지는데, 둘 다 모두 링크 자체에서 변화를 줄 수 있습니다.
즉, 링크가 변하지 않고 데이터가 바뀌는 동적 페이지가 존재하지 않기 때문에 2가지 크롤링 방법이 존재합니다.

  1. Beautifulsoup을 활용한 정적 크롤링
  2. Selenium을 활용한 동적 크롤링

저는 여기서 정적 크롤링을 사용하였습니다!
정적 크롤링을 사용한 이유는 정적 크롤링은 chrome의 버전과 상관없이 언제든 사용할 수 있고, 동적 크롤링보다 속도가 월등히 빠르기 때문입니다.
 
저는 개인적으로 정적 크롤링과, 동적 크롤링 모두 사용할 수 있다면 정적 크롤링을 사용하시는 것을 추천드립니다!!

  • 페이지 수를 확인하기

이제 페이지 링크를 확인했으니, 페이지 별로 기사를 크롤링 하는 방법만 남았습니다.
하지만 페이지의 수는 날짜마다 다르기 때문에 페이지의 끝을 알아야 합니다.
페이지의 끝을 찾아야 하는 이유는 아래 그림과 같습니다.

2024년 1월 4일에는 9페이지까지 존재하는데, 링크에 11페이지를 넣어도 오류가 발생하지 않는 것을 볼 수 있습니다.
즉, 네이버 뉴스는 해당하는 링크의 페이지가 존재하지 않거나, 오류가 발생하는 종류의 코드를 사용할 수 없기 때문에 반드시 페이지의 끝을 찾아야 올바르게 페이지를 탐색할 수 있습니다.
 
페이지의 끝을 찾기 위해서는 먼저 페이지 마지막 버튼이 어떤 HTML 구조를 가지고 있는지 확인을 해야 합니다.
모든 페이지의 HTML 구조를 확인하기 위해서는 '개발자 도구' 창을 열어야 합니다.

 

개발자 도구에 대한 자세한 설명은 아래 링크를 확인해주세요!

https://yhj9855.com/entry/%ED%81%AC%EB%A1%AC-%EA%B0%9C%EB%B0%9C%EC%9E%90-%EB%8F%84%EA%B5%AC-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0

 

크롬 개발자 도구 사용하기

안녕하세요. 오늘은 크롤링을 진행하기 위해 반드시 필요한 개발자 도구를 사용하는 법에 대해서 포스팅 하겠습니다. 크롬 개발자 도구란? 크롬 브라우저에 직접 내장된 웹 개발 도구로, 웹 페

yhj9855.com

 

그 중에서 저희는 페이지 끝에 있는 버튼의 구조를 알고 싶은 것이기 때문에 아래 그림처럼 따라합니다.

①번의 아이콘을 클릭한 후, ②번(=원하는 정보)을 클릭하면 원하는 정보의 HTML 구조로 바로 이동이 됩니다.
원하는 정보의 HTML 구조를 확인해보니, 아래와 같이 나왔습니다.
 
<a href="?mode=LS2D&sid2=229&sid1=105&mid=shm&date=20240104&page=9" class="nclicks(fls.page)">9</a>
HTML 구조의 뜻

더보기
  1. 'a' 태그: 링크가 담겨져 있는 공간이면 해당 태그를 사용합니다. 현재 페이지 버튼에는 해당 페이지의 링크 정보가 담겨져 있기 때문에 a 태그가 사용된 것입니다.
  2. href: 링크의 주소를 가지고 있는 부분입니다. 전체 링크를 가지고 있는 경우도 있지만, 대부분 주로 변경이 되는 부분만 따로 담고 있는 경우가 많습니다.
  3. class: 태그의 속성을 나타내는 부분입니다. 크롤링을 진행할 때 많이 사용되는 부분으로 ID가 없을 경우에는 이름처럼 사용되기도 합니다.

저희는 지금 페이지의 마지막을 알고 싶기 때문에 HTML 구조에서 '9'라는 부분을 가져오고 싶습니다.
9 부분은 class가 nclicks(fls.page)이고, a태그인 HTML 구조의 텍스트입니다.
하지만 그림을 보면, 현재 페이지인 2페이지를 제외하면 모두 동일한 구조를 가지고 있는 것을 볼 수 있습니다.

이런 경우에는 조건을 만족하는 모든 페이지를 가져온 다음, 가장 마지막만 가지고 오면 됩니다.
해당 부분을 코드로 변경하면 아래와 같습니다.

# Beautifulsoup으로 코드를 가져오기 위해서 꼭 필요한 과정
# 해당 홈페이지에 올바르게 접근할 경우에는 해당 부분에서 오류가 발생하지 않는다.
# 보통의 페이지에서는 headers가 필요 없는데, 네이버는 접근을 막는 경우가 있어서 headers를 추가해야 한다.
respose = requests.get(main_link, headers={'User-Agent':'Moailla/5.0'})

# main_link의 전체 HTML 구조를 가지고 온다.
html = respose.content
soup = BeautifulSoup(html, 'html.parser')

# 페이지에 해당 하는 부분이 a태그에 class가 nclilcks(fls.page)이기 때문에 이렇게 사용한다.
# find_all인 이유는 동일한 구조가 여러 개 있기 때문이다.
# find를 사용할 경우에는 동일한 구조가 여러 개 있을 경우 가장 앞에 있는 것만 가지고 오고,
# find_all을 사용할 경우에는 동일한 구조 여러 개를 모두 가져와서 리스트로 저장한다.
# 즉, Page는 리스트인 것이다.
Page = soup.find_all('a', {'class' : 'nclicks(fls.page)'})

try :
	# 가장 마지막 페이지를 가지고 오기 위해서 리스트의 가장 마지막 부분을 받아온다.
    end_page = Page[-1].text
# 페이지가 한 페이지 밖에 없을 경우에는 오류가 발생한다.
except :
    end_page = 1

 
페이지별 링크와 마지막 페이지까지 찾았으니, 반복문을 통해서 페이지 별 링크에 접속하는 코드도 생성해봅니다.

# 기사의 수, 제목, 링크를 받아올 예정이기 때문에 정보를 담아줄 데이터 프레임을 생성한다.
Main_link = pd.DataFrame({'number' : [], 'title' : [], 'link' : []})

# 기사의 수를 담을 변수
number = 0

# end_page는 문자열이기 때문에 정수로 변환하여 사용한다.
for i in range(1, int(end_page)+1) :
    page_link = main_link + '&page=' + str(i)
  • 기사의 제목과 링크 가져오기

마지막으로 크롤링 목적인 기사의 제목과 링크를 가져오기만 하면 첫 번째 코드의 크롤링이 완료됩니다!
페이지 수를 확인했던 것처럼 개발자 도구에서 기사의 제목과 링크가 어떤 HTML 구조를 가지고 있는지 확인해보겠습니다.

HTML 구조를 확인해보니 아래와 같이 나왔습니다.
 
<dt>
<a href="https://n.news.naver.com/mnews/article/009/0005239915?sid=105" class="nclicks(itn.2ndcont)">
 전세계 300만장 팔린 이 게임...이정도였어? </a>
</dt>
 
이전 페이지 수의 HTML 구조와 매우 유사한 것을 알 수 있습니다.
저희가 수집해야 할 정보는 아래와 같습니다.

  1. 기사의 제목은 dt태그 속 a태그 HTML 구조의 텍스트
  2. 기사의 링크는 dt태그 속 a태그 HTML 구조의 href

해당 부분을 코드로 변경하면 아래와 같습니다.
※ 페이지 수와 다른 방법으로 크롤링하기 위해서 dt 태그 속 a태그로 지정하였지만, 페이지 수와 마찬가지로 a태그와 class 이름으로 지정하여도 동일한 결과물을 얻을 수 있습니다.

    respose = requests.get(page_link, headers={'User-Agent':'Moailla/5.0'})
    html = respose.content
    soup = BeautifulSoup(html, 'html.parser')

    # 정보가 담긴 a태그 바로 위의 태그인 dt태그를 전부 찾아준다.
    # dt태그는 오직 기사와 관련된 부분에만 존재하는 태그로, a태그의 범위를 좁히는 목적으로만 사용한다.
    # 페이지 수를 찾는 방법과 동일하게 a태그와 class이름으로 지정해도 상관없다.
    Info = soup.find_all('dt')

for info in Info :
        # 기사의 제목
        # strip을 사용하여 눈으로 확인할 수 없는 양 끝의 공백을 잘라준다.
        title = info.find('a').text.strip()
        # HTML 태그가 잘못 들어오는 경우가 종종 있어서 해당 부분을 적어준다.
        # 텍스트가 없는 것은 기사로 판단하지 않아서 해당 부분의 데이터는 넘어가는 것으로 진행한다.
        if title == '' :
            continue
        # href 부분을 가져오는 방법
        # a태그 내 href를 가져오는 의미이다.
        link = info.find('a')["href"]
        # 번호는 0부터 시작하기 때문에 1을 더해준다.
        li = [number+1, title, link]
        Main_link.loc[number] = li
        number = number+1
  • 엑셀 파일로 저장

크롤링 작업은 완료하였습니다.
이제 크롤링한 데이터프레임을 엑셀 파일로 저장하도록 하겠습니다.

# 엑셀을 잘 관리하기 위해서 크롤링 날짜를 파일 이름에 포함한다.
excel_name = 'news_' + date + '.xlsx'
with pd.ExcelWriter(excel_name) as writer :
    Main_link.to_excel(writer, sheet_name='링크', index=False)

 
이런 과정을 통해서 특정 날짜의 모든 기사의 제목과 링크를 크롤링하는 코드가 완성되었습니다!!
<전체 코드>

더보기
from bs4 import BeautifulSoup
import requests
import pandas as pd
from openpyxl import *

link = 'https://news.naver.com/main/list.naver?mode=LS2D&sid2=229&sid1=105&mid=shm&date='
date = '20240104'
main_link = link + date 
Main_link = pd.DataFrame({'number' : [], 'title' : [], 'link' : []})
respose = requests.get(main_link, headers={'User-Agent':'Moailla/5.0'})
html = respose.content
soup = BeautifulSoup(html, 'html.parser')
Page = soup.find_all('a', {'class' : 'nclicks(fls.page)'})
try :
    end_page = Page[-1].text
except :
    end_page = 1
number = 0
for i in range(1, int(end_page)+1) :
    page_link = main_link + '&page=' + str(i)
    respose = requests.get(page_link, headers={'User-Agent':'Moailla/5.0'})
    html = respose.content
    soup = BeautifulSoup(html, 'html.parser')
    Info = soup.find_all('dt')
    for info in Info :
        title = info.find('a').text.strip()
        if title == '' :
            continue
        link = info.find('a')["href"]
        li = [number+1, title, link]
        Main_link.loc[number] = li
        number = number+1
excel_name = 'news_' + date + '.xlsx'
with pd.ExcelWriter(excel_name) as writer :
    Main_link.to_excel(writer, sheet_name='링크', index=False)

저는 이번에 Xpath, CSS_Selector를 사용하지 않았는데, 해당 부분을 사용하면 쉽게 크롤링을 할 수 있지만
HTML 코드가 복잡하거나 크롤링을 배우고 싶은 분들에게는 좋은 방법이 아니라고 생각합니다.
 
기사의 본문을 크롤링하는 두 번째 코드의 자세한 크롤링 코딩 과정을 확인하고 싶으신 분들은 아래 링크를 확인해주세요!!
https://yhj9855.com/entry/Crawling-%EB%84%A4%EC%9D%B4%EB%B2%84-%EB%89%B4%EC%8A%A4-%ED%81%AC%EB%A1%A4%EB%A7%81-3

 

[Crawling] 네이버 뉴스 크롤링 - 3

안녕하세요. 오늘은 기존에 작성한 네이버 뉴스 크롤링 코드에서 두 번째 코드의 자세한 크롤링 과정을 포스팅 하겠습니다. 네이버 뉴스 크롤링 전체 코드를 확인하고 싶으신 분들은 아래 링크

yhj9855.com


코드에 대해 궁금한 점이 있으신 분들은 댓글로 남겨주시면, 답변 드리겠습니다.

★ 읽어주셔서 감사합니다★

728x90
반응형

+ Recent posts