크롤링

2024. 12. 6. 03:29카테고리 없음

1. 크롤링(Crawling) 이란,
웹 크롤러(Web Craler) 또는 스크레이퍼(scraper)라고 불리는 프로그램이나 스크립트를 사용하여 인터넷상의 웹페이지에서 데이터를 자동으로 수집하는 과정을 말합니다.
주로, 검색 엔진이 웹사이트를 탐색하고 색인(Index)에 추가하기 위해 사용하는 기술이며, 특정 주제나 데이터를 수집해 분석하는 데에도 활용됩니다.
크롤링은 HTML, CSS, JAVASCRIPT로 구성된 웹페이지 구조를 파싱(Parsing)하여 원하는 정보를 추출하고, 이를 활용 가능한 데이터 형식으로 저장합니다. 
크롤링 시에는 웹사이트의 이용약관과 로봇 배제 표준(Robots.txt)을 준수하여 법적, 윤리적 문제를 방지해야 합니다.
예) https://www.melon.com/robots.txt

 
2. basicenglishspeaking.com
[주소]  https://basicenglishspeaking.com/daily-english-conversation-topics/
 
3. BeautifulSoup 이란?
- BeautifulSoup은 HTML 및 XML 파일에서 데이터를 추출하기 위해 사용되는 파이썬 라이브러리입니다. 이 라이브러리는 웹페이지 소스 코드에서 파싱 트리(parse tree)를 생성하여 데이터를 계층적이고 읽기 쉬운 방식으로 추출할 수 있게 해 줍니다. 

import requests
from bs4 import BeautifulSoup

 
4. 크롤링 예시)

site = 'https://basicenglishspeaking.com/daily-english-conversation-topics/' # 이 변수는 문자열로 URL을 저장합니다. 
                                                                             # 이 URL은 웹사이트의 주소로, 영어 회화 주제를 제공하는 웹페이지입니다.
request = requests.get(site) #requests 라이브러리를 사용하여 지정된 URL (site)에 HTTP GET 요청을 보냅니다. 
                             #이 작업은 해당 URL에서 데이터를 가져오는 역할을 합니다.
print(request) # <Response [200]> -> 요청이 성공했음을 나타냄.
               # <Response [404]> -> 웹페이지를 찾지 못했음을 뜻합니다.
print(request.text) # 웹페이지의 HTML 코드 전체가 출력됩니다.

 
5. 크롤링 예시 2)

import requests
from bs4 import BeautifulSoup

# URL 요청 및 응답 받기
site = 'https://basicenglishspeaking.com/daily-english-conversation-topics/'
request = requests.get(site)

# BeautifulSoup으로 HTML 파싱
soup = BeautifulSoup(request.text, 'html.parser')

# 특정 'div' 태그 찾기 (예: 'thrv-columns' 클래스가 있는 경우)
div = soup.find('div', {'class': 'thrv-columns'})

for link in links:
        print(link.text)  # 링크 텍스트 출력

 
6. 크롤링 예시 3)

subject = []
for link in links:
    subject.append(link.text)
print(subject)         # 출력: ['Topic 1', 'Topic 2', 'Topic 3']
print(len(subject))    # 출력: 3

 
7. 크롤링 예시 4)

import requests  # 웹사이트에 요청을 보내기 위한 라이브러리
from bs4 import BeautifulSoup  # HTML 데이터를 파싱하고 탐색하기 위한 라이브러리

# 대상 웹사이트 URL 설정
site = 'https://basicenglishspeaking.com/daily-english-conversation-topics/'

# 웹사이트로 HTTP GET 요청을 보내고 응답 데이터 저장
request = requests.get(site)

# BeautifulSoup을 사용하여 HTML 소스를 파싱
soup = BeautifulSoup(request.text)


# 주제 개수 출력
print('총', len(subject), '개의 주제를 찾았습니다.')
# subject 리스트에 저장된 각 주제를 번호와 함께 출력

for i in range(len(subject)):  # subject 리스트의 길이만큼 반복
    print('{0:2d}, {1:s}'.format(i+1, subject[i]))
    # {0:2d}: i+1(항목 번호)을 최소 2자리 정수로 출력
    # {1:s}: subject[i](해당 주제 텍스트)를 문자열로 출력

