コード例 #1
0
    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
コード例 #2
0
ファイル: articlecrawler.py プロジェクト: jinsu-Jang/AIStock
    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()
コード例 #3
0
    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()
コード例 #4
0
    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()
コード例 #5
0
    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()
コード例 #6
0
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()
コード例 #7
0
    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()
コード例 #8
0
    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()
コード例 #9
0
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()