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
반응형

안녕하세요. 오늘은 기존에 작성한 네이버 뉴스 크롤링 코드에서 두 번째 코드의 자세한 크롤링 과정을 포스팅 하겠습니다.
 
네이버 뉴스 크롤링 전체 코드를 확인하고 싶으신 분들은 아래 링크를 확인해주세요!
<네이버 뉴스 크롤링 전체 코드>
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
반응형

+ Recent posts