def crawling_article(self, content_url, date, category): try: # 기사 HTML 가져옴 self.webdriver.get(content_url) html = self.webdriver.page_source document_content = BeautifulSoup(html, 'lxml') # 기사 제목 가져옴 tag_headline = document_content.find_all('h3', {'id': 'articleTitle'}, {'class': 'tts_head'}) text_headline = '' # 뉴스 기사 제목 초기화 text_headline = text_headline + ArticleParser.clear_headline( str(tag_headline[0].find_all(text=True))) if not text_headline: # 공백일 경우 기사 제외 처리 raise Exception('No text headline') # 기사 본문 가져옴 tag_content = document_content.find_all('div', {'id': 'articleBodyContents'}) text_sentence = '' # 뉴스 기사 본문 초기화 text_sentence = text_sentence + ArticleParser.clear_content(str(tag_content[0].find_all(text=True))) if not text_sentence: # 공백일 경우 기사 제외 처리 raise Exception('No contents') # 기사 언론사 가져옴 tag_company = document_content.find_all('meta', {'property': 'me2:category1'}) text_company = '' # 언론사 초기화 text_company = text_company + str(tag_company[0].get('content')) if not text_company: # 공백일 경우 기사 제외 처리 raise Exception('No press information') article_obj = {} article_obj['url'] = content_url article_obj['press'] = text_company article_obj['date'] = date article_obj['category'] = category article_obj['title'] = text_headline article_obj['contents'] = text_sentence # 댓글 크롤링!! article_obj['comments'] = self.crawling_comments(document_content) return article_obj except Exception as ex: # UnicodeEncodeError .. print(ex) return None
def crawling(self, category_name): # Multi Process PID print(category_name + " PID: " + str(os.getpid())) writer = Writer(category='Article', article_category=category_name, date=self.date) # 기사 url 형식 url_format = f'http://news.naver.com/main/list.nhn?mode=LSD&mid=sec&sid1={self.categories.get(category_name)}&date=' # start_year년 start_month월 ~ end_year의 end_month 날짜까지 기사를 수집합니다. target_urls = self.make_news_page_url(url_format, self.date['start_year'], self.date['end_year'], self.date['start_month'], self.date['end_month']) print(category_name + " Urls are generated") print("The crawler starts") for url in target_urls: request = self.get_url_data(url) document = BeautifulSoup(request.content, 'html.parser') # html - newsflash_body - type06_headline, type06 # 각 페이지에 있는 기사들 가져오기 temp_post = document.select('.newsflash_body .type06_headline li dl') temp_post.extend(document.select('.newsflash_body .type06 li dl')) # 각 페이지에 있는 기사들의 url 저장 post_urls = [] for line in temp_post: # 해당되는 page에서 모든 기사들의 URL을 post_urls 리스트에 넣음 post_urls.append(line.a.get('href')) del temp_post for content_url in post_urls: # 기사 url # 크롤링 대기 시간 sleep(0.01) # 기사 HTML 가져옴 request_content = self.get_url_data(content_url) try: document_content = BeautifulSoup(request_content.content, 'html.parser') except: continue try: # 기사 제목 가져옴 tag_headline = document_content.find_all('h3', {'id': 'articleTitle'}, {'class': 'tts_head'}) # 뉴스 기사 제목 초기화 text_headline = '' text_headline = text_headline + ArticleParser.clear_headline(str(tag_headline[0].find_all(text=True))) # 공백일 경우 기사 제외 처리 if not text_headline: continue # 기사 본문 가져옴 tag_content = document_content.find_all('div', {'id': 'articleBodyContents'}) # 뉴스 기사 본문 초기화 text_sentence = '' text_sentence = text_sentence + ArticleParser.clear_content(str(tag_content[0].find_all(text=True))) # 공백일 경우 기사 제외 처리 if not text_sentence: continue # 기사 언론사 가져옴 tag_company = document_content.find_all('meta', {'property': 'me2:category1'}) # 언론사 초기화 text_company = '' text_company = text_company + str(tag_company[0].get('content')) # 공백일 경우 기사 제외 처리 if not text_company: continue # 기사 시간대 가져옴 time = re.findall('<span class="t11">(.*)</span>',request_content.text)[0] # CSV 작성 writer.write_row([time, category_name, text_company, text_headline, text_sentence, content_url]) del time del text_company, text_sentence, text_headline del tag_company del tag_content, tag_headline del request_content, document_content # UnicodeEncodeError except Exception as ex: del request_content, document_content pass writer.close()
def crawling(self, category_name): # Multi Process PID print(category_name + " PID: " + str(os.getpid())) writer = Writer(category='Article', article_category=category_name, date=self.date) # 기사 url 형식 url_format = f'http://news.naver.com/main/list.nhn?mode=LSD&mid=sec&sid1={self.categories.get(category_name)}&date=' # start_year년 start_month월 ~ end_year의 end_month 날짜까지 기사를 수집합니다. target_urls = self.make_news_page_url(url_format, self.date['start_year'], self.date['end_year'], self.date['start_month'], self.date['end_month']) print(category_name + " Urls are generated") print("The crawler starts") for index, url in enumerate(target_urls): if index % 100 == 0: print(index, ' : ', url, round(index / len(target_urls) * 100, 2), '%') request = self.get_url_data(url) document = BeautifulSoup(request.content, 'html.parser') # html - newsflash_body - type06_headline, type06 # 각 페이지에 있는 기사들 가져오기 temp_post = document.select( '.newsflash_body .type06_headline li dl') temp_post.extend(document.select('.newsflash_body .type06 li dl')) # 각 페이지에 있는 기사들의 url 저장 post_urls = [] for line in temp_post: # 해당되는 page에서 모든 기사들의 URL을 post_urls 리스트에 넣음 post_urls.append(line.a.get('href')) del temp_post for content_url in post_urls: # 기사 url # 크롤링 대기 시간 sleep(0.01) # 기사 HTML 가져옴 request_content = self.get_url_data(content_url) try: document_content = BeautifulSoup(request_content.content, 'html.parser') except: continue try: # 기사 제목 가져옴 tag_headline = document_content.find_all( 'h3', {'id': 'articleTitle'}, {'class': 'tts_head'}) # 뉴스 기사 제목 초기화 text_headline = '' text_headline = text_headline + ArticleParser.clear_headline( str(tag_headline[0].find_all(text=True))) # 공백일 경우 기사 제외 처리 if not text_headline: continue # 기사 본문 가져옴 tag_content = document_content.find_all( 'div', {'id': 'articleBodyContents'}) # 뉴스 기사 본문 초기화 text_sentence = '' text_sentence = text_sentence + ArticleParser.clear_content( str(tag_content[0].find_all(text=True))) # 공백일 경우 기사 제외 처리 if not text_sentence: continue # 기사 언론사 가져옴 tag_company = document_content.find_all( 'meta', {'property': 'me2:category1'}) # 언론사 초기화 text_company = '' text_company = text_company + str( tag_company[0].get('content')) # 공백일 경우 기사 제외 처리 if not text_company: continue # 기사 시간대 가져옴 time_list = re.findall('<span class="t11">(.*)</span>', request_content.text) time = time_list[0] #기사 작성 시간 if len(time_list) >= 2: modify_time = time_list[1] #기사 수정 시간 else: modify_time = '' #2020123추가 #Reaction추가 oid = re.findall('oid=(.*)&', content_url)[0] aid = re.findall('aid=(.*)', content_url)[0] reaction_url = 'https://news.like.naver.com/v1/search/contents?q=NEWS[ne_{}_{}]'.format( oid, aid) #웹에서 동적으로 받아와짐 => 기사의 oid, aid 활용하여 동적접근 reaction_req = requests.get(reaction_url) reaction_html = reaction_req.text reaction_json = json.loads( reaction_html)['contents'][0]['reactions'] reactionCountList = [0, 0, 0, 0, 0] reactList = np.array( ['like', 'warm', 'sad', 'angry', 'want']) for countIndex, reaction in enumerate(reactList): if reaction not in [ i['reactionType'] for i in reaction_json ]: # 값이 없는 리액션은 넘어감 continue reaction_index = [ i['reactionType'] for i in reaction_json ].index(reaction) reactionCountList[countIndex] = reaction_json[ reaction_index]['count'] timestamp = int( str(json.loads(reaction_html)['timestamp'])[:10]) # CSV 작성 writer.write_row([ time, category_name, text_company, text_headline, text_sentence, content_url, modify_time, reactionCountList, timestamp ]) del time, modify_time del text_company, text_sentence, text_headline del tag_company del tag_content, tag_headline del request_content, document_content # UnicodeEncodeError except Exception as ex: del request_content, document_content pass writer.close()
def crawling(self, category_name): # Multi Process PID print(category_name + " PID: " + str(os.getpid())) writer = Writer(category_name=category_name, date=self.date) url = "http://news.naver.com/main/list.nhn?mode=LSD&mid=sec&sid1=" + str( self.categories.get(category_name)) + "&date=" day_urls = self.make_news_page_url(url, self.date['start_year'], self.date['end_year'], self.date['start_month'], self.date['end_month']) print(category_name + " Urls are generated") print("The crawler starts") for URL in day_urls: regex = re.compile("date=(\d+)") news_date = regex.findall(URL)[0] request = self.get_url_data(URL) document = BeautifulSoup(request.content, 'html.parser') post_temp = document.select( '.newsflash_body .type06_headline li dl') post_temp.extend(document.select('.newsflash_body .type06 li dl')) post = [] for line in post_temp: post.append(line.a.get('href')) del post_temp for content_url in post: sleep(0.01) request_content = self.get_url_data(content_url) try: document_content = BeautifulSoup(request_content.content, 'html.parser') except: continue try: tag_headline = document_content.find_all( 'h3', {'id': 'articleTitle'}, {'class': 'tts_head'}) text_headline = '' text_headline = text_headline + ArticleParser.clear_headline( str(tag_headline[0].find_all(text=True))) if not text_headline: continue tag_content = document_content.find_all( 'div', {'id': 'articleBodyContents'}) text_sentence = '' text_sentence = text_sentence + ArticleParser.clear_content( str(tag_content[0].find_all(text=True))) if not text_sentence: continue tag_company = document_content.find_all( 'meta', {'property': 'me2:category1'}) text_company = '' text_company = text_company + str( tag_company[0].get('content')) if not text_company: continue wcsv = writer.get_writer_csv() wcsv.writewor([ news_date, category_name, text_company, text_headline, text_sentence, content_url ]) del text_company, text_sentence, text_headline del tag_company del tag_content, tag_headline del request_content, document_content except Exception as ex: del request_content, document_content pass writer.close()
def crawling(self, category_name): # Multi Process PID print(category_name + " PID: " + str(os.getpid())) writer = Writer(category_name=category_name, date=self.date) # 기사 URL 형식 url = "http://news.naver.com/main/list.nhn?mode=LSD&mid=sec&sid1=" + str( self.categories.get(category_name)) + "&date=" # start_year년 start_month월 ~ end_year의 end_month 날짜까지 기사를 수집합니다. day_urls = self.make_news_page_url(url, self.date['start_year'], self.date['end_year'], self.date['start_month'], self.date['end_month']) print(category_name + " Urls are generated") print("The crawler starts") for URL in day_urls: regex = re.compile("date=(\d+)") news_date = regex.findall(URL)[0] request = self.get_url_data(URL) document = BeautifulSoup(request.content, 'html.parser') # html - newsflash_body - type06_headline, type06 # 각 페이지에 있는 기사들 가져오기 post_temp = document.select( '.newsflash_body .type06_headline li dl') post_temp.extend(document.select('.newsflash_body .type06 li dl')) # 각 페이지에 있는 기사들의 url 저장 post = [] for line in post_temp: post.append(line.a.get( 'href')) # 해당되는 page에서 모든 기사들의 URL을 post 리스트에 넣음 del post_temp for content_url in post: # 기사 URL # 크롤링 대기 시간 sleep(0.01) # 기사 HTML 가져옴 request_content = self.get_url_data(content_url) try: document_content = BeautifulSoup(request_content.content, 'html.parser') except: continue try: # 기사 제목 가져옴 tag_headline = document_content.find_all( 'h3', {'id': 'articleTitle'}, {'class': 'tts_head'}) text_headline = '' # 뉴스 기사 제목 초기화 text_headline = text_headline + ArticleParser.clear_headline( str(tag_headline[0].find_all(text=True))) if not text_headline: # 공백일 경우 기사 제외 처리 continue # 기사 본문 가져옴 tag_content = document_content.find_all( 'div', {'id': 'articleBodyContents'}) text_sentence = '' # 뉴스 기사 본문 초기화 text_sentence = text_sentence + ArticleParser.clear_content( str(tag_content[0].find_all(text=True))) if not text_sentence: # 공백일 경우 기사 제외 처리 continue # 기사 언론사 가져옴 #tag_company = document_content.find_all('meta', {'property': 'me2:category1'}) #text_company = '' # 언론사 초기화 #text_company = text_company + str(tag_company[0].get('content')) #if not text_company: # 공백일 경우 기사 제외 처리 # continue # CSV 작성 wcsv = writer.get_writer_csv() wcsv.writerow([text_headline, text_sentence]) del text_company, text_sentence, text_headline del tag_company del tag_content, tag_headline del request_content, document_content except Exception as ex: # UnicodeEncodeError .. # wcsv.writerow([ex, content_url]) del request_content, document_content pass writer.close()
class ArticleCrawler(object): def __init__(self): self.parser = ArticleParser() self.categories = {'정치': 100, '경제': 101, '사회': 102, '생활문화': 103, 'IT과학': 105, 'politics': 100, 'economy': 101, 'society': 102, 'living_culture': 103, 'IT_science': 105} self.selected_categories = [] self.date = {'start_year': 0, 'end_year': 0, 'end_month': 0} def set_category(self, *args): for key in args: if self.categories.get(key) is None: raise InvalidCategory(key) self.selected_categories = args def set_date_range(self, start_year, end_year, end_month): args = [start_year, end_year, end_month] if start_year > end_year: raise InvalidYear(start_year, end_year) if end_month < 1 or end_month > 12: raise InvalidMonth(end_month) for key, date in zip(self.date, args): self.date[key] = date print(self.date) def make_news_page_url(self, category_url, start_year, last_year, start_month, last_month): maked_url = [] final_startmonth = start_month final_lastmonth = last_month for year in range(start_year, last_year + 1): if year != last_year: start_month = 1 last_month = 12 else: start_month = final_startmonth last_month = final_lastmonth for month in range(start_month, last_month + 1): for month_day in range(1, calendar.monthrange(year, month)[1] + 1): url = category_url if len(str(month)) == 1: month = "0" + str(month) if len(str(month_day)) == 1: month_day = "0" + str(month_day) url = url + str(year) + str(month) + str(month_day) final_url = url # page 날짜 정보만 있고 page 정보가 없는 url 임시 저장 # totalpage는 네이버 페이지 구조를 이용해서 page=1000으로 지정해 totalpage를 알아냄 # page=1000을 입력할 경우 페이지가 존재하지 않기 때문에 page=totalpage로 이동 됨 totalpage = self.parser.find_news_totalpage(final_url + "&page=1000") for page in range(1, totalpage + 1): url = final_url # url page 초기화 url = url + "&page=" + str(page) maked_url.append(url) return maked_url def crawling(self, category_name): # MultiThread PID print(category_name + " PID: " + str(os.getpid())) # 각 카테고리 기사 저장 할 CSV file = open('Article_' + category_name + '.csv', 'w', encoding='euc_kr', newline='') wcsv = csv.writer(file) # 기사 URL 형식 url = "http://news.naver.com/main/list.nhn?mode=LSD&mid=sec&sid1=" + str( self.categories.get(category_name)) + "&date=" # start_year년 1월 ~ end_year의 end_mpnth 날짜까지 기사를 수집합니다. final_urlday = self.make_news_page_url(url, self.date['start_year'], self.date['end_year'], 1, self.date['end_month']) print(category_name + " Urls are generated") print("The crawler starts") for URL in final_urlday: regex = re.compile("date=(\d+)") news_date = regex.findall(URL)[0] request = requests.get(URL) document = BeautifulSoup(request.content, 'html.parser') tag_document = document.find_all('dt', {'class': 'photo'}) post = [] for tag in tag_document: post.append(tag.a.get('href')) # 해당되는 page에서 모든 기사들의 URL을 post 리스트에 넣음 for content_url in post: # 기사 URL # 크롤링 대기 시간 sleep(0.01) # 기사 HTML 가져옴 request_content = requests.get(content_url) document_content = BeautifulSoup(request_content.content, 'html.parser') try: # 기사 제목 가져옴 tag_headline = document_content.find_all('h3', {'id': 'articleTitle'}, {'class': 'tts_head'}) text_headline = '' # 뉴스 기사 제목 초기화 text_headline = text_headline + self.parser.clear_headline(str(tag_headline[0].find_all(text=True))) if not text_headline: # 공백일 경우 기사 제외 처리 continue # 기사 본문 가져옴 tag_content = document_content.find_all('div', {'id': 'articleBodyContents'}) text_sentence = '' # 뉴스 기사 본문 초기화 text_sentence = text_sentence + self.parser.clear_content(str(tag_content[0].find_all(text=True))) if not text_sentence: # 공백일 경우 기사 제외 처리 continue # 기사 언론사 가져옴 tag_company = document_content.find_all('meta', {'property': 'me2:category1'}) text_company = '' # 언론사 초기화 text_company = text_company + str(tag_company[0].get('content')) if not text_company: # 공백일 경우 기사 제외 처리 굳. continue # CSV 작성 wcsv.writerow([news_date, category_name, text_company, text_headline, text_sentence, content_url]) except Exception as ex: # UnicodeEncodeError .. pass file.close() def start(self): # MultiProcess 크롤링 시작 for category_name in self.selected_categories: proc = Process(target=self.crawling, args=(category_name,)) proc.start()
def crawling(self, category_name: str = '경제'): """크롤링 시작.""" pid = str(os.getpid()) if self.logger is not None: self.logger.info(f"카테고리:{category_name} | PID: {pid}") writer = Writer(category='Article', article_category=category_name, date=self.date, root=self.write_root) url_format = \ f"http://news.naver.com/main/list.nhn?mode=LSD&mid=sec&" + \ f"sid1={self.categories.get(category_name)}&date=" target_urls = self.make_news_page_url( category_url=url_format, start_year=self.date['start_year'], end_year=self.date['end_year'], start_month=self.date['start_month'], end_month=self.date['end_month']) if self.logger is not None: self.logger.info(f"URLs generated for {category_name}. Start!") # Write headers for csv file writer.write_row(['일시', '카테고리', '언론사', '제목', '본문', 'url']) #for url in tqdm.tqdm(target_urls, desc=category_name, position=0, leave=True): _process = mp.current_process() total = len(target_urls) position = self.selected_categories.index(category_name) with tqdm.tqdm(desc=f"Keyword: {category_name}", total=total, position=position) as pg: for url in target_urls: request = self.get_url_data(url) if request is None: continue document = BeautifulSoup(request.content, 'html.parser') # html - newsflash_body - type06_headline, type06 # 각 페이지에 있는 기사들 가져오기 temp_post = document.select( '.newsflash_body .type06_headline li dl') temp_post.extend( document.select('.newsflash_body .type06 li dl')) # 각 페이지에 있는 기사들의 url 저장 post_urls = [] for line in temp_post: # 해당되는 page에서 모든 기사들의 URL을 post_urls 리스트에 넣음 post_urls.append(line.a.get('href')) del temp_post # 기사 url for content_url in post_urls: # 크롤링 대기 시간 sleep(0.01) # 기사 HTML 가져옴 request_content = self.get_url_data(content_url) if request_content is None: continue try: document_content = BeautifulSoup( request_content.content, 'html.parser') except: continue try: # 기사 제목 가져옴 tag_headline = document_content.find_all( 'h3', {'id': 'articleTitle'}, {'class': 'tts_head'}) # 뉴스 기사 제목 초기화 text_headline = '' text_headline = text_headline + ArticleParser.clear_headline( str(tag_headline[0].find_all(text=True))) # 공백일 경우 기사 제외 처리 if not text_headline: continue # 기사 본문 가져옴 tag_content = document_content.find_all( 'div', {'id': 'articleBodyContents'}) # 뉴스 기사 본문 초기화 text_sentence = '' text_sentence = text_sentence + ArticleParser.clear_content( str(tag_content[0].find_all(text=True))) # 공백일 경우 기사 제외 처리 if not text_sentence: continue # 기사 언론사 가져옴 tag_company = document_content.find_all( 'meta', {'property': 'me2:category1'}) # 언론사 초기화 text_company = '' text_company = text_company + str( tag_company[0].get('content')) # 공백일 경우 기사 제외 처리 if not text_company: continue # 기사 시간대 가져옴 time = re.findall('<span class="t11">(.*)</span>', request_content.text)[0] # CSV 작성 writer.write_row([ time, category_name, text_company, text_headline, text_sentence, content_url ]) del time del text_company, text_sentence, text_headline del tag_company del tag_content, tag_headline del request_content, document_content # UnicodeEncodeError except Exception as ex: del request_content, document_content pass pg.update(1) writer.close()
def crawling(self, category_name): # Multi Process PID print(category_name + " PID: " + str(os.getpid())) writer = Writer(category_name=category_name, date=self.date) # 기사 URL 형식 url = "http://news.naver.com/main/list.nhn?mode=LSD&mid=sec&sid1=" + str( self.categories.get(category_name)) + "&date=" # 설정 기간 동안 crawling day_urls = self.make_news_page_url(url, self.date['start_year'], self.date['end_year'], self.date['start_month'], self.date['end_month'], self.date['start_date'], self.date['end_date']) print(category_name + " Urls are generated") print("The crawler starts") for URL in day_urls: regex = re.compile("date=(\d+)") news_date = regex.findall(URL)[0] request = self.get_url_data(URL) document = BeautifulSoup(request.content, 'html.parser') # 각 페이지에 있는 기사들 가져오기 post_temp = document.select( '.newsflash_body .type06_headline li dl') post_temp.extend(document.select('.newsflash_body .type06 li dl')) # 각 페이지에 있는 기사들의 url 저장 post = [] for line in post_temp: post.append(line.a.get( 'href')) # 해당되는 page에서 모든 기사들의 URL을 post 리스트에 넣음 del post_temp for content_url in post: # 기사 URL # 크롤링 대기 시간 sleep(0.01) # 기사 HTML 가져옴 request_content = self.get_url_data(content_url) try: document_content = BeautifulSoup(request_content.content, 'html.parser') except: continue try: # 기사 제목 가져옴 tag_headline = document_content.find_all( 'h3', {'id': 'articleTitle'}, {'class': 'tts_head'}) text_headline = '' # 뉴스 기사 제목 초기화 text_headline = text_headline + ArticleParser.clear_headline( str(tag_headline[0].find_all(text=True))) #keyword 검사 if not self.keyword in text_headline: continue if not text_headline: # 공백일 경우 기사 제외 처리 continue # 기사 본문 가져옴 tag_content = document_content.find_all( 'div', {'id': 'articleBodyContents'}) text_sentence = '' # 뉴스 기사 본문 초기화 text_sentence = text_sentence + ArticleParser.clear_content( str(tag_content[0].find_all(text=True))) #keyword 검사 if not self.keyword in text_sentence: continue if not text_sentence: # 공백일 경우 기사 제외 처리 continue # 기사 언론사 가져옴 tag_company = document_content.find_all( 'meta', {'property': 'me2:category1'}) text_company = '' # 언론사 초기화 text_company = text_company + str( tag_company[0].get('content')) if not text_company: # 공백일 경우 기사 제외 처리 continue #사진 저장 if (self.captureFlag): browser = webdriver.Chrome( ChromeDriverManager().install()) browser.get(content_url) #element not found error 처리 try: element = browser.find_element_by_class_name( 'end_photo_org') location = element.location y = location.get('y') #사진 padding 처리 (y-60) browser.execute_script("window.scrollTo(%d,%d);" % (0, y - 60)) size = element.size title = text_headline + '.png' #기사 제목으로 사진제목 설정 element.screenshot(title) except Exception as ex: print('Not find element') browser.quit() # CSV 작성 wcsv = writer.get_writer_csv() wcsv.writerow([ news_date, category_name, text_company, text_headline, text_sentence, content_url ]) print('작성완료') del text_company, text_sentence, text_headline del tag_company del tag_content, tag_headline del request_content, document_content except Exception as ex: del request_content, document_content pass writer.close()
MAXCOUNT = 0 for content_url in post: # 기사 URL if MAXCOUNT >= 1: break # 크롤링 대기 시간 sleep(0.01) # 기사 HTML 가져옴 request_content = get_url_data(content_url) try: document_content = BeautifulSoup(request_content.content, 'html.parser') except: continue try: text_sentence = "" tag_content = document_content.find_all( 'div', {'id': 'articleBodyContents'}) text_sentence = text_sentence + ArticleParser.clear_content( str(tag_content[0].find_all(text=True))) if not text_sentence: # 공백일 경우 기사 제외 처리 continue output.write(text_sentence) except Exception as ex: del request_content, document_content pass
class ArticleCrawler(object): def __init__(self): self.parser = ArticleParser() self.categories = {'정치': 100, '경제': 101, '사회': 102, '생활문화': 103, '세계': 104, 'IT과학': 105, '오피니언': 110, 'politics': 100, 'economy': 101, 'society': 102, 'living_culture': 103, 'world': 104, 'IT_science': 105, 'opinion': 110} self.selected_categories = [] self.date = {'start_year': 0, 'start_month': 0, 'end_year': 0, 'end_month': 0} self.user_operating_system = str(platform.system()) def set_category(self, *args): for key in args: if self.categories.get(key) is None: raise InvalidCategory(key) self.selected_categories = args def set_date_range(self, start_year, start_month, end_year, end_month): args = [start_year, start_month, end_year, end_month] if start_year > end_year: raise InvalidYear(start_year, end_year) if start_month < 1 or start_month > 12: raise InvalidMonth(start_month) if end_month < 1 or end_month > 12: raise InvalidMonth(end_month) if start_month > end_month: raise OverbalanceMonth(start_month, end_month) for key, date in zip(self.date, args): self.date[key] = date print(self.date) def make_news_page_url(self, category_url, start_year, end_year, start_month, end_month): made_url = [] for year in range(start_year, end_year + 1): if start_year == end_year: year_startmonth = start_month year_endmonth = end_month else: if year == start_year: year_startmonth = start_month year_endmonth = 12 elif year == end_year: year_startmonth = 1 year_endmonth = end_month else: year_startmonth = 1 year_endmonth = 12 for month in range(year_startmonth, year_endmonth + 1): for month_day in range(1, calendar.monthrange(year, month)[1] + 1): if len(str(month)) == 1: month = "0" + str(month) if len(str(month_day)) == 1: month_day = "0" + str(month_day) # 날짜별로 Page Url 생성 url = category_url + str(year) + str(month) + str(month_day) # totalpage는 네이버 페이지 구조를 이용해서 page=10000으로 지정해 totalpage를 알아냄 # page=10000을 입력할 경우 페이지가 존재하지 않기 때문에 page=totalpage로 이동 됨 (Redirect) totalpage = self.parser.find_news_totalpage(url + "&page=10000") for page in range(1, totalpage + 1): made_url.append(url + "&page=" + str(page)) return made_url def crawling(self, category_name): # Multi Process PID print(category_name + " PID: " + str(os.getpid())) # csv 파일 이름에 들어갈 month 자릿수 맞추기 if len(str(self.date['start_month'])) == 1: save_startmonth = "0" + str(self.date['start_month']) else: save_startmonth = str(self.date['start_month']) if len(str(self.date['end_month'])) == 1: save_endmonth = "0" + str(self.date['end_month']) else: save_endmonth = str(self.date['end_month']) # 각 카테고리 기사 저장 할 CSV # Windows uses euc-kr if self.user_operating_system == "Windows": file = open('Article_' + category_name + '_' + str(self.date['start_year']) + save_startmonth + '_' + str(self.date['end_year']) + save_endmonth + '.csv', 'w', encoding='euc-kr', newline='') # Other OS uses utf-8 else: file = open('Article_' + category_name + '_' + str(self.date['start_year']) + save_startmonth + '_' + str(self.date['end_year']) + save_endmonth + '.csv', 'w', encoding='utf-8', newline='') wcsv = csv.writer(file) del save_startmonth, save_endmonth # 기사 URL 형식 url = "http://news.naver.com/main/list.nhn?mode=LSD&mid=sec&sid1=" + str(self.categories.get(category_name)) + "&date=" # start_year년 start_month월 ~ end_year의 end_month 날짜까지 기사를 수집합니다. final_urlday = self.make_news_page_url(url, self.date['start_year'], self.date['end_year'], self.date['start_month'], self.date['end_month']) print(category_name + " Urls are generated") print("The crawler starts") for URL in final_urlday: regex = re.compile("date=(\d+)") news_date = regex.findall(URL)[0] request = requests.get(URL) document = BeautifulSoup(request.content, 'html.parser') # html - newsflash_body - type06_headline, type06 # 각 페이지에 있는 기사들 가져오기 post_temp = document.select('.newsflash_body .type06_headline li dl') post_temp.extend(document.select('.newsflash_body .type06 li dl')) # 각 페이지에 있는 기사들의 url 저장 post = [] for line in post_temp: post.append(line.a.get('href')) # 해당되는 page에서 모든 기사들의 URL을 post 리스트에 넣음 del post_temp for content_url in post: # 기사 URL # 크롤링 대기 시간 sleep(0.01) # 기사 HTML 가져옴 request_content = requests.get(content_url) document_content = BeautifulSoup(request_content.content, 'html.parser') try: # 기사 제목 가져옴 tag_headline = document_content.find_all('h3', {'id': 'articleTitle'}, {'class': 'tts_head'}) text_headline = '' # 뉴스 기사 제목 초기화 text_headline = text_headline + self.parser.clear_headline(str(tag_headline[0].find_all(text=True))) if not text_headline: # 공백일 경우 기사 제외 처리 continue # 기사 본문 가져옴 tag_content = document_content.find_all('div', {'id': 'articleBodyContents'}) text_sentence = '' # 뉴스 기사 본문 초기화 text_sentence = text_sentence + self.parser.clear_content(str(tag_content[0].find_all(text=True))) if not text_sentence: # 공백일 경우 기사 제외 처리 continue # 기사 언론사 가져옴 tag_company = document_content.find_all('meta', {'property': 'me2:category1'}) text_company = '' # 언론사 초기화 text_company = text_company + str(tag_company[0].get('content')) if not text_company: # 공백일 경우 기사 제외 처리 continue # CSV 작성 wcsv.writerow([news_date, category_name, text_company, text_headline, text_sentence, content_url]) del text_company, text_sentence, text_headline del tag_company del tag_content, tag_headline del request_content, document_content except Exception as ex: # UnicodeEncodeError .. # wcsv.writerow([ex, content_url]) del request_content, document_content pass file.close() def start(self): # MultiProcess 크롤링 시작 for category_name in self.selected_categories: proc = Process(target=self.crawling, args=(category_name,)) proc.start()