1. 특정 뉴스 웹페이지 크롤링 중 에러 발생 시 회피
: 종종 naver.news로 들어갔는데도 이상한 페이지로 넘어가서 HTML 태그가 바뀌는 경우가 있다 (특히, 연예 섹션 뉴스)
-> try, except 함수 사용
DataFrame을 만드는 과정에서 각 list의 길이가 완전히 일치해야한다. 이를 위해 본문이나 언론사, 등등 어느 하나라도 ERROR가 나는 경우에 전체가 각 list에 append되지 않도록 해야한다.
따라서, Error가 날 경우 append가 되지 않도록 1) append 함수는 제목/날짜/본문/언론사 정보가 모두 추출되었을 때 제일 마지막에 몰아서 코드를 작성하도록 한다. 또한, 2) 한 곳이라도 에러가 나는 경우에도 전체 코드가 except로 넘어가도록 하는 코드를 작성해야 한다.
+ 스크래핑할 때 가장 많이 나는 에러:
find함수로 search 실패하여 None이 입력되는 경우, get_text()하면 에러가 남
예를 들자면, source_news.find('h3', {'id' : 'articleTitle'}).get_text()
이미 source_news.find('h3', {'id' : 'articleTitle'}) 이 함수에서 search가 실패하여 None인 상태에서 get_text를 실행해주면 에러가 나는 것이다.
이를 방지하기 위해 try, except 함수를 사용한다.
2. 여러 페이지에 걸쳐 크롤링하기
: 페이지네이션
- 콘텐츠를 여러 개 페이지에 나눠서 보여주는 사용자 인터페이스
- 페이지 넘어가도록 설정하는 방법
1) 단순하게 a 태그로 만들어놓은 경우 (네이버)
2) 자바스크립트 함수로 만들어놓은 경우, li or button 태그
-> 그러면 브라우저 강제로 onClick을 활용하여 페이지 바꾸도록
(다음 또는 다다음 게시글에 소개될 예정)
- URL 분석이 필수적
https://search.naver.com/search.naver?
where=news&
sm=tab_pge&
query=데이터분석&
sort=0&
photo=0&
field=0&
pd=0&
ds=&
de=&cluster_rank=20&
mynews=0&
office_type=0&
office_section_code=0&
news_office_checked=&
nso=so:r,p:all,a:all&
start=11 # 페이지당 기사 시작 번호
start=' '를 활용해서 아래와 같은 코드 작성
current_call = 1
last_call = (max_page - 1) * 10 + 1 # max_page이 5일 경우 41에 해당
while current_call <= last_call:
print(current_call) # 1, 11, 21, 31, 41
current_call += 10
3. 날짜 지정하여 크롤링하기
'''
https://search.naver.com/search.naver?
where=news&
query=데이터분석&
sm=tab_opt&
sort=0&
photo=0&
field=0&
pd=3&
ds=2022.01.01&
de=2022.03.28&
docid=&
related=0&
mynews=0&
office_type=0&
office_section_code=0&
news_office_checked=&
nso=so%3Ar%2Cp%3Afrom20220101to20220328&
is_sug_officeid=0
'''
https://search.naver.com/search.naver?
where=news&
query=데이터분석&
# ds=2022.01.01&
# de=2022.03.27&
nso=so%3Ar%2Cp%3Afrom20220101to20220327
url에 아래와 같이 nso 파라미터를 추가해주었다.
# \ : 사칙연산 쓸 때 줄바꿈하고 싶을 때 씀 (여러 개의 lines를 하나의 line으로 연결시키는 방법)
url = "https://search.naver.com/search.naver?where=news&query=" + query \
+ "&nso=so%3Ar%2Cp%3Afrom" + start_date \
+ "to" + end_date \
+ "%2Ca%3A&start=" + str(current_call)
4. 기사 정렬 순서 지정하여 크롤링하기
https://search.naver.com/search.naver?where=news&query=데이터분석&sm=tab_opt&sort=1&photo=0&field=0&pd=0&ds=&de=&docid=&related=0&mynews=0&office_type=0&office_section_code=0&news_office_checked=&nso=so%3Add%2Cp%3Aall&is_sug_officeid=0
https://search.naver.com/search.naver?where=news&query=데이터분석&sm=tab_opt&sort=0&photo=0&field=0&pd=0&ds=&de=&docid=&related=0&mynews=0&office_type=0&office_section_code=0&news_office_checked=&nso=so%3Ar%2Cp%3Aall&is_sug_officeid=0
https://search.naver.com/search.naver?where=news&query=데이터분석&sm=tab_opt&sort=2&photo=0&field=0&pd=0&ds=&de=&docid=&related=0&mynews=0&office_type=0&office_section_code=0&news_office_checked=&nso=so%3Ar%2Cp%3Aall&is_sug_officeid=0
# 관련도순 = 0 최신순 = 1 오래된순 = 2
관련도순 = 0, 최신순 = 1, 오래된순 = 2
최종 코드
def main_crawling(query, start_date, end_date, sort_type, max_page):
# if type(query) == None: 이 아니라
# if query == '': 이렇게 써야 아무것도 입력하지 않았을 때에도 확인할 수 있음
if query == '':
query = '데이터 분석'
if len(start_date) != 10:
start_date = '2021.01.01'
if len(end_date) != 10:
end_date = '2021.12.31'
if sort_type not in ['0', '1', '2']:
sort_type = '0'
# if max_page == '':
# max_page = 5
# 각 기사들의 데이터를 종류별로 나눠담을 리스트를 생성합니다. (추후 DataFrame으로 모을 예정)
titles = []
dates = []
articles = []
article_urls = []
press_companies = []
# 주어진 일자를 쿼리에 맞는 형태로 변경해줍니다.
start_date = start_date.replace(".", "")
end_date = end_date.replace(".", "")
# 지정한 기간 내 원하는 페이지 수만큼의 기사를 크롤링합니다.
current_call = 1
last_call = (max_page - 1) * 10 + 1 # max_page이 5일 경우 41에 해당
while current_call <= last_call:
print('\n{}번째 기사글부터 크롤링을 시작합니다.'.format(current_call))
url = "https://search.naver.com/search.naver?where=news&query=" + query \
+ "&sort=" + sort_type \
+ "&nso=so%3Ar%2Cp%3Afrom" + start_date \
+ "to" + end_date \
+ "%2Ca%3A&start=" + str(current_call)
urls_list = []
try: # 네이버 뉴스 검색결과 페이지 자체에 접근이 불가능할 경우 에러가 발생할 수 있습니다.
web = requests.get(url).content
source = BeautifulSoup(web, 'html.parser')
for urls in source.find_all('a', {'class' : "info"}):
if urls["href"].startswith("https://news.naver.com"):
urls_list.append(urls["href"])
except:
print('해당 뉴스 검색 페이지의 네이버 뉴스 링크를 모으는 중 에러가 발생했습니다. : ', url)
# urls_list : 해당 페이지에 있는 "네이버 뉴스"의 링크 모음(list)
if urls_list != []:
for url in urls_list:
try: # 특정 뉴스 기사글 하나를 크롤링하는 중 에러가 발생할 수 있습니다.ㄴ
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'}
web_news = requests.get(url, headers=headers).content
source_news = BeautifulSoup(web_news, 'html.parser')
title = source_news.find('h3', {'id' : 'articleTitle'}).get_text()
print('Processing article : {}'.format(title))
date = source_news.find('span', {'class' : 't11'}).get_text()
article = source_news.find('div', {'id' : 'articleBodyContents'}).get_text()
article = article.replace("\n", "")
article = article.replace("// flash 오류를 우회하기 위한 함수 추가function _flash_removeCallback() {}", "")
article = article.replace("동영상 뉴스 ", "")
article = article.replace("동영상 뉴스", "")
article = article.strip()
press_company = source_news.find('address', {'class' : 'address_cp'}).find('a').get_text()
titles.append(title)
dates.append(date)
articles.append(article)
press_companies.append(press_company)
article_urls.append(url)
except:
print('\n*** {}번부터 {}번까지의 기사글을 크롤링하는 중 문제가 발생했습니다.'.format(current_call, current_call+9))
print('*** 다음 링크의 뉴스를 크롤링하는 중 에러가 발생했습니다 : {}'.format(url))
else:
pass
time.sleep(5)
current_call += 10
article_df = pd.DataFrame({'Title':titles,
'Date':dates,
'Article':articles,
'URL':article_urls,
'PressCompany':press_companies})
article_df.to_excel('result_{}.xlsx'.format(datetime.now().strftime('%y%m%d_%H%M')), index=False, encoding='utf-8')
print('\n크롤링이 성공적으로 완료되었습니다!')
print('\n크롤링 결과를 다음 파일에 저장하였습니다 : {}'.format(datetime.now().strftime('%y%m%d_%H%M')))
query = input('검색어를 입력해주세요. (ex. 데이터 분석) : ')
start_date = input('검색 시작 날짜를 입력해주세요. (형식 : 2021.01.01) : ')
end_date = input('검색 종료 날짜를 입력해주세요. (형식 : 2021.12.31) : ')
sort_type = input('정렬 타입을 입력해주세요 (관련도순 = 0, 최신순 = 1, 오래된순 = 2) : ')
max_page = input('크롤링을 원하는 전체 페이지 수를 입력해주세요. (ex. 5) : ')
if start_date > end_date:
print('\n시작 날짜는 종료 날짜보다 이후로 지정하실 수 없습니다. 다시 실행해주세요!')
elif max_page == '':
max_page = 5
print('\n원하시는 페이지 수가 입력되지 않았습니다. 5 페이지까지만 크롤링을 진행합니다.')
main_crawling(query, start_date, end_date, sort_type, max_page)
else:
max_page = int(max_page)
main_crawling(query, start_date, end_date, sort_type, max_page)
'멋쟁이 사자처럼 AI SCHOOL 5기 > Today I Learned' 카테고리의 다른 글
[3주차 총정리] Selenium으로 브라우저 제어 자동화하기 (0) | 2022.03.29 |
---|---|
[3주차 총정리] Okt 텍스트 분석 후에 Word Cloud 제작하기 (0) | 2022.03.29 |
[2주차 총정리] Web Scrapping (네이버 단일 뉴스 기사) (0) | 2022.03.26 |
[2주차 총정리] 자연어처리(NLP) _ 2. Text Similarity Analysis (TF-IDF, Cosine Similarity 이론 및 실습) (0) | 2022.03.26 |
[2주차 총정리] 자연어처리(NLP) _ 1. Preprocessing Text Data & Text Data Exploration (0) | 2022.03.25 |