-->
총 3 개의 주제를 찾았습니다.
 1, Topic 1
 2, Topic 2
 3, Topic 3

 
8. 크롤링 예시 5)

#이 함수는 다음(Daum) 뉴스의 ID를 기반으로 제목을 가져오는 기능을 수행합니다.
#BeautifulSoup을 사용해 HTML 페이지에서 클래스가 tit_view인 <h3> 태그를 찾아 제목을 추출합니다.
#제목을 찾지 못하면 '제목 없음'을 반환합니다.
#코드가 안정적으로 작동하려면 뉴스 페이지의 HTML 구조가 유지되어야 합니다.


# 특정 뉴스 ID를 사용해 다음(Daum) 뉴스의 제목을 가져오는 함수 정의
def daum_news_title(news_id):
    # 다음(Daum) 뉴스 URL 구성
    url = 'https://v.daum.net/v/{}'.format(news_id)
    # `news_id`를 포함하여 URL을 동적으로 생성
    # 예: 'https://v.daum.net/v/20241205093117938'

    # GET 요청을 보내 URL의 HTML 소스를 가져옴
    request = requests.get(url)
    
    # BeautifulSoup으로 HTML을 파싱
    soup = BeautifulSoup(request.text, 'html.parser')

    # 뉴스 제목을 포함하는 <h3> 태그를 찾음 (클래스가 'tit_view'인 태그)
    title = soup.find('h3', {'class': 'tit_view'})

    # 제목이 존재하면 텍스트를 추출하고, 공백을 제거하여 반환
    if title:
        return title.text.strip()

    # 제목이 없을 경우 '제목 없음' 반환
    return '제목 없음'

# 특정 뉴스 ID에 해당하는 뉴스 제목 가져오기
daum_news_title('20241205093117938')  # 첫 번째 뉴스 ID로 제목 추출
daum_news_title('20241205083931932')  # 두 번째 뉴스 ID로 제목 추출
-->
이승기♥이다인, 10개월 딸·신혼집 깜짝 공개…육아 예능 가나요 [Oh!쎈 이슈]

 
9. 크롤링 예시 6)

import requests  # HTTP 요청을 보내기 위한 라이브러리
from bs4 import BeautifulSoup  # HTML 파싱을 위한 라이브러리

# 벅스 차트 제목을 가져오는 함수 정의
def music_bugs():
    # 벅스 차트 URL
    chart_url = 'https://music.bugs.co.kr/chart'

    # HTTP GET 요청을 보내고 응답 객체 저장
    request = requests.get(chart_url)

    # BeautifulSoup으로 HTML 파싱
    soup = BeautifulSoup(request.text, 'html.parser')

    # 제목이 포함된 태그 찾기 (클래스가 'title'인 <p> 태그)
    titles = soup.find_all('p', {'class': 'title'})

    # 제목 리스트 생성
    result = []
    for title in titles:
        result.append(title.text.strip())  # 제목 텍스트를 리스트에 추가

    # 리스트 반환
    return result if result else '제목없음'

# 함수 호출 및 결과 출력
titles = music_bugs()
print("벅스 차트 제목 목록:")
for idx, title in enumerate(titles, start=1):
    print(f"{idx}. {title}")

 
10. 크롤링 예시 10)

# 1위~ 100위까지의 곡명, 가수 크롤링
# 출력 예) 1위. HOME SWEET HOME (feat. 태양, 대성) -G-DRAGON

import requests
from bs4 import BeautifulSoup

# 벅스 뮤직 차트 페이지 URL
url = 'https://music.bugs.co.kr/chart'

# HTTP GET 요청 보내기
response = requests.get(url)

# 요청 성공 확인
if response.status_code == 200:
    # HTML 파싱
    soup = BeautifulSoup(response.text, 'html.parser')

    # 곡명 추출 (클래스: 'title')
    titles = soup.find_all('p', class_='title')

    # 가수명 추출 (클래스: 'artist')
    artists = soup.find_all('p', class_='artist')

    # 곡명과 가수 출력
    print("벅스 차트 TOP 100:")
    for i in range(len(titles)):
        title = titles[i].text.strip()  # 곡명 텍스트 추출 및 공백 제거
        artist = artists[i].text.strip()  # 가수 텍스트 추출 및 공백 제거
        print(f"{i+1}위. {title} - {artist}")
