상세 컨텐츠

본문 제목

[K-DIGITAL] 파이썬 웹 크롤링 - 뉴스 기사 스크랩(2)

PYTHON/K-DIGITAL

by ranlan 2021. 6. 23. 13:24

본문

728x90

멋쟁이사자처럼 X K-DIGITAL Training - 06.11

 

 

[이전] 2021.06.23 - [python/k-digital] - [K-DIGITAL] 파이썬 웹 크롤링 - 뉴스 기사 스크랩

 

[K-DIGITAL] 파이썬 웹 크롤링 - 뉴스 기사 스크랩

멋쟁이사자처럼 X K-DIGITAL Training - 06.11 웹 스크랩핑 vs 웹 크롤링 웹 스크랩핑 (scraping) 웹 사이트 상에서 원하는 정보를 추출하는 기술 특정 웹 사이트 또는 페이지에서 특정 정보 검색 웹 크롤링

juran-devblog.tistory.com


 

이전 글에서는 '뉴시스' 언론사 기준으로 여러 기사 본문 스크랩핑을 진행하였다.

텍스트데이터 분석에 쓰기에 데이터 양도 부족할 뿐더러 몇 개의 뉴스에서는 본문이 제대로 스크랩되지 않아

수업시간에 배운대로 네이버 뉴스 기반으로 쓰기로 하였다.

내 나름대로 기사 본문 전처리를 한다고 하긴 하였는데 기사에 담긴 사진, 기자마다 기사를 시작하는 방식, 마지막에 본인의 이메일과 이름을 적는 방식이 조금씩 달라서(혹은 언론사가 달라서) 완벽하게 본문만 추출되지는 않았다😥

그래도 이전 스크랩보다는 훨씬 깔끔하여 이 방식으로 기사를 스크랩하고 텍스트 데이터 분석을 하기로 하였다.

 

 

 

단일 기사 본문 스크랩

* 네이버뉴스(연예란) 기준

 

[이전] 네이버 뉴스 탭에 검색

query = '배우 박정민'
url = "https://search.naver.com/search.naver?where=news&query=" + query

web = requests.get(url).content
source = BeautifulSoup(web, 'html.parser')

네이버 연예 뉴스 get 요청

url = 'https://entertain.naver.com/read?oid=018&aid=0004963324'
    
web = requests.get(url).content 
source = BeautifulSoup(web, 'html.parser')

뉴스 제목

source.find('h2').get_text().strip()

>> '배우 이제훈, 매니지먼트 컴퍼니온 설립 [공식]'

 

뉴스 본문

article = source.find('div', {'id': 'articeBody'}).get_text().strip()

 

- 이메일부터 마지막까지 삭제

pattern = re.compile(r'[\s\Wa-zA-Z0-9]*@') 
email_address = pattern.search(article)

# 삭제할 부분
article[email_address.start()+1:]

# 삭제
article = article[:email_address.start()+1]

* 기자마다 이름과 이메일 작성 방식이 달라 이메일만 삭제하도록 결정😅

'처음 ~ 기자] ' 삭제

del_index = article.find('기자]')

# 삭제할 부분
article[:del_index+3] # 이제훈[이데일리 스타in 김가영 기자]
article = article[del_index+3:]

- 발행 시간

source.find('span', {'class': 'author'}).find('em').get_text()

>> 2021.06.21. 오전 9:17

 

- 발행사

source.find('img')['alt']

>> 이데일리

 

 

 

여러 뉴스 기사 모으기

* 네이버뉴스 링크가 있는 '네이버뉴스' div를 통해 url 스크랩

네이버뉴스 url 스크랩

urls_list = []
for info in source.find_all('div', {'class': 'info_group'}):
    for item in info.find_all('a', {'class': 'info'}):
        if item.get_text() == '네이버뉴스':
            urls_list.append(item['href'])
            
urls_list

각 뉴스마다 본문 스크랩

