프로그래밍/Crawling

[WebCrawling] 네이버 뉴스 섹션별 토픽 기사 크롤링 2022.ver

seojeon9 2022. 8. 3. 02:05

 

이 게시글은 데이터사이언스엔지니어링_전문가 과정을 수강하며 복습을 위해 정리한 글입니다.


네이버 뉴스 크롤링 세번째 게시글입니다. 앞선 게시글을 본 후 보는 것을 추천드립니다.

 

[WebCrawling] 네이버 뉴스 메뉴 크롤링 2022.ver

이 게시글은 데이터사이언스엔지니어링_전문가 과정을 수강하며 복습을 위해 정리한 글입니다. 포털사이트 크롤링 소스내에서 특정 문자열(data)을 자칭하는 선택자 얻기(크롬 개발자도구 사용)

seojeong-99.tistory.com

 

 

[WebCrawling] 네이버 뉴스 섹션 토픽 크롤링 2022.ver

이 게시글은 데이터사이언스엔지니어링_전문가 과정을 수강하며 복습을 위해 정리한 글입니다. 이전 게시글을 통해 네이버 -> 뉴스 -> 각 섹션 url을 얻어왔을 것이다. 이번에 할 단계는 각 섹션

seojeong-99.tistory.com


이제 드디어 본격적으로 기사 내용을 추출할 것이다.

원기사를 추출하기 앞서 간결하게 보이는 기사를 먼저 수집하려한다.

토픽별 기사

여기 보이는 기사들의 제목, 세부내용, 뉴스사, 날짜, url을 추출해 올 것이다.

from urllib.request import urlopen
import requests
import pandas as pd
import bs4 # 파싱패키지

def get_topic_info(url) :
    # 빈 리스트 생성
    paper_list = []
    date_list = []
    link_list = []
    title_list = []
    subscript_list = []
    
    # 사이트(url)에 요청해서 소스 응답
    headers = {"User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.141 Whale/3.15.136.29 Safari/537.36"}
    res = requests.get(url, headers=headers)
    
    # bs4 객체 생성
    html = res.text
    bs_obj = bs4.BeautifulSoup(html,'html.parser')
    
    try :
        # 전체 기사 카드를 포함하고 있는 영역 추출
        news_list = bs_obj.findAll("div",{'class':'cluster'})[1]

        # news_list의 모든 li 태그 추출
        lis = news_list.findAll('li')
    
        
        for li in lis :
            try :
                title_list.append(li.findAll('a')[1].text)
                link_list.append(li.findAll('a')[1]['href'])
                subscript_list.append(li.find('span',{'class':'lede'}).text)
                paper_list.append(li.find('span',{'class':'writing'}).text)
                date_list.append(li.find('span',{'class':'date'}).text)
            except :
                print('이미지가 없음')

        news_dict = {'제목':title_list,
                    'URL':link_list,
                    '신문사':paper_list,
                    '작성일':date_list,
                    '세부내용':subscript_list}
    
        return news_dict

    except :
            print('형식이 조금 다름')

실행중에 대다수의 형식과 다른 기사들이 있어 오류가 발생할 수도 있다.

이 같은 경우 그 기사를 찾아서 따로 적용을 해주어도 되지만

지금 하는 크롤링의 경우 받아오는 데이터의 양이 많고 오류나는 기사 하나를 받아오지 않아도

전혀 문제가 되지 않기 때문에

그냥 예외처리하여 넘어가는 방법을 선택하였다.

꼭 모든 데이터를 받아와야 하는 경우에는 따로 코드를 만들기 바란다.

 

이제 위 함수를 사용해 데이터를 수집하여 저장해보겠다.

# 빈df 생성
dict_sub ={}
dict_sub["제목"] = []
dict_sub["URL"]=[]
dict_sub["신문사"] = []
dict_sub['작성일'] = []
dict_sub['세부내용'] = []
topic_info_df = pd.DataFrame(dict_sub)
topic_info_df

for url in topic_df['url'] :
    res = pd.DataFrame(get_topic_info(url))
    topic_info_df = pd.concat([topic_info_df,res],
                             axis=0,
                             ignore_index=True)
                             
# 파일로 저장
topic_info_df.to_csv('./crawl_data/naver_news_topic_info.csv')

 


 

기사 원본

이제 마지막으로 최종수집된 토픽별 링크를 이용해서 원 기사 내용 정체를 수집할 것이다.

  • 기사제목
  • 기사입력시간
  • 기사내용
  • 함수로 구성 : get_news_sub_info(url)

이때 너무 많은 요청을 한번에 하면 접속거부될 수 있으므로 time.sleep()을 두고 텀을두고 진행하기 바란다.

def get_news_sub_info(url) :
    dict_sub={}
    
    # 1. 소스 추출
    headers ={"User-Agent" : 
          "Mozilla/5.0(Window NT 10.0;Win64;x64) AppleWebKit/537.36 (KHTML,likeGecko) Chrome/87.0.4280.88 Safari/537.36"}
    result = requests.get(url,headers=headers)

    # 2. bs4 객체 생성
    html = result.content
    bs_obj = bs4.BeautifulSoup(html,'html.parser')

    try :
        # 3. 필요데이터 추출(parsing)
        # 기사 제목
        title = bs_obj.find("div",{'class':"media_end_head_title"}).text.replace('\n','')
        # 기사 입력시간
        date_time = bs_obj.find("div",{"class":"media_end_head_info_datestamp"}).find('span').text
        # 기사 내용
        contents = bs_obj.find(id='newsct_article').text

        # 기사 저장
        dict_sub['기사제목'] = title
        dict_sub['기사입력시간'] = date_time
        dict_sub['기사내용']= contents

        return dict_sub
    except :
        print('error')

 

# 수집 데이터 불러오기
news_df = pd.read_csv('./crawl_data/naver_news_topic_info.csv', index_col=0)
news_df.head()

 

# 호출이 계속해서 들어오면 서버에서 공격으로 인지하고 접속을 끊어버리기 때문에
# 10개의 기사 데이터만 요청하겠다
df_url = news_df['URL'][2045:2055]

# 빈 데이터프레임 생성
dict_sub ={}
dict_sub["기사제목"] = []
dict_sub["기사입력시간"]=[]
dict_sub["기사내용"] = []
news_sub_df = pd.DataFrame(dict_sub)
news_sub_df

# 기사 추출
for url in df_url :
    res = pd.DataFrame(get_news_sub_info(url),index=range(1,2))
    news_sub_df = pd.concat([news_sub_df,res],axis=0,ignore_index=True)
    
# 파일로 저장
news_sub_df.to_csv('./crawl_data/naver_news.csv')

이렇게 하면 각 섹션별 토픽별 기사 크롤링이 완성된다!!

위의 방법을 따라 기사데이터 추출해 잘 사용하기 바란다.

 

크롤링 특성상 네이버가 페이지를 리뉴얼하면 위의 코드가 바로 적용되지 않을 수 있다.

하지만 방법을 알고 태그를 구별하여 대입한다면 충분히 크롤링할 수 있을것이다.

 

자세한 개념과 문법을 알고 싶다면 아래의 게시글로 가보길 바란다.

 

[WebCrawling] 웹 크롤링 기본 개념 및 문법 (BeautifulSoup사용법)

이 게시글은 데이터사이언스엔지니어링_전문가 과정을 수강하며 복습을 위해 정리한 글입니다. 웹 크롤링은 웹 브라우저를 통해 진행 됨 관련 패키지 : webbrowser # 브라우저 컨트롤 모듈 import impo

seojeong-99.tistory.com

 

그럼 이만

728x90