else:
    print(f"요청 실패: {response.status_code}")

 
11. 크롤링 11)

# 필요한 라이브러리 임포트
import requests  # HTTP 요청을 보내기 위한 라이브러리
from bs4 import BeautifulSoup  # HTML 파싱을 위한 라이브러리

# 벅스 차트 URL로 HTTP GET 요청
request = requests.get('https://music.bugs.co.kr/chart')

# 요청 객체 출력 (요청 성공 여부 확인)
print(request)
# 출력 예시: <Response [200]> -> 요청 성공
# 출력 예시: <Response [404]> -> 페이지 없음

# BeautifulSoup을 사용해 HTML 파싱
soup = BeautifulSoup(request.text)  
# HTML 문서를 BeautifulSoup 객체로 변환하여 계층적으로 탐색 가능
# 주의: 기본 파서를 사용하지만 'html.parser'를 명시하는 것이 좋음
# soup = BeautifulSoup(request.text, 'html.parser')

# 곡명 추출 (클래스가 'title'인 <p> 태그를 모두 찾음)
titles = soup.findAll('p', {'class': 'title'})
# findAll(): HTML 문서에서 지정된 태그와 조건에 맞는 모든 요소를 리스트로 반환
# 예: <p class="title">곡명</p> 태그를 리스트로 반환

# 가수명 추출 (클래스가 'artist'인 <p> 태그를 모두 찾음)
artists = soup.findAll('p', {'class': 'artist'})
# 가수 정보가 포함된 <p class="artist">태그를 리스트로 반환

# 곡명 리스트 출력
print(titles)
# 출력 예시:
# [<p class="title">곡명1</p>, <p class="title">곡명2</p>, ...]

# 가수 리스트 출력
print(artists)
# 출력 예시:
# [<p class="artist">가수1</p>, <p class="artist">가수2</p>, ...]

 
12. 크롤링 예시 12)

# enumerate()와 zip()을 사용하여 곡명과 가수를 순회하며 인덱스와 데이터를 함께 처리
for i, (t, a) in enumerate(zip(titles, artists), 1):
    # zip(titles, artists): 곡명(titles)과 가수(artists)를 동시에 순회
    # enumerate(..., 1): 인덱스를 1부터 시작하여 곡명과 가수를 함께 처리
    # i: 1부터 시작하는 순위 번호
    # t: 현재 순회 중인 곡명 태그 (예: <p class="title">HOME SWEET HOME</p>)
    # a: 현재 순회 중인 가수 태그 (예: <p class="artist">G-DRAGON</p>)

    # 곡명 텍스트 추출 및 양쪽 공백 제거
    title = t.text.strip()
    # t.text: 곡명 태그에서 텍스트만 추출
    # strip(): 텍스트의 양쪽 공백 제거

    # 가수 텍스트 추출, 'wn' 문자열로 나눈 후 첫 번째 부분만 가져옴
    artist = a.text.strip().split('wn')[0]
    # a.text: 가수 태그에서 텍스트만 추출
    # strip(): 텍스트의 양쪽 공백 제거
    # split('wn'): 텍스트를 'wn' 기준으로 분리
    # [0]: 분리된 첫 번째 부분만 사용 (예: "Artist Name wnOtherInfo" → "Artist Name")

    # 포맷팅된 순위, 곡명, 가수 정보를 출력
    print('{0:3d}위. {1:s} - {2:s}'.format(i, title, artist))
    # '{0:3d}': i(순위 번호)를 3자리 정수로 출력, 왼쪽에 공백 추가
    # '{1:s}': title(곡명)을 문자열로 출력
    # '{2:s}': artist(가수)를 문자열로 출력
    # .format(): 문자열 포맷팅 메서드로, 순위(i), 곡명(title), 가수(artist)를 출력 형식에 맞게 삽입
    
    -->
  로제(ROSÉ)
  5위. 너와의 모든 지금 - 재쓰비 (JAESSBEE)
  6위. POWER - G-DRAGON
  7위. number one girl - 로제(ROSÉ)
  8위. Mantra - 제니 (JENNIE)
  9위. Drowning - WOODZ
 10위. HAPPY - DAY6 (데이식스)
 11위. 나는 반딧불 - 황가람
 12위. UP (KARINA Solo) - aespa
 13위. Letter To Myself - 태연 (TAEYEON)
 14위. 내 이름 맑음 - QWER
 15위. Igloo - KISS OF LIFE

 
