크롤링

현서·2025년 2월 3일

파이썬 웹서비스

목록 보기
1/7
post-thumbnail

1. 크롤링(Crawling)

  • 웹사이트에서 데이터를 자동으로 수집하는 과정이다.
  • 웹 크롤러라는 프로그램이 특정 웹 페이지를 방문해 그 안의 HTML 코드를 읽고 필요한 정보를 추출한다.
  • 웹 페이지를 탐색하면서 링크를 따라가며 반복되며, 검색 엔진이 정보를 수집하거나 데이터 분석 목적으로 사용된다.
    ex) 뉴스 사이트의 제목과 본문을 수집해 정보를 분석하는 데 활용.

※ 웹사이트의 규칙(robots.txt 파일)이나 법적 규제에 따라 크롤링이 제한될 수 있으므로 이를 준수해야 한다.

스크레이핑(Scraping) : 크롤링 + 데이터를 추출하고 가공하는 행위


2. Basic English Speaking

Basic English Speaking

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 ... 형태로 출력됨.

3. 다음 뉴스기사 제목 크롤링

#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의 뉴스 제목 출력

4. 벅스뮤직 차트

벅스뮤직 차트

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) ... 이런 식으로 출력.

5. 멜론 차트

멜론 차트

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}')

6. 네이버 증권

네이버 증권

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')
profile
The light shines in the darkness.

0개의 댓글