AI/Python

파이썬 기초(웹 크롤링)

jumemory 2025. 5. 26. 17:52

파이썬 실전: 데이터 크롤링부터 웹 앱 배포까지

문법을 배웠다면 이제 실전에 적용할 차례입니다. 웹상의 데이터를 수집하고, 이를 지도에 표시하며, 누구나 접속할 수 있는 웹 페이지로 만드는 전 과정을 알아보겠습니다.


1. 데이터 수집의 준비: 파일 및 라이브러리 관리

import zipfile
with zipfile.ZipFile("./이름_생년_성별_10000.zip", 'r') as f:
    f.extractall("./mydata")

 

# - 파일 목록보기
# os.listdir("./mydata")
#
# - 파일 옮기기
# import shutil
# shutil.move("./'드디어 SKT 유심 교체했어요'…한달이나 참았던 이유-2025-05-23 064009.txt", "./a/")

데이터를 다루기 전, 파일을 압축 해제하고 관리하는 방법부터 시작합니다.

  • 압축 풀기: zipfile 모듈을 사용하여 대량의 데이터를 한 번에 추출합니다.
  • OS 활용: os.listdir()로 파일 목록을 확인하거나 shutil.move()로 파일을 정리하며 수집된 데이터를 관리합니다.
import os #운영체제(OS: Operating System) 관련 기능을 사용할 수 있게 해주는 표준 라이브러리를 불러오는 거예요.
if not os.path.isdir("./lyrics"):
    os.mkdir("./lyrics")
f = open(f"./lyrics/{artist}-{title}.txt", 'w', encoding='utf-8') #utf -8 전세계의 언어를 표현하는 확장팩팩 ///인코딩 디코딩 파일 변환방식임
f.write(lyrics.strip()) #f.write()만 하면, 데이터가 **메모리(버퍼)**에만 잠깐 저장돼 있을 수 있어요
f.close() #f.close()를 해야 진짜 파일에 저장되고 → 시스템이 파일을 안전하게 닫고 정리해요.

2. 웹 크롤링의 핵심 원리

웹사이트는 우리가 배운 딕셔너리와 유사한 JSON 형태나 태그 기반의 HTML 구조로 이루어져 있습니다.

  • HTTP 통신 (Request & Response):
    • requests 패키지: 서버와 데이터를 주고받는 도구입니다.
    • GET: URL에 데이터가 노출되는 방식. 주소를 잘 활용하면 페이지 이동 크롤링이 쉽습니다.
    • POST: 데이터를 Payload(딕셔너리 형태)에 숨겨서 요청하는 방식. 보안이나 복잡한 조건이 필요할 때 씁니다.
    • 헤더(Headers) 설정: 서버가 접근을 거부(<Response [406]>)할 때, 브라우저인 척 위장하여 우회하기 위해 사용합니다.
    • Status Code: 응답이 성공(200)했는지 확인합니다. <Response [406]>이 뜨면 서버가 거부한 것이므로, **헤더(User-Agent)**를 설정해 브라우저인 척 위장(우회)해야 합니다.
    • .json(): 서버에서 받은 JSON 텍스트를 파이썬의 딕셔너리 형태로 자동 변환해 줍니다.
  • result = requests.post('https://www.starbucks.co.kr/store/getStore.do?r=4B5E8X6R0Q', data=payload).json()
  • 데이터 파싱 (BeautifulSoup):
    • HTML 구조에서 원하는 데이터를 추출할 때 bs4 라이브러리를 사용합니다.
    • .find(), .find_all()을 이용해 태그, 클래스, ID로 원하는 요소를 정확히 찾아낼 수 있습니다.
    • Tip: 우클릭이나 복사가 금지된 사이트는 **F12(개발자 도구) -> F1(설정) -> Debugger 섹션의 'Disable JavaScript'**를 체크하면 분석이 수월해집니다.

 

pip install bs4
from bs4 import BeautifulSoup 
bs = BeautifulSoup(r.text)
bs.find("div", class_="song_name")

 

.replace, .text를 활용하여 원하는 데이터를 출력할수있다(참고** BeautifulSoup의 .text는 태크를 제외하고 문자만 출력해준다)

  • String Methods: .split(), .strip(), .replace() 등 지저분한 데이터를 깨끗하게 만드는 법.

정규식도 사용가능