13. 크롤링 13)

import requests  # HTTP 요청을 보내기 위한 라이브러리
from bs4 import BeautifulSoup  # HTML 파싱을 위한 라이브러리

# 멜론 차트 URL로 HTTP GET 요청
request = requests.get('https://www.melon.com/chart/index.html')
# `requests.get()`을 사용하여 지정된 URL에서 HTML 소스를 가져옴
# 반환값인 `request` 객체에는 서버 응답 상태 코드와 HTML 소스가 포함됨

# 서버 응답 객체 출력
print(request)
# 출력 예시: <Response [200]> -> 요청 성공
# 출력 예시: <Response [404]> -> 페이지를 찾을 수 없음
# 응답 객체는 `status_code` 속성을 통해 요청 성공 여부를 확인할 수 있음

# BeautifulSoup을 사용해 HTML 파싱
soup = BeautifulSoup(request.text)
# `request.text`는 가져온 HTML 소스를 문자열로 반환
# BeautifulSoup 객체로 변환하여 HTML 문서를 계층적으로 탐색할 수 있게 함
# 기본 파서를 사용했지만, 명시적으로 `'html.parser'`를 지정하는 것이 좋음
# 예: soup = BeautifulSoup(request.text, 'html.parser')

 
14. 크롤링 예시)

# 필요한 라이브러리 import
import requests  # HTTP 요청을 보내기 위한 라이브러리
from bs4 import BeautifulSoup  # HTML 파싱을 위한 라이브러리

# User-Agent 헤더 설정
header = {'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'}
# 'user-agent': HTTP 요청 헤더 중 하나로, 클라이언트의 소프트웨어 정보를 서버에 전달
# 위 값은 브라우저에서 접속하는 것처럼 보이도록 하기 위해 설정
# User-Agent 없이 요청할 경우, 서버가 요청을 거부할 수 있음

# 멜론 차트 페이지로 HTTP GET 요청을 보냄
request = requests.get('https://www.melon.com/chart/index.html', headers=header)
# 'headers=header': 요청 헤더에 User-Agent 정보를 포함
# 서버는 요청 헤더를 확인하여 봇인지 브라우저인지 판단

# 요청 결과 출력
print(request)
# 출력 예시: <Response [200]> -> 요청 성공
# 출력 예시: <Response [403]> -> 접근이 거부됨 (User-Agent 설정 필요)

# BeautifulSoup을 사용하여 HTML 파싱
soup = BeautifulSoup(request.text, 'html.parser')
# 'html.parser': HTML을 파싱하는 기본 파서
# request.text: 요청 응답의 HTML 소스를 문자열로 가져옴
# BeautifulSoup 객체로 변환하여 HTML 문서를 계층적으로 탐색 가능

 
15. 크롤링 예시)

import requests
from bs4 import BeautifulSoup

# 삼성전자 종목 코드 (네이버 금융 URL에서 확인 가능)
stock_code = '005930'

# URL 설정 (네이버 금융 개별 종목 페이지)
url = f'https://finance.naver.com/item/main.nhn?code={stock_code}'

# HTTP GET 요청 보내기
response = requests.get(url)

# 요청 성공 여부 확인
if response.status_code == 200:
    # BeautifulSoup으로 HTML 파싱
    soup = BeautifulSoup(response.text, 'html.parser')

    # 회사명 추출
    name = soup.find('div', class_='wrap_company').find('h2').text.strip()

    # 현재 가격 추출
    price = soup.find('p', class_='no_today').find('span', class_='blind').text.strip()

    # 거래량 추출
    volumn = soup.find('td', {'class': 'first'}).find_next_sibling('td').find('span', class_='blind').text.strip()

 
16. 크롤링 예시