for url in urls_list:
    if url.startswith('https://news.naver.com'):
        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'}
            content = requests.get(url, headers=headers).content
            source = BeautifulSoup(content, 'html.parser')

            # 기사제목
            title = source.find('h2').get_text().strip()

            # 기사날짜
            date = source.find('span', {'class': 'author'}).find('em').get_text()

            # 기사본문
            article = source.find('div', {'id': 'articeBody'}).get_text().strip()
            pattern = re.compile(r'[\s\Wa-zA-Z0-9]*@') 
            email_address = pattern.search(article)
            article = article[:email_address.start()+1]
            del_index = article.find('기자]')
            article = article[del_index+3:]

            # 언론사
            press_company = source.find('img')['alt']
            
            titles.append(title)
            dates.append(date)
            articles.append(article)
            press_companies.append(press_company)
            urls.append(url)
            print('Title: {}'.format(url))
            
        except:
            print('*** error occurred at {} ***'.format(url))
    else:
        print('** (네이버뉴스x) Title: {}'.format(url))

데이터프레임 생성

df_article = pd.DataFrame({'Title': titles, 'Date': dates, 'Article': articles, 'URL': url, 'Press Company': press_companies})

 

 

 

메서드화

뉴스 본문 스크랩

def scraping_news(url, titles, dates, articles, press_companies, urls):
    if url.startswith('https://news.naver.com'):
        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'}
            content = requests.get(url, headers=headers).content
            source = BeautifulSoup(content, 'html.parser')

            # 기사제목
            title = source.find('h2').get_text().strip()

            # 기사날짜
            date = source.find('span', {'class': 'author'}).find('em').get_text()

            # 기사본문
            article = source.find('div', {'id': 'articeBody'}).get_text().strip()
            pattern = re.compile(r'[\s\Wa-zA-Z0-9]*@') 
            email_address = pattern.search(article)
            article = article[:email_address.start()+1]
            del_index = article.find('기자]')
            article = article[del_index+3:]

            # 언론사
            press_company = source.find('img')['alt']
            
            titles.append(title)
            dates.append(date)
            articles.append(article)
            press_companies.append(press_company)
            urls.append(url)
            print('Title: {}'.format(url))
            
        except:
            print('*** error occurred at {} ***'.format(url))
    else:
        print('** (네이버뉴스x) Title: {}'.format(url))

데이터프레임 생성

def make_dateframe(titles, dates, articles, urls, presscompanies):
    return pd.DataFrame({'Title':titles, 
                           'Date':dates, 
                           'Article':articles, 
                           'URL':urls, 
                           'PressCompany':presscompanies})

 

 

 

여러 페이지에 걸쳐 크롤링하기

query = (input('검색할 단어를 입력하세요: '))
max_page = (input('검색할 총 페이지수를 입력하세요: '))

current = 1
last = (int(max_page)-1) * 10 + 1
base_url = 'https://search.naver.com/search.naver?where=news&query='


titles = []
dates = []
articles = []
press_companies = []
urls = []
while current <= last:
    print('\n{}번째 페이지'.format((current//10) + 1))
    print('{}번째 기사글부터 크롤링을 시작합니다.'.format(current))
    
    # 페이지 이동
    url = base_url + query + '&start=' + str(current)
    web = requests.get(url).content
    source = BeautifulSoup(web, 'html.parser')
    
    # 각 페이지 url에서 기사 url 스크랩
    urls_list = []
    for info in source.find_all('div', {'class': 'info_group'}):
        for item in info.find_all('a', {'class': 'info'}):
            if item.get_text() == '네이버뉴스':
                urls_list.append(item['href'])
        
    # 각 url에 접속하여 기사 본문 스크랩    
    for url in urls_list:
        scraping_news(url, titles, dates, articles, press_companies, urls)

    # 접속 차단 방지를 위해 몇초간 sleep
    time.sleep(5)
    current += 10

# 데이터프레임 생성
df_news = make_dateframe(titles, dates, articles, urls, press_companies)

 

데이터프레임

df_news

엑셀 파일로 저장

df_news.to_excel('result_{}.xlsx'.format(datetime.now().strftime('%y%m%d_%H%M')), index=False, encoding='utf-8')

728x90

관련글 더보기

댓글 영역