예를 들어보면 제목대로 네이버 뉴스를 검색 후 크롤링을 하여 가져온다고 치자. 일일히 검색어를 치고, 클릭을 하여 페이지를 넘겨가며 복사 붙여넣기를 하는 수고로움을 하지 않으려고 하는게 크롤링이다. 그러다 보니 클릭을 해서 다음페이지 넘어가는 것을 "프로그램화" 하여 마치 넘어간거 처럼 만들기 위해 소스코드를 짜는 것이다.
이게 네이버 입장에서는 해킹을 하려고 시도하는 것으로 착각을 할 수 있으니, 보안상 혹은 컴퓨터(서버) 부하에 영향을 미치게 되니 이를 막기위해서 HTLML 소스의 방식을 어느 일정 기간마다 변경을 하고 있다.
따라서 몇년전에 잘 돌아가던 크롤링 소스가 이제는 무용지물인 경험을 할 수 있을 것이다.
완벽한 소스는 없다. 모든 포털 사이트의 뉴스기사가 동일한 형태의 소스로 짜여져 있다면 좋겠지만, 그렇지는 않다. 네이버 뉴스를 위해 짠 소스는 어쩌면 네이버 뉴스에서만 돌아갈 가능성이 높다.(쓰니도 해보지는 않음)
단, 크롤링 구조를 완벽히 이해를 한다면 응용이 가능 하겠지...
# -*- coding: utf-8 -*-
from bs4 import BeautifulSoup
from datetime import datetime
import requests
import pandas as pd
import re
#한글깨짐 방지
import sys
import io
sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding = 'utf-8')
sys.stderr = io.TextIOWrapper(sys.stderr.detach(), encoding = 'utf-8')
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''
< naver 뉴스 검색시 리스트 크롤링하는 프로그램 > _select사용
- 크롤링 해오는 것 : 링크,제목,신문사,내용요약본
- 내용요약본 -> 정제 작업 필요
- 리스트 -> 딕셔너리 -> df -> 엑셀로 저장
'''''''''''''''''''''
#각 크롤링 결과 저장하기 위한 리스트 선언
title_text=[]
link_text=[]
source_text=[]
contents_text=[]
result={}
#엑셀로 저장하기 위한 변수
RESULT_PATH ='C:/' #결과 저장할 경로
now = datetime.now() #파일이름 현 시간으로 저장하기
#내용 정제화 함수
def contents_cleansing(contents):
first_cleansing_contents = re.sub('<dl>.*?</a> </div> </dd> <dd>', '',str(contents)).strip() #앞에 필요없는 부분 제거
second_cleansing_contents = re.sub('<ul class="relation_lst">.*?</dd>', '', first_cleansing_contents).strip()#뒤에 필요없는 부분 제거 (새끼 기사)
third_cleansing_contents = re.sub('<.+?>', '', second_cleansing_contents).strip()
contents_text.append(third_cleansing_contents)
#print(contents_text)
#크롤링 시작
def crawler(maxpage,query,sort,s_date,e_date):
s_from = s_date.replace(".","")
e_to = e_date.replace(".","")
page = 1
maxpage_t =(int(maxpage)-1)*10+1 # 11= 2페이지 21=3페이지 31=4페이지 ...81=9페이지 , 91=10페이지, 101=11페이지
while page <= maxpage_t:
url = "https://search.naver.com/search.naver?where=news&query=" + query + "&sort="+sort+"&ds=" + s_date + "&de=" + e_date + "&nso=so%3Ar%2Cp%3Afrom" + s_from + "to" + e_to + "%2Ca%3A&start=" + str(page)
response = requests.get(url)
html = response.text
#뷰티풀소프의 인자값 지정
soup = BeautifulSoup(html, 'html.parser')
#<a>태그에서 제목과 링크주소 (a 태그 중 class 명이 news_tit인 것)
atags = soup.find_all('a', 'news_tit')
for atag in atags:
title = atag.get('title')
title_text.append(title) #제목
link_text.append(atag['href']) #링크주소
#신문사 추출 (a 태그 중 class 명이 info press인 것)
source_lists = soup.find_all('a', 'info press')
for source_list in source_lists:
source_text.append(source_list.text) #신문사
#본문요약본 (a 태그 중 class 명이 api_txt_lines dsc_txt_wrap인 것)
contents_lists = soup.find_all('a','api_txt_lines dsc_txt_wrap')
for contents_list in contents_lists:
contents_cleansing(contents_list) #본문요약 정제화
#모든 리스트 딕셔너리형태로 저장
result= {"title":title_text , "source" : source_text ,"contents": contents_text ,"link":link_text }
df = pd.DataFrame(result) #df로 변환
page += 10
# 새로 만들 파일이름 지정
outputFileName = '%s-%s-%s %s시 %s분 %s초 merging.xlsx' % (now.year, now.month, now.day, now.hour, now.minute, now.second)
df.to_excel(RESULT_PATH+outputFileName,sheet_name='sheet1')
#메인함수
def main():
info_main = input("="*50+"\n"+"입력 형식에 맞게 입력해주세요."+"\n"+" 시작하시려면 Enter를 눌러주세요."+"\n"+"="*50)
maxpage = input("최대 크롤링할 페이지 수 입력하시오: ") #10,20...
query = input("검색어 입력: ") #네이버, 부동산...
sort = input("뉴스 검색 방식 입력(관련도순=0 최신순=1 오래된순=2): ") #관련도순=0 최신순=1 오래된순=2
s_date = input("시작날짜 입력(2019.01.04):") #2019.01.04
e_date = input("끝날짜 입력(2019.01.05):") #2019.01.05
crawler(maxpage,query,sort,s_date,e_date)
#메인함수 수행
main()
소스의 구조는 어렵지 않다.
위의 소스에서 특이사항이 있는 부분은 아래서 설명한다.