# 네이버 금융에서 주식 정보를 가져오는 함수 정의
def naver_finance(code):
    # 네이버 금융 개별 종목 URL 구성
    site = f'https://finance.naver.com/item/main.naver?code={code}'
    # 종목 코드를 URL에 삽입하여 특정 주식 페이지로 접근

    # HTTP GET 요청을 보내고 응답 저장
    request = requests.get(site)

    # BeautifulSoup으로 HTML 파싱
    soup = BeautifulSoup(request.text)
    # HTML 문서를 BeautifulSoup 객체로 변환하여 계층적으로 탐색 가능

    # 전체 종목 정보를 포함하는 <div> 태그 찾기
    div_totalinfo = soup.find('div', {'class': 'new_totalinfo'})
    # 'new_totalinfo' 클래스는 종목 이름, 현재가, 거래량 등 주요 정보를 포함

    # 종목 이름 추출
    name = div_totalinfo.find('h2').text
    # 'new_totalinfo' 내부의 <h2> 태그에서 종목 이름을 추출

    # 현재가 정보가 포함된 <div> 태그 찾기
    div_today = div_totalinfo.find('div', {'class': 'today'})
    # 'today' 클래스는 현재가 정보를 포함

    # 현재가 추출
    price = div_today.find('span', {'class': 'blind'}).text
    # 'blind' 클래스는 시각적으로 숨겨진 텍스트를 포함
    # 이 태그에서 현재가 텍스트를 추출

    # 거래량이 포함된 <table> 태그 찾기
    table_no_info = soup.find('table', {'class': 'no_info'})
    # 'no_info' 클래스는 거래량, 거래대금 등의 정보를 포함

    # <td> 태그 전체를 리스트로 가져오기
    tds = table_no_info.findAll('td')

    # 거래량 정보 추출
    volume = tds[2].find('span', {'class': 'blind'}).text
    # 'no_info' 테이블에서 세 번째 <td> 태그의 'blind' 클래스에 거래량이 포함

    # 결과를 딕셔너리 형태로 정리
    dic = {'name': name, 'code': code, 'price': price, 'volume': volume}
    # 종목 이름, 종목 코드, 현재가, 거래량 정보를 딕셔너리로 저장

    # 결과 반환
    return dic

 
17. 크롤링 예시

# 대상 종목 코드 리스트 생성
codes = ['035720', '000660']
# '035720': 카카오의 종목 코드
# '000660': SK하이닉스의 종목 코드
# 주식 정보를 가져올 종목 코드들을 리스트로 저장

# 데이터를 저장할 빈 리스트 생성
data = []
# 각 종목의 정보를 딕셔너리로 저장한 후, 이 리스트에 추가

# 종목 코드 리스트를 순회하며 정보 가져오기
for code in codes:
    dic = naver_finance(code)
    # naver_finance() 함수 호출
    # 종목 코드(`code`)를 입력하여 해당 종목의 회사명, 가격, 거래량 등의 정보를 딕셔너리로 반환

    data.append(dic)
    # 반환된 딕셔너리를 `data` 리스트에 추가

# 최종 데이터 출력
print(data)
# 모든 종목 정보를 포함한 리스트 출력

 
18. 크롤링 예시

# pandas 라이브러리 import
import pandas as pd
# pandas는 데이터 분석과 처리를 위한 라이브러리로, 특히 데이터프레임 형식으로 데이터를 다루기 편리

# data 리스트를 데이터프레임으로 변환
df = pd.DataFrame(data)
# data: 이전 코드에서 생성된 종목 정보를 저장한 리스트
# 예: [{'name': '카카오', 'code': '035720', 'price': '55,000', 'volume': '1,234,567'}, ...]

# 데이터프레임 객체 확인
df
# 생성된 데이터프레임을 출력
# 데이터프레임 형식으로 보기 좋게 데이터가 정리되어 출력됩니다
# 예:
#      name   code   price    volume
# 0   카카오  035720  55,000  1,234,567
# 1  SK하이닉스  000660  120,000  2,345,678

# 데이터프레임을 엑셀 파일로 저장
df.to_excel('naver_finance_xlsx')
# 'naver_finance_xlsx': 저장할 엑셀 파일 이름
# 파일 이름은 확장자 `.xlsx`를 포함해야 합니다. 수정 필요:
# 예: df.to_excel('naver_finance.xlsx')
# 저장된 엑셀 파일은 데이터프레임의 내용을 포함
728x90
LIST