공학속으로/python

[Python] 네이버 뉴스 검색 크롤링하기

더월드 2023. 8. 11.

기사 검색하기

아래와 같이 네이버 뉴스 검색 부분에 '사건 +  사고'를 검색하면,

전체 URL은 "https://search.naver.com/search.naver?where=news&query=[검색키워드]&sm=tab_opt&sort=1&photo=0&field=0&pd=1&ds=2024.09.13&de=2024.09.20&docid=&related=0&mynews=0&office_type=0&office_section_code=0&news_office_checked=&nso=so%3Add%2Cp%3A1w&is_sug_officeid=0&office_category=0&service_area=0" 형태임을 알 수 있다.

 

https://search.naver.com/search.naver?where=news&query=[검색키워드]   이부분은 변하지 않는 부분이고,

②"&sm=tab_opt&sort=1&photo=0&field=0&pd=1&ds=2024.09.13&de=2024.09.20&docid=&related=0&mynews=0&office_type=0&office_section_code=0&news_office_checked=&nso=so%3Add%2Cp%3A1w&is_sug_officeid=0&office_category=0&service_area=0" 이부분은 오션에 따라 달라짐을 알 수 있다.

 

 

bs 라이브러리를 사용하여 뉴스 검색 URL에서 뉴스 제목, 언론사, 게시일, 요악을 크롤링 하는 코드는 아래와 같고,

resp = requests.get( [URL(키워드 포함)], headers=headers, verify=False)

soup = bs(resp.text, 'html.parser')
#print(resp.text)

news_title = soup.findAll("a", {"class":"news_tit"})
news_info = soup.findAll("a", {"class":"info press"})
news_date = soup.findAll("span", {"class":"info"})
news_contents = soup.findAll("a", {"class":"api_txt_lines dsc_txt_wrap"})

 

위 코드를 포함한 뉴스를 검색하는 코드는 아래와 같다.

# -*- coding: utf-8 -*-
import requests
import urllib.parse
import warnings
import time
import os.path 
from datetime import datetime
from bs4 import BeautifulSoup as bs

warnings.filterwarnings("ignore")

#--------------------------
# 메인
#--------------------------
def main(): 
    keywords = [
                '사건 + 사고',
                '독점 + 수사'
                ]
    # csv 헤더
    header_list = ['No','Title','Media','URL','description','pubDate','UID','KeyWord']
    
    # 뉴스 검색 URL 1 (고정)
    prefix_url = "https://search.naver.com/search.naver?where=news&query="
    
    # 뉴스 검색 URL 2 (옵션)
    suffix_url = "&sm=tab_srt&sort=1&photo=0&field=0&reporter_article=&pd=12&ds=2024.09.15.07.06&de=2024.09.20.13.06&docid=&nso=so%3Add%2Cp%3Aall%2Ca%3Aall&mynews=0&refresh_start=0&related=0"
    
    # User-Agent
    headers = { 'user-agent' : 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36' }

    time.sleep(5)
    
    cnt=0
    
    # 60초 간격으로 반복
    while True:
        print("[검색]" + time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())))
        
        # 키워드 여러개 사용
        for keyword in keywords:        
            
            # 전체 URL
            resp = requests.get(prefix_url + urllib.parse.quote(keyword) + suffix_url, headers=headers, verify=False)
            resp.encoding = None
            
            # bs 을 사용한 html 파싱하기
            soup = bs(resp.text, 'html.parser')
            #print(resp.text)
            
            # 파싱 결과물에서 제목, 정보, 게시일, 요약 찾아 저장하기
            news_title = soup.findAll("a", {"class":"news_tit"})
            news_info = soup.findAll("a", {"class":"info press"})
            news_date = soup.findAll("span", {"class":"info"})
            news_contents = soup.findAll("a", {"class":"api_txt_lines dsc_txt_wrap"})
			
            # 기사별로 구분하기
            for i in range(len(news_title)):
                title = news_title[i].get('title')
                link = news_title[i].get('href')
                description = "'{0}'".format(news_contents[i].get_text())
                
                pubDate = news_date[i].get_text()
                author = news_info[i].get_text()
                
                # 출력
                print(pubDate)
                print(author)
                print(title)
                print(link)
                print(description)
                
        print("[대기]" + time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())))
        
        # 60초 딜레이
        time.sleep(60)

