네이버 뉴스 크롤링
네이버 검색창에 컴퓨터를 검색하고 카테고리를 뉴스로 설정했다.
크롤링 할 때는 첫 번째 기사처럼 네이버뉴스 버튼이 있는 기사를 가져오고 싶다. (웹 페이지의 구조를 동일하게 맞추기 위해)
html을 분석해보니 네이버뉴스 버튼이 있는 기사들은 info 태그를 두 개씩 가지고 있다.
이 부분에 집중해 코드를 작성하자.
import requests
from bs4 import BeautifulSoup
import time
response = requests.get("https://search.naver.com/search.naver?where=news&sm=tab_jum&query=%EC%BB%B4%ED%93%A8%ED%84%B0")
html = response.text
soup = BeautifulSoup(html, 'html.parser')
articles = soup.select('div.info_group')
for article in articles:
links = article.select("a.info")
if len(links) >= 2:
url = links[1].attrs['href']
response = requests.get(url, headers={'User-agent':'Mozila/5.0'})
html = response.text
soup = BeautifulSoup(html, 'html.parser')
content = soup.select_one("#dic_area")
print(content.text)
time.sleep(0.3)
지금까지 내용을 코드로 나타내면 위와 같다.
headers={} 파라미터는 크롤링 시 봇 검사를 피하기 위해 사용됐고, time.sleep()은 크롤링 대상 서버에게 부담을 덜어주기 위해 사용됐다.
뉴스 정보를 제공하는 사이트별로 html이 다를 수 있으니, 리다이렉션과 css태그를 잘 고려해 오류 없는 프로그램을 작성하자.
네이버 뉴스에도 일반 뉴스 / 연예 뉴스 / 스포츠 뉴스 이렇게 세 가지로 분류되는데, 뉴스별로 제공하는 html구조가 다른 경우 이에 따른 처리를 해 줘야 한다.
html에서 특정 요소를 지우고 싶으면 find 메서드로 해당 요소를 가져오고 decompose 메서드를 사용하자.
페이징 작업은 쿼리에 start 옵션을 추가해서 처리한다.
import requests
from bs4 import BeautifulSoup
import time
import pyautogui
# user input
keyword = pyautogui.prompt("검색어를 입력하세요")
lastpage = int(pyautogui.prompt("몇 페이지까지 가져올까요?"))
page_num = 1
for i in range(1, lastpage * 10, 10):
print(f"{page_num} 번째 페이지를 가져오고 있습니다.")
response = requests.get(f"https://search.naver.com/search.naver?where=news&sm=tab_jum&query={keyword}&start={i}")
html = response.text
soup = BeautifulSoup(html, 'html.parser')
articles = soup.select('div.info_group')
for article in articles:
links = article.select("a.info")
if len(links) >= 2:
url = links[1].attrs['href']
response = requests.get(url, headers={'User-agent':'Mozila/5.0'})
html = response.text
soup = BeautifulSoup(html, 'html.parser')
content = soup.select_one("#dic_area")
print(content.text)
time.sleep(0.3)
page_num += 1
여기서 f-string을 사용하면 {} 를 통해 문자열을 좀 더 편하게 다룰 수 있다.
10씩 증가해야 하고, 사용자가 입력한 페이지만큼 가져오도록 설계하자.
크롤링으로 가져온 결과를 워드 문서에 저장해보자.
import requests
from bs4 import BeautifulSoup
import time
import pyautogui
from docx import Document
# user input
keyword = pyautogui.prompt("검색어를 입력하세요")
lastpage = int(pyautogui.prompt("몇 페이지까지 가져올까요?"))
# word document create
document = Document()
page_num = 1
for i in range(1, lastpage * 10, 10):
print(f"{page_num} 번째 페이지를 가져오고 있습니다.")
response = requests.get(f"https://search.naver.com/search.naver?where=news&sm=tab_jum&query={keyword}&start={i}")
html = response.text
soup = BeautifulSoup(html, 'html.parser')
articles = soup.select('div.info_group')
for article in articles:
links = article.select("a.info")
if len(links) >= 2:
url = links[1].attrs['href']
response = requests.get(url, headers={'User-agent':'Mozila/5.0'})
html = response.text
soup = BeautifulSoup(html, 'html.parser')
if "entertain" in response.url:
title = soup.select_one(".end_tit")
content = soup.select_one("#articeBody")
elif "sports" in response.url:
title = soup.select_one("h4.title")
content = soup.select_one("#newsEndContents")
# delete unnecessary tag
divs = content.select("div")
for div in divs:
div.decompose()
paragraphs = content.select("p")
for paragraph in paragraphs:
paragraph.decompose()
else:
title = soup.select_one("h2.media_end_head_headline")
content = soup.select_one("#dic_area")
print("----link----\n", url)
print("----title----\n", title.text.strip())
print("----paragraph----\n", content.text.strip())
document.add_heading(title.text.strip(), level = 0)
document.add_paragraph(url)
document.add_paragraph(content.text.strip())
time.sleep(0.3)
page_num += 1
document.save(f"{keyword}_result.docx")
우선, 연예 기사와 스포츠 기사를 따로 처리해줬다.
자바에서라면 title과 content를 if문 바깥에서 선언해 준 후 사용해야되지만, 파이썬에서는 if문 안쪽에 변수를 선언해도 알아서 할당된다.
Document 라이브러리를 가져오고, 라이브러리의 메서드를 사용해서 처리한다.
코드가 직관적이라서 쉽게 이해할 수 있다.
결과를 엑셀에 저장하는 경우도 비슷하다.
필요한 라이브러리를 가져오고 메서드를 적절하게 사용해주면 된다.
메서드가 어떤 로직으로 동작하는지 깊게 이해하려 하지 말고, 활용에 초점을 맞춰 공부하자.
import requests
from bs4 import BeautifulSoup
import time
import pyautogui
from docx import Document
from openpyxl import Workbook
from openpyxl.styles import Alignment
# user input
keyword = pyautogui.prompt("검색어를 입력하세요")
lastpage = int(pyautogui.prompt("몇 페이지까지 가져올까요?"))
# word document create
document = Document()
# create excel
wb = Workbook()
ws = wb.create_sheet(keyword)
# row width control
ws.column_dimensions['A'].width = 60
ws.column_dimensions['B'].width = 60
ws.column_dimensions['C'].width = 60
page_num = 1
row = 1
for i in range(1, lastpage * 10, 10):
print(f"{page_num} 번째 페이지를 가져오고 있습니다.")
response = requests.get(f"https://search.naver.com/search.naver?where=news&sm=tab_jum&query={keyword}&start={i}")
html = response.text
soup = BeautifulSoup(html, 'html.parser')
articles = soup.select('div.info_group')
for article in articles:
links = article.select("a.info")
if len(links) >= 2:
url = links[1].attrs['href']
response = requests.get(url, headers={'User-agent':'Mozila/5.0'})
html = response.text
soup = BeautifulSoup(html, 'html.parser')
if "entertain" in response.url:
title = soup.select_one(".end_tit")
content = soup.select_one("#articeBody")
elif "sports" in response.url:
title = soup.select_one("h4.title")
content = soup.select_one("#newsEndContents")
# delete unnecessary tag
divs = content.select("div")
for div in divs:
div.decompose()
paragraphs = content.select("p")
for paragraph in paragraphs:
paragraph.decompose()
else:
title = soup.select_one("h2.media_end_head_headline")
content = soup.select_one("#dic_area")
print("----link----\n", url)
print("----title----\n", title.text.strip())
print("----paragraph----\n", content.text.strip())
document.add_heading(title.text.strip(), level = 0)
document.add_paragraph(url)
document.add_paragraph(content.text.strip())
ws[f'A{row}'] = url
ws[f'B{row}'] = title.text.strip()
ws[f'C{row}'] = content.text.strip()
# line control
ws[f'C{row}'].alignment = Alignment(wrap_text=True)
time.sleep(0.3)
row += 1
page_num += 1
document.save(f"{keyword}_result.docx")
wb.save(f'{keyword}_result.xlsx')
뉴스 정보를 가져올 때 마지막 페이지를 확인해보자.
페이징 처리 부분에서 > 버튼의 속성을 통해 마지막 페이지임을 확인할 수 있다.
해당 버튼의 aria-disabled 속성이 true이면 마지막 페이지이고, false이면 마지막 페이지가 아니다.
가져온 뉴스 기사들의 본문을 모아서 워드클라우드(worditout)를 만들어 사용하는 등 여러 가지 방법으로 데이터를 활용해보자.
'Web > Web Scraping' 카테고리의 다른 글
크롤링에서 POST 요청이 필요한 경우 (0) | 2022.09.24 |
---|---|
네이버 금융 크롤링 (1) | 2022.09.24 |
이미지 크롤링 (2) | 2022.09.21 |
쿠팡 상품 크롤링 (0) | 2022.09.20 |
HTTP 통신과 라이브러리 (0) | 2022.04.05 |
댓글
이 글 공유하기
다른 글
-
네이버 금융 크롤링
네이버 금융 크롤링
2022.09.24 -
이미지 크롤링
이미지 크롤링
2022.09.21 -
쿠팡 상품 크롤링
쿠팡 상품 크롤링
2022.09.20 -
HTTP 통신과 라이브러리
HTTP 통신과 라이브러리
2022.04.05