3. 실전 프로젝트: 멜론 가사 수집 & 스타벅스 지도

  • 데이터 저장: f.open(), f.write(), f.close()를 통해 수집한 텍스트를 파일로 저장하며, utf-8 인코딩을 사용하여 한글 깨짐을 방지합니다.
  • 지도 시각화 (Folium)
    • folium.Map으로 지도를 생성하고, folium.Marker로 수집한 위경도 좌표에 마커를 찍습니다.
    • popup(클릭 시), tooltip(마우스 오버 시) 옵션으로 정보를 표시합니다.
    •  
  • 객체 저장 (Pickle): 수집한 딕셔너리 데이터를 원본 그대로(바이너리 형식) 저장하고 나중에 다시 불러올(load) 때 사용합니다.

.add_to(seoul)

  • folium.Marker(...)로 만든 마커를 seoul이라는 지도 객체에 **추가(add)**합니다.
seoul.save("./starbucks.html")

그렇게 만들어진 seoul을 파일로 저장

import pickle
with open("./starbucks.pkl", 'wb') as f:
    pickle.dump(result, f)

result

pickle은 파이썬에서 파일은 원본 그대로(직렬화) 저장하는 모듈이다 

with open()은 파일을 열고 자동으로 닫아주는 방식이다 "./starbucks.pkl" 이라는 파일을 만들어서 w(쓰고),b(바이너리)로 저장한것을 f지정함  (*** pickle은 데이터를 이진(binary) 형식으로 저장하기 때문에 wb 모드를 써야 한다***)

 

  • dump는 "데이터를 저장해라"는 뜻이에요.
  • result라는 변수에 담긴 데이터를 파일 객체 f에 저장하는 거예요.
  • 즉, result를 starbucks.pkl 파일에 저장하겠다는 뜻이에요.
import folium.map


seoul = folium.Map(location=[37.55, 126.98], zoom_start=12)

 

seoul = folium.Map(location=[37.55, 126.98], zoom_start=12)

지도 시작위치를 지정해서 생성하고 seoul이라는 변수에 저장

 

with open("./starbucks.pkl", 'rb') as f:
    result = pickle.load(f)

아까 저장했던 피클을 복원해주는것

for store in result['list']:
    folium.Marker([store['lat'],
                   store['lot']],
                   popup=store['s_name'],
                  tooltip=store['s_name'],
                   icon=folium.Icon(color='blue', icon='info-sign'
                                     )).add_to(seoul)

리스트에 저장된 딕셔너리(매장)위치 정보를 지도에 나타낸다

 

map_data = st_folium(seoul, width=1000, height=1000)

st_folium을 통해서 서울 스타벅스 위치정보를 추가한 seoul이라는 지도를 앱에 표시하겠다.

 

for store in result['list']:
    folium.Marker([store['lat'], store['lot']], popup=store['s_name']).add_to(seoul)
store['lat'] 위도 (latitude)
store['lot'] 경도 (longitude) — 타이핑 실수로 보이며 보통 lng 또는 lon이어야 정확함
popup=store['s_name'] 마커 클릭 시 뜨는 말풍선에 표시할 텍스트 (가게 이름 등)

 

 

 


4. 파이썬 웹 앱 만들기 (Streamlit)