#--------------------------
# Main
#--------------------------
if __name__ == "__main__":
    main()

 

검색된 기사는 패스하기

1분마다 기사를 검색하기에 '제목'과 '뉴스 URL'을 합치 문자열을  SHA1 해시로 변환해서 UID를 생성하여 기록한 후, 동일 UID에 대해서는 패스하도록 코드를 넣으면 한 번 검색된 기사는 다시 출력하지 않을 수 있습니다.

#--------------------------
# 기사 UID 생성
#--------------------------
def UID_make(str):
    result = hashlib.sha1(str.encode())
    enVal = result.hexdigest()
    return enVal

#--------------------------
# 기사 UID 체크
#--------------------------    
def Check_UID(file, uid):
    enVal = False
    if os.path.isfile(file):
        with open(file,encoding='utf-8',newline='') as csvfile:
            reader = csv.DictReader(csvfile)                            
            for row in reader:
                if uid == row['UID']:
                    enVal = True
                    break                
   
    return enVal
 
#--------------------------
# 메인
#--------------------------
def main(): 
    기사 검색...

    # check UID        
    title_media = "{0} - {1}".format(title,link)
    uid = UID_make(title_media)                
                
    if Check_UID(file, uid):
        break
    else:
        print('기사출력')                   

#--------------------------
# Main
#--------------------------
if __name__ == "__main__":
    main()

 

검색된 기사 저장하기

네이버 뉴스를 검색하기 csv 파일로 저장하는 코드는 아래와 같다.

# 파일의 첫 번째 행은 헤더 추가
if cnt == 0:
    cnt = cnt+1                        
else:
    with open(file,encoding='utf-8',newline='') as csvfile:
        reader = csv.DictReader(csvfile)                            
        cnt = 1
        for row in reader:
            cnt=cnt+1  

# 뉴스 기사 출력
print(" ------------------------------------------------------------ ")
print("{0}. {1}".format(cnt, title_media))
print('URL:{0}'.format(link))
print(description)
print(" ------------------------------------------------------------ ")

# 파일 오픈
f = open(file,'a',encoding='utf-8',newline='')
csvWriter = csv.writer(f)
if cnt==1:
    csvWriter.writerow(header_list)

# 파일 저장
csvWriter.writerow([cnt,title,author,link,description, pubDate,uid,keyword])
msg = "▶ {0}({1})\n{2}\n{3}".format(title, pubDate, description, link)
print(msg)                  

#파일 닫기
f.close()

 

전체 코드

위 네이버 뉴스 검색, UID 생성/체크, CSV파일로 저장하는 소스를 합친 전체적인 코드는 아래와 같다.

# -*- coding: utf-8 -*-
import requests
import urllib.parse
import warnings
import time
import csv
import os.path 
from datetime import datetime
import hashlib
from bs4 import BeautifulSoup as bs

warnings.filterwarnings("ignore")

#--------------------------
# Main
#--------------------------  
def TimeConvert(strTime):
    inputTimeFormat = "%a, %d %b %Y %H:%M:%S %z"
    outputTimeFormat = "%Y-%m-%d %H:%M:%S"
    
    objTime = datetime.strptime(strTime, inputTimeFormat)
    enVal = objTime.strftime(outputTimeFormat)      
    return enVal

#--------------------------
# 기사 UID 생성
#--------------------------
def UID_make(str):
    result = hashlib.sha1(str.encode())
    enVal = result.hexdigest()
    return enVal

