일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- 머신러닝
- residuals
- OVB
- 누락편의
- Sharp RD
- 선형대수
- HTML
- 교란변수
- 최소제곱법
- 회귀불연속설계
- 인과 추론
- 인과추론
- 단순선형회귀
- 크롤링
- 예제
- Python
- 통계
- 잔차의 성질
- 사영
- backdoor adjustment
- rct
- Omitted Variable Bias
- causal inference
- simple linear regression
- 네이버 뉴스
- confounder
- Instrumental Variable
- LU분해
- 교란 변수
- least square estimation
- Today
- Total
Always awake,
[2탄] 쉽게 따라하는 네이버 뉴스 크롤링(python) - title, URL 가져오기 본문
"본 포스팅은 네이버 웹 크롤링 실제 python 코드를 작성하는 2탄입니다.
전 단계인 수행계획을 확인하고 싶으신 분들은 아래링크(1탄)을 참고해주세요 :)"
네이버 웹 페이지 구성이 바뀌어 내용, 코드 수정(2021.01.26)
쉽게 따라하는 네이버 뉴스 크롤링(python) - 1탄
데이터 분석을 공부하면서 python의 여러 패키지를 툴로 사용하였고 그 중 데이터 수집 단계에서 사용되는 크롤링에 대해서 알게 되었다. 크롤링(crawling)은 단어 그대로 해석하면 밑바닥까지 긁어
everyday-tech.tistory.com
지난 편에 이어 네이버 뉴스를 크롤링하는 python 코드를 작성하는 포스팅을 합니다.
지난 편은 네이버 뉴스 웹 구성 체계를 확인하여 원하는 정보(뉴스 기사 title, URL)의 위치를 확인하여 크롤링 계획을 수립하였고
본 편에서는 이를 python 코드로 작성하여 실제 수행해보려고 합니다.
서론
이에 앞서 지난 편을 간단히 정리하고 본 편에서 진행할 내용을 정리해봅니다.
<지난 편>
STEP 1. 소스 조사
- 제공 사이트 조사
- 제공 정보 조사
- 확보 가능 정보 확인
STEP 2. 웹 구성 체계 확인
- HTML 구조 확인
- 제공 정보 확인
- 크롤링 가능 여부 확인
- 네이버 뉴스의 기사 URL의 형태 : https://search.naver.com/search.naver?where=news&sm=tab_jum&query=코로나
- 코로나를 키 위드로 검색 시
- 네이버 뉴스 HTML 구성 (뉴스 title, URL을 찾을 시)
<본 편>
STEP 3. 크롤링 진행
- parsing 방안 및 위치 확인
- request 방법 확인
- data 저장 형태 설계
STEP 4. 최종 데이터 생성
- 데이터 저장 형태
- 데이터 저장
이를 바탕으로 실제 수행하는 코드를 작성해보겠습니다
본론
STEP 3. 크롤링 진행
1. 필요 환경 및 패키지 설치
- python 3 버전을 사용하였습니다.
- requests, bs4, re, pandas 패키지를 사용하였습니다.
패키지 명 | 용도 |
requests | 웹페이지 소스 추출(HTML) |
bs4 | HTML 파싱, 필요 태그 및 소스 추출 |
re | 조건부 문자열(정규 표현식), 태그 탐색 시 일반화 조건을 사용하기 위함 |
pandas | 데이터 프레임, 엑셀 변환 |
2. 코드 작성
1. 패키지 importing
import requests
from pandas import DataFrame
from bs4 import BeautifulSoup
import re
from datetime import datetime
import os
2. 현재 시간 저장
- 나중에 output으로 엑셀 저장 시 크롤링한 날짜, 시간을 파일명에 넣기 위해 저장하는 변수입니다.
date = str(datetime.now())
date = date[:date.rfind(':')].replace(' ', '_')
date = date.replace(':','시') + '분'
3. Input 생성
- 검색할 키워드, 추출할 뉴스 기사 수를 저장하는 변수입니다.
- query에서 ' ' 를 '+'로 바꾸어주는 이유는 띄어쓰기 시 URL 조건 절에 '+'로 적용되어 요청 인자가 들어가기 때문입니다.
query = input('검색 키워드를 입력하세요 : ')
query = query.replace(' ', '+')
news_num = int(input('총 필요한 뉴스기사 수를 입력해주세요(숫자만 입력) : '))
4. 요청할 URL 생성 및 요청
- 3번에서 받은 키워드(query)를 URL의 조건절 중 키워드에 해당하는 변수에 대응시켜 요청 URL을 만듭니다.
- 그리고 requests 패키지의 get함수를 이용하여 HTML 코드를 받아옵니다.
- 받은 코드를 bs4의 BeautifulSoup 함수를 이용하여 파싱합니다.
news_url = 'https://search.naver.com/search.naver?where=news&sm=tab_jum&query={}'
req = requests.get(news_url.format(query))
soup = BeautifulSoup(req.text, 'html.parser')
받은 HTML 코드의 일부를 보면 다음과 같습니다.(req.text)
5. 원하는 정보를 담을 변수 생성(딕셔너리)
뉴스 기사 정보를 저장할 딕셔너리를 생성합니다. (key : 번호, value : 뉴스 기사 정보)
- idx : 현재 뉴스의 번호
- cur_page : 네이버 뉴스의 웹 페이지입니다. 추출하려는 기사 수가 현재 페이지에 있는 기사보다 많은 경우 다음 페이지로 넘어가야 하기 때문에 현 페이지 번호를 기억하도록 변수로 설정한 것입니다.
news_dict = {}
idx = 0
cur_page = 1
6. parsing 한 HTML 코드에서 원하는 정보 탐색(뉴스 기사 title, URL)
idx(현재 뉴스 기사 번호)가 news_num(원하는 뉴스 기사 수) 보다 작은 동안 아래 코드를 실행합니다.
- table : 뉴스 바운딩 박스(ul 태그)
- li_list : 뉴스 바운딩 박스 안의 각 뉴스 기사(li 태그)
- area_list : 뉴스 기사 안의 뉴스 제목, 본문이 담긴 태그(div 태그)
- a_list : 각 뉴스기사 내부 title, URL 정보가 담긴 태그(a 태그)
- news_dict : 뉴스 기사를 담는 딕셔너리
- key : 뉴스 기사 번호
- value : 뉴스 기사 title, url을 key로 하는 딕셔너리
- next_page_url : 현재 수집한 뉴스 기사 수가 부족한 경우 다음 페이지로 넘어가야 하므로 다음 페이지에 해당하는 URL을 추출합니다.
- 형식은 div 태그이며 class 속성 값이 "sc_page_inner"입니다.
- 하위에 존재하는 a 태그 내부에 페이지 번호와, URL(href 속성 값) 정보가 있습니다.
- 위에서 언급한 cur_page 변수와 일치하는 페이지 번호의 URL을 가져옵니다.
- 형식은 div 태그이며 class 속성 값이 "sc_page_inner"입니다.
print()
print('크롤링 중...')
while idx < news_num:
### 네이버 뉴스 웹페이지 구성이 바뀌어 태그명, class 속성 값 등을 수정함(20210126) ###
table = soup.find('ul',{'class' : 'list_news'})
li_list = table.find_all('li', {'id': re.compile('sp_nws.*')})
area_list = [li.find('div', {'class' : 'news_area'}) for li in li_list]
a_list = [area.find('a', {'class' : 'news_tit'}) for area in area_list]
for n in a_list[:min(len(a_list), news_num-idx)]:
news_dict[idx] = {'title' : n.get('title'),
'url' : n.get('href') }
idx += 1
cur_page += 1
pages = soup.find('div', {'class' : 'sc_page_inner'})
next_page_url = [p for p in pages.find_all('a') if p.text == str(cur_page)][0].get('href')
req = requests.get('https://search.naver.com/search.naver' + next_page_url)
soup = BeautifulSoup(req.text, 'html.parser')
STEP 4. 최종 데이터 생성
7. 데이터 프레임 변환 및 저장
- 크롤링한 뉴스 정보가 담긴 딕셔너리(news_dict)를 데이터 프레임(news_df)으로 변환합니다.
- 그리고 크롤링한 키워드(query)와 크롤링 날짜(date)를 엑셀 파일 명으로 하여 저장합니다.
- 마지막으로 저장을 완료한 폴더를 띄웁니다.
print('크롤링 완료')
print('데이터프레임 변환')
news_df = DataFrame(news_dict).T
folder_path = os.getcwd()
xlsx_file_name = '네이버뉴스_{}_{}.xlsx'.format(query, date)
news_df.to_excel(xlsx_file_name)
print('엑셀 저장 완료 | 경로 : {}\\{}'.format(folder_path, xlsx_file_name))
os.startfile(folder_path)
8. 결과물
결과물은 다음과 같습니다.(query : 코로나 강아지 산책, news_num : 17)
전체 코드
import requests
from pandas import DataFrame
from bs4 import BeautifulSoup
import re
from datetime import datetime
import os
date = str(datetime.now())
date = date[:date.rfind(':')].replace(' ', '_')
date = date.replace(':','시') + '분'
query = input('검색 키워드를 입력하세요 : ')
news_num = int(input('총 필요한 뉴스기사 수를 입력해주세요(숫자만 입력) : '))
query = query.replace(' ', '+')
news_url = 'https://search.naver.com/search.naver?where=news&sm=tab_jum&query={}'
req = requests.get(news_url.format(query))
soup = BeautifulSoup(req.text, 'html.parser')
news_dict = {}
idx = 0
cur_page = 1
print()
print('크롤링 중...')
while idx < news_num:
### 네이버 뉴스 웹페이지 구성이 바뀌어 태그명, class 속성 값 등을 수정함(20210126) ###
table = soup.find('ul',{'class' : 'list_news'})
li_list = table.find_all('li', {'id': re.compile('sp_nws.*')})
area_list = [li.find('div', {'class' : 'news_area'}) for li in li_list]
a_list = [area.find('a', {'class' : 'news_tit'}) for area in area_list]
for n in a_list[:min(len(a_list), news_num-idx)]:
news_dict[idx] = {'title' : n.get('title'),
'url' : n.get('href') }
idx += 1
cur_page += 1
pages = soup.find('div', {'class' : 'sc_page_inner'})
next_page_url = [p for p in pages.find_all('a') if p.text == str(cur_page)][0].get('href')
req = requests.get('https://search.naver.com/search.naver' + next_page_url)
soup = BeautifulSoup(req.text, 'html.parser')
print('크롤링 완료')
print('데이터프레임 변환')
news_df = DataFrame(news_dict).T
folder_path = os.getcwd()
xlsx_file_name = '네이버뉴스_{}_{}.xlsx'.format(query, date)
news_df.to_excel(xlsx_file_name)
print('엑셀 저장 완료 | 경로 : {}\\{}'.format(folder_path, xlsx_file_name))
os.startfile(folder_path)
아쉬운 점
뉴스 본문까지 크롤링 가능하였다면 더 좋았을 것 같습니다.
추출한 뉴스 기사 URL로 다시 requests 요청을 보내고 받은 HTML 코드 내부에 기사 본문이 있기 때문에 현재 기술로는 충분히 가능합니다.
하지만, 각 언론사마다 웹페이지 구성이 다르기 때문에 본문의 정보를 담고 있는 태그의 위치와 이름 등이 상이하여 모든 언론사의 뉴스 본문 크롤링을 하기에는 더 많은 조사가 필요합니다.
만약 일부 언론사( ex. 매일 경제, 동아 일보, 중앙일보 )만 크롤링한다면
- 각 언론사 웹페이지 구성을 파악하고
- 본문의 위치를 확인한 후에
- 뉴스 크롤링 시 해당 언론사 URL만 남기고 본문 크롤링을 진행하면 될 것입니다.
마치며
최대한 이해가 쉽도록 주저리주저리 설명했는데.. 지루하게 느끼신 분들도 있을 것 같습니다.
긴 글 읽어주셔서 감사합니다.
피드백은 언제나 환영입니다~
▼ 글이 도움이 되셨다면 아래 클릭 한번 부탁드립니다 :) ▼
'코딩' 카테고리의 다른 글
수치 미분을 해보자 (0) | 2023.09.23 |
---|---|
[3탄] 쉽게 따라하는 네이버 뉴스 크롤링 - 본문 가져오기 (50) | 2020.09.07 |
[아래한글 자동화] 보안승인모듈 등록 (3) | 2020.09.02 |
[1탄] 쉽게 따라하는 네이버 뉴스 크롤링(python) - 계획 짜기 (2) | 2020.08.30 |