※ 웹사이트의 규칙(robots.txt 파일)이나 법적 규제에 따라 크롤링이 제한될 수 있으므로 이를 준수해야 한다.
import requests # html, css 이런 것들을 가져오는 것
from bs4 import BeautifulSoup # 원하는 것들을 빼오는 것
site = 'https://basicenglishspeaking.com/daily-english-conversation-topics/'
request = requests.get(site) # 200 : 정상적인 접속. 4XX : 페이지 없음.
print(request) # 200 : 정상적인 접속
<Response [200]>
print(request.text)
soup = BeautifulSoup(request.text, "html.parser")
box_div = soup.find('div', {'class':'thrv-columns'}) # find : box 하나만 찾는 것. find_all : list로 여러개 찾는 것.
box_div
links = divs.find_all('a')
print(links)
for link in links:
print(link.text) # 영어 단어들이 출력됨.
subject = []
for link in links:
subject.append(link.text)
print(subject) # 리스트 형태로 영어 단어들이 출력됨.
print(len(subject)) # 리스트의 길이(영어 단어 갯수 : 75) 출력.
print(f'총 {len (subject)}개의 주제를 찾았습니다')
for i in range(len(subject)):
print(f'{i+1},{subject[i]}')
# 총 75개의 주제를 찾았습니다. 라는 문구 출력 이후, 1, Family 2,Restaurant ... 형태로 출력됨.
#https://v.daum.net/v/news_id1
#https://v.daum.net/v/news_id2
#https://v.daum.net/v/news_id3
def daum_news_title(news_id):
url = f'https://v.daum.net/v/{news_id}'
# 사이트 접속
request = requests.get(url)
# soup 객체 생성
soup = BeautifulSoup(request.text)
# 뉴스제목을 저장
title = soup.find('h3',{'class': 'tit_view'})
if title:
return title.text.strip()
return '제목없음'
daum_news_title('news_id1') # news_id1의 뉴스 제목 출력
daum_news_title('news_id2') # news_id2의 뉴스 제목 출력
daum_news_title('news_id3') # news_id3의 뉴스 제목 출력
request = requests.get('https://music.bugs.co.kr/chart')
print(request)
<Response [200]>
soup = BeautifulSoup(request.text, 'html.parser')
titles = soup.find_all('p',{'class':'title'})
print(titles)
artists = soup.find_all('p',{'class':'artist'})
print(artists)
# 데이터만큼 반복하면서 아래와 같이 출력
# 1. 제목 - 가수
# 2. 제목 - 가수
for i, (t, a) in enumerate(zip(titles, artists),1):
title = t.text.strip()
artist = a.text.strip().split('\n')[0]
print(f'{i}.{title} - {artist}')
# 출력 결과
# 1.Whiplash - aespa
# 2.APT. - 로제(ROSÉ)
# 3.Mantra - 제니 (JENNIE) ... 이런 식으로 출력.
request = requests.get('https://www.melon.com/chart/index.htm')
request
<Response [406]>
🤔❓<Response [406]>
HTTP 상태 코드 중 하나로, "Not Acceptable"을 의미한다.
클라이언트가 서버에서 응답 가능한 형식을 지정하지 않았거나, 서버가 요청을 차단한 경우에 발생할 수 있다.
Melon 사이트가 406 응답을 보내는 이유?
Melon은 보통 봇이나 자동화된 스크래핑 요청을 차단하려고 여러 보호 장치를 두는데, 그중 하나가 User-Agent 검사이다.
requests.get()은 기본적으로 다음과 같은 헤더로 요청을 보낸다:User-Agent: python-requests/2.31.0이걸 보고 Melon 서버는 브라우저가 아니라고 판단해서 406 오류를 보내는 것!
👌❕해결 방법: headers에 User-Agent 추가하기
# Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'}
request = requests.get('https://www.melon.com/chart/index.htm', headers=headers)
request
<Response [200]>
User-Agent는 F12키(개발자 도구) → Network → F5키(새로고침) 하면 찾을 수 있다.
soup = BeautifulSoup(request.text, 'html.parser')
titles = soup.find_all('div',{'class':'rank01'})
# print(titles)
artists = soup.find_all('span',{'class':'checkEllipsis'})
# print(artists)
for i, (t, a) in enumerate(zip(titles, artists), 1):
title = t.text.strip()
artist = a.text.strip()
print(f'{i}. {title} - {artist}')
site = 'https://finance.naver.com/item/main.naver?code=003490'
request = requests.get(site)
request
<Response [200]>
with open('snapshot_2025_07-15.html', 'w', encoding='utf-8') as f:
f.write(request.text)
soup = BeautifulSoup(request.text, 'html.parser')
div_totalinfo = soup.find('div', {'class':'new_totalinfo'})
div_totalinfo
name = div_totalinfo.find('h2').text
name # 이름 출력
div_today = div_totalinfo.find('div', {'class':'today'})
# div_today
price = div_today.find('span', {'class':'blind'}).text
# price
price = int(price.replace(",",""))
price # 가격 출력
table_no_info = soup.find('table', {'class':'no_info'})
# table_no_info
tds = table_no_info.find_all('td')
# tds
volume = tds[2].find('span', {'class':'blind'}).text
volume = int(volume.replace(",",""))
volume # 거래량 출력
dic = {"name":name, "code":"003490", "price":price, "volume":volume}
dic # 딕셔너리 형태로 출력
이제 각 code에 따른 이름, 가격...등 을 출력하도록 해보자.
def naver_finance(code):
site = f'https://finance.naver.com/item/main.naver?code={code}'
request = requests.get(site)
soup = BeautifulSoup(request.text, 'html.parser')
div_totalinfo = soup.find('div', {'class':'new_totalinfo'})
name = div_totalinfo.find('h2').text
div_today = div_totalinfo.find('div', {'class':'today'})
price = div_today.find('span', {'class':'blind'}).text
price = int(price.replace(",",""))
table_no_info = soup.find('table', {'class':'no_info'})
tds = table_no_info.find_all('td')
volume = tds[2].find('span', {'class':'blind'}).text
volume = int(volume.replace(",",""))
dic = {"name":name, "code":code, "price":price, "volume":volume}
return dic
naver_finance('003490')
# code에 맞는 이름, 코드, 가격, 거래량이 딕셔너리 형태로 출력됨.
naver_finance('000660')