#--------------------------
# 기사 UID 체크
#--------------------------    
def Check_UID(file, uid):
    enVal = False
    if os.path.isfile(file):
        with open(file,encoding='utf-8',newline='') as csvfile:
            reader = csv.DictReader(csvfile)                            
            for row in reader:
                if uid == row['UID']:
                    enVal = True
                    break                
   
    return enVal

#--------------------------
# 메인
#--------------------------
def main(): 
    keywords = [
                '사건 + 사고',
                '독점 + 수사'
                ]
    
    # csv 헤더
    header_list = ['No','Title','Media','URL','description','pubDate','UID','KeyWord']
    
    # 뉴스 검색 URL 1 (고정)
    prefix_url = "https://search.naver.com/search.naver?where=news&query="
    
    # 뉴스 검색 URL 2 (옵션)
    suffix_url = "&sm=tab_srt&sort=1&photo=0&field=0&reporter_article=&pd=12&ds=2024.09.15.07.06&de=2024.09.20.13.06&docid=&nso=so%3Add%2Cp%3Aall%2Ca%3Aall&mynews=0&refresh_start=0&related=0"
    
    # User-Agent
    headers = { 'user-agent' : 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36' }

    print("____________________________________________")
    print("              네이버 뉴스 검색            ")
    print("____________________________________________")
    
    time.sleep(5)
    
    file = f'C:/Work/navernews_{datetime.today().strftime("%Y%m%d")}.csv'

    cnt=0
    
    # 60초마다 반복
    while True:
        print("[검색]" + time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())))
        
        # 검색어 별로 크롤링
        for keyword in keywords:
        	# 전체 URL
            resp = requests.get(prefix_url + urllib.parse.quote(keyword) + suffix_url, headers=headers, verify=False)
            resp.encoding = None
            
            # URL 파싱
            soup = bs(resp.text, 'html.parser')
            #print(resp.text)
            
            # 기사제목, 언론사, 게시일, 요약 내용만 크롤링
            news_title = soup.findAll("a", {"class":"news_tit"})
            news_info = soup.findAll("a", {"class":"info press"})
            news_date = soup.findAll("span", {"class":"info"})
            news_contents = soup.findAll("a", {"class":"api_txt_lines dsc_txt_wrap"})

            for i in range(len(news_title)):
                title = news_title[i].get('title')
                link = news_title[i].get('href')
                description = "'{0}'".format(news_contents[i].get_text())
                
                pubDate = news_date[i].get_text()
                author = news_info[i].get_text()
                
                #print(pubDate)
                #print(author)
                #print(title)
                #print(link)
                #print(description)
                
                # UID 생성하기
                title_media = "{0} - {1}".format(title,link)
                uid = UID_make(title_media)                
                
                # UID 확인하기
                if Check_UID(file, uid):
                    break
                else:
                    if cnt == 0:
                        cnt = cnt+1                        
                    else:
                    	# CSV 파일 열기
                        with open(file,encoding='utf-8',newline='') as csvfile:
                            reader = csv.DictReader(csvfile)                            
                            cnt = 1
                            for row in reader:
                                cnt=cnt+1  
                    
                    print(" ------------------------------------------------------------ ")
                    print("{0}. {1}".format(cnt, title_media))
                    print('URL:{0}'.format(link))
                    print(description)
                    print(" ------------------------------------------------------------ ")
                    f = open(file,'a',encoding='utf-8',newline='')
                    csvWriter = csv.writer(f)
                    
                    # CSV 파일 해더 추가하기
                    if cnt==1:
                        csvWriter.writerow(header_list)
                    
                    # CSV 저장하기
                    csvWriter.writerow([cnt,title,author,link,description, pubDate,uid,keyword])
                    msg = "▶ {0}({1})\n{2}\n{3}".format(title, pubDate, description, link)
                    print(msg)                  
                    f.close()
                
        print("[대기]" + time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())))
        
        # 60초 대기
        time.sleep(60)

#--------------------------
# Main
#--------------------------
if __name__ == "__main__":
    main()

 

 

네이버뉴스 크롤링 실행 결과

댓글

💲 추천 글