파이썬 코드만으로 빠르게 웹 페이지를 구축하는 도구입니다. streamlit run 파일명.py로 실행합니다.

  • 주요 기능: st.title(), st.write(), st.slider(), st_folium() 등을 활용해 앞서 만든 지도를 웹에 띄울 수 있습니다.( from streamlit_folium import st_folium
  •  웹 서버도 자동  streamlit run 파일명.py을 실행하면 만든 페이지를 열어볼수있다

5. 프로그래밍 심화 이론 (고급 기능 & 자료구조)

실전 코드를 더 유연하게 만드는 개념들입니다.

scores = [90, 85, 95, 88]
total_score = calculate_sum(*scores)

  • 가변 인자 (*args, **kwargs):
    • *args: 정해지지 않은 개수의 인자를 튜플로 받습니다. 일반 매개변수 뒤에 위치합니다.
    • **kwargs: 여분의 키워드 인자들을 딕셔너리로 받습니다. 매개변수 목록 가장 마지막에 위치합니다.
    • 언패킹: `*`는 시퀀스를 위치 인자로, `**`는 딕셔너리를 키워드 인자로 풀어 전달합니다. (사용하지 않는 값은 언더바 _를 사용하여 버립니다.)
  • 클래스(Class)와 자료구조:
    • 클래스: 객체를 만들기 위한 틀입니다. 메서드의 첫 파라미터는 자기 자신을 가리키는 self를 씁니다.
    • 스택(Stack): 후입선출(LIFO), 큐(Queue): 선입선출(FIFO).
    • 링크드 리스트(Linked List): 각 노드가 데이터와 다음 노드의 주소를 가지고 연결된 구조입니다.

 

# Node class
class Node:
    def __init__(self, data):
        self.data = data
        self.next = None

 

# Linked List class
class LinkedList:
    def __init__(self):
        self.head = None

 

    # Append a new node to the end of the list
    def append(self, data):
        new_node = Node(data)
        if not self.head:
            self.head = new_node
            return
        last_node = self.head
        while last_node.next:
            last_node = last_node.next
        last_node.next = new_node

 

    # Prepend a new node to the beginning of the list
    def prepend(self, data):
        new_node = Node(data)
        new_node.next = self.head
        self.head = new_node

 

    # Delete a node with the given data
    def delete(self, data):
        if not self.head:
            return

 

        if self.head.data == data:
            self.head = self.head.next
            return

 

        current_node = self.head
        while current_node.next and current_node.next.data != data:
            current_node = current_node.next

 

        if current_node.next:
            current_node.next = current_node.next.next

 

    # Display the linked list
    def display(self):
        elements = []
        current_node = self.head
        while current_node:
            elements.append(str(current_node.data))
            current_node = current_node.next
        return " -> ".join(elements) if elements else "비어 있음"

 

 

 

 

from urllib.parse import urlparse, urlencode, quote
import requests
from bs4 import BeautifulSoup
import re
import os
import pathlib

p = re.compile("playSong\(\'([0-9]+)\',([0-9]+)\)")

def my_request(url, method='get'):
    head = {'user-agent'
            : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36 Edg/136.0.0.0'}
    if method == "get":
        return requests.get(url, headers=head)
   
def search_id(title):
    payload = {
        'searchGnbYn' : ['Y'],
        'kkoSpl' :  ['Y'],
        'mwkLogType' : ['T']
    }
    payload['q'] = [title]

    # url 주소 생성
    url = host + urlencode(payload, doseq=True)

    # return url
    r = my_request(url)
    text = BeautifulSoup(r.text).find("div", class_="tb_list d_song_list songTypeOne").find_all("tr")[1].find("button","btn_icon play" )['onclick']

    return p.findall(text)[0][-1]

def save_lyrics(songid, path='lyrics'):

    r = requests.get(url)
    head = {'user-agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36 Edg/136.0.0.0'}

    r = requests.get(url, headers=head)
    bs = BeautifulSoup(r.text)
    lyrics = BeautifulSoup(str(bs.find("div", id="d_video_summary")).replace("<br/>", "\n")).text

    # if not os.path.isdir(f"./lyrics/{path}"):
    #     os.mkdir(f"./lyrics/{path}")
    # else:
    #     pass
    pathlib.Path(f"./lyrics/{path}").mkdir(parents=True, exist_ok=True)

    title = bs.find("div", class_="song_name").text.replace("곡명", "").strip()
    artist = bs.find("div", class_="artist").text.strip()
    f = open(f"./lyrics/{path}/{artist}-{title}.txt", 'w', encoding='utf-8')
    f.write(lyrics.strip())
    f.close()

 

 

 

 

분야별 주요 라이브러리 요약

  • 데이터 과학: Pandas(데이터 분석), NumPy(수치 계산), SciPy(과학 계산).
  • 시각화: Matplotlib, Seaborn.
  • 인공지능: TensorFlow, PyTorch, Keras, Scikit-learn.
  • 웹 개발: Django, Flask, FastAPI.
  • GUI/자동화: PyQt, Tkinter, 시스템 스크립팅.

'AI > Python' 카테고리의 다른 글

통계 개념  (0) 2025.06.04
파이썬 기초(함수와 모듈)  (0) 2025.05.26
파이썬 기초(제어문)  (0) 2025.05.23
파이썬 기초(자료 구조의 핵심)  (0) 2025.05.21
Python 시작  (0) 2025.05.21