오늘은 파이썬으로 웹데이터 수집을 직접 해보는 실습을 하였다. 우선 필요한 라이브러리들을 설치해준다.
원하는 웹페이지에 들어가서 개발자 도구(F12)로 확인해보고 selector를 가져와 경로를 정확하게 지정해주어야 한다. 혹은 html파일을 불러와서 select로 확인할 수도 있다.

파이썬 홈페이지에 들어가서 검색창에 내가 직접 입력하지 않고 코드로 가져와 select해보았다.
from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.get('https://www.python.org')
input_el = driver.find_element(by=By.ID, value='id-search-field')
input_el.send_keys('pycon')
코드를 실행하면 크롬창으로 파이썬 홈페이지가 검색창에 "pycon"이 입력된 채로 열린다.

이 외에도 기상청 홈페이지에서 기온을 .text로 가져오기도 해보았다.
수업 막바지에는 본격적으로 크롤링을 해보았다. yes24 홈페이지에서 베스트셀러 도서 정보를 크롤링해서 가져와 SQL 워크벤치 데이터베이스로 넣어보았다.

오늘은 파이썬을 활용한 웹 데이터 수집 실습을 통해, 직접 웹페이지의 정보를 추출해보는 경험을 했다. 처음에는 F12 개발자 도구로 selector를 찾고, HTML 구조를 파악하는 과정이 낯설었지만, 실습을 통해 점점 익숙해졌다. 특히 selenium을 이용해 Python 공식 홈페이지의 검색창에 자동으로 텍스트를 입력하는 과정을 직접 구현해보며 자동화의 원리를 체감할 수 있었다. 수업 후반에는 yes24 사이트의 베스트셀러 정보를 크롤링해 SQL 데이터베이스에 연동하는 작업까지 수행해보았다. 단순히 웹페이지를 보는 것이 아닌, 그 안의 구조를 분석해 원하는 정보를 추출하는 과정이 신기하고 재미있었다. 처음 접한 크롤링 개념이 막막하게 느껴졌지만, 코드를 통해 차근차근 구현해보며 크롤링에 익숙해져야겠다.
오늘은 웹데이터를 수집하고 새로 레포지토리 만들어서 깃허브에 올리는 실습을 하였다. 처음 실습 두 가지는 강의자료를 따라해보고 세번째 실습은 내가 원하는 웹페이지에서 직접 크롤링을 했다.
RSS피드는 웹사이트(뉴스, 블로그 등)에 새로 올라오는 글이나 콘텐츠의 요약 정보를 자동으로 제공하는 데이터 포맷이다. 그래서 첫 번째 실습은 뉴스 데이터 수집하기이다. lxml라이브러리를 설치하고 뉴스 웹페이지에서 개발자 도구(F12)를 열어 가져오려는 태그를 확인한다. select에 경로를 정확하게 입력해주고 해당 뉴스 데이터를 news.csv파일로 저장하는 것까지 해보았다.
두 번째 실습을 웹의 이미지를 로컬에 저장하는 실습이었다. 이미지 URL을 태그에서 찾고 이미지 URL을 이용해서 요청한다. 무비차트에서 영화 랭킹 정보 조회 및 포스터 이미지를 저장한다. 아래와 같이 images라는 폴더가 생기고 포스터 이미지들이 들어간 걸 확인할 수 있다.

세 번째로는 각자 원하는 웹페이지에서 크롤링을 해보는데 나는 올리브영 홈페이지에서 메이크업 카테고리의 랭킹을 선정했다. 해당 페이지의 url을 입력해주고 csv파일로 저장해본다.
try:
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.CSS_SELECTOR, "ul.cate_prd_list > li"))
)
print("상품 목록 요소가 성공적으로 로드되었습니다.")
except Exception as e:
print(f"상품 목록 로드 대기 중 시간 초과 또는 오류 발생: {e}")
print("페이지가 완전히 로드되지 않았거나, 셀렉터가 변경되었을 수 있습니다.")
# 브라우저가 렌더링한 최종 HTML 콘텐츠 가져오기
html_content = driver.page_source
# BeautifulSoup으로 HTML 파싱
soup = BeautifulSoup(html_content, 'html.parser')
# 상품 목록 추출
# 이 'items' 리스트의 순서는 웹 페이지에서 보이는 순서와 일치
items = soup.select("ul.cate_prd_list > li")
print(f"찾은 상품 아이템 개수: {len(items)}")
products = []
rank_counter = 1 # 순위를 위한 카운터 변수 초기화
for item in items:
# 순위 정보 추출 (웹페이지에서 보이는 순서대로 1, 2, 3... 부여)
# Selenium 사용
rank = str(rank_counter)
# 상품명 추출
name_tag = item.select_one("div.prd_name a")
name = name_tag.text.strip() if name_tag else None
# 가격 추출
price_nums = item.select("p.prd_price span.tx_num")
original_price = None
discounted_price = None
if price_nums:
if len(price_nums) > 1: # 할인가가 있는 경우 (두 개의 span.tx_num)
original_price = price_nums[0].text.strip()
discounted_price = price_nums[1].text.strip()
else: # 할인가가 없는 경우 (하나의 span.tx_num)
original_price = price_nums[0].text.strip()
discounted_price = price_nums[0].text.strip() # 할인가를 정가와 동일하게 설정
if name: # 상품명이 추출되었을 경우에만 리스트에 추가
products.append({
"순위": rank,
"상품명": name,
"정가": original_price,
"할인가": discounted_price
})
rank_counter += 1
# Pandas DataFrame 생성 및 CSV 저장
df = pd.DataFrame(products)
df.to_csv("oliveyoung_makeup.csv", index=False, encoding="utf-8-sig")

이처럼 oliveyoung_makeup.csv 파일로 예쁘게 정리된 파일이 생겼다. 이제 크롤링해서 가져온 데이터를 SQL 워크벤치 데이터베이스로 넣었고 그 결과 잘 들어갔다.

오늘 실습을 통해 웹 데이터 수집의 과정이 생각보다 섬세하고 다양하다는 걸 느꼈다. 처음에는 강의자료를 따라하면서 단순히 태그를 복사해오는 작업처럼 느껴졌지만, 점차 구조를 파악하고 태그를 선택하는 데에도 논리가 필요하다는 것을 알게 되었다. 네이버 웹툰 이미지도 저장해보려고 했지만 불러오는 과정에서 막혀버려서 올리브영 데이터로 바꾼 것이다. 중간에 요소가 안 잡히거나 셀렉터가 틀리는 오류도 겪었지만, 그 덕분에 디버깅하는 방법도 조금은 익숙해졌다. 수집한 데이터를 csv로 정리하고, 그걸 다시 SQL에 넣는 과정에서 데이터 흐름에 대한 감각이 생겼다. 올리브영 말고도 다른 내가 관심 있는 데이터를 직접 수집해보면 좋을 것 같다.
오늘은 도커(Docker)를 설치하기 위해서 VMWARE로 가상머신 우분투에 대하여 배웠다. 가장 먼저 리눅스를 다루기 위한 기초적인 명령어들에 대해 입력해보았다.
등 여러 기초 명령어에 대해 배웠는데 캠프 초반에 리눅스 잠깐 다뤘을때도 했던 명령어들이라 크게 어렵지 않았다. vi에디터 연습 과제도 쉬운 난이도로 몇 개 주셔서 빠르게 제출하였다.
IP는 네트워크 상에서의 특정 컴퓨터를 가리키는 주소이다.
Port는 한 컴퓨터 내에서 실행되고 있는 특정 프로그램의 주소이다.
👉 특정 서버와 통신을 할 때는 IP주소와 서버가 실행되고 있는 포트 번호까지 알고 있어야 한다.
0~1023번까지의 포트 번호는 주요 통신을 위한 규약에 따라 이미 정해져 있다. 이렇게 규약을 통해 역할이 정해져 있는 포트 번호를 보고 잘 알려진 포트라고 부르기도 한다. 이들 중 자주 사용되는 포트 번호에 대해서 살펴보겠다.
- 22번(SSH) : 원격 접속을 위한 포트 번호
- 80번(HTTP) : HTTP로 통신을 할 때 사용
- 443번(HTTPS) : HTTPS로 통신을 할 때 사용
- 21번(FTP) : 파일 전송을 위한 표준 네트워크 프로토콜로, 서버와 클라이언트 간에 파일을 업로드하거나 다운로드할 때 사용
- 8888번(주피터 노트북) : 주피터 노트북의 기본 포트 번호
- 2375/2376번(도커) : 도커 데몬이 기본적으로 사용하는 포트 번호로, 2375번(비보안), 2376(보안)
- 3306번(MySQL) : MySQL 데이터베이스 서버에 접속할 때 사용
기본적인 이론에 대해 배우고 이후에는 우분투(Ubuntu)에서 Docker를 설치하였다. 그리고 이와 관련한 이론에 대해서도 배웠다.
우분투에서 도커 설치 후 Nginx라는 이미지를 다운받고 이미지를 컨테이너에 올려 실행도 해보고 수정, 삭제 등을 실습해보며 Nginx 서버가 잘 실행되는 지 브라우저로 확인해보는 실습을 해보며 오늘 수업이 마무리되었다.
오랜만에 리눅스에 대해 배우면서 가물가물했던 명령어들을 되새길 수 있어서 좋았다. 도커와 컨테이너, 이미지의 개념은 처음엔 추상적이었지만, 실습을 통해 직접 컨테이너를 실행하고 수정하면서 자연스럽게 익힐 수 있었다. 사실 공모전 마감일이 오늘이라서 급하게 기획서 수정하고 신경쓰느라 수업에 온전히 집중하지 못하긴 했지만 다행히 크게 어렵지 않은 이론들과 예전에 학교다닐 때 리눅스를 접해본 적이 있어서 금방 따라갈 수 있었고 기획서도 제시간에 맞춰 제출하였다. 이제 기획서도 제출하였으니 내일부터 다시 수업에 온전히 집중해야겠다.
오늘도 이론적인 수업 이해와 Xshell에서 직접 입력해보는 시간을 가졌다.
도커 클라이언트
도커 호스트
도커 엔진
레지스트리(Registry)
웹 서비스 아키텍처는 웹 애플리케이션의 구조를 설계하는 방식으로, 클라이언트와 서버 간의 상호작용을 체계적으로 구성한다.

💡 클라이언트는 서버에게 특정한 웹페이지를 요구하고 웹서버는 그 웹페이지를 찾아서 클라이언트에게 전달하여 주는 것이 기본이다.
이후 Xshell로 새로 nginx이미지를 만들어보는 실습을 하였다. 새로 폴더 만들고 .html파일을 작성 후 도커 파일도 생성한 후에 새로운 이미지를 빌드해보았다. 나는 빌드까지는 잘 되었는데 브라우저에서 내 ip주소:8080으로 직접 연결하는 과정에서 문제가 생겼었다. 나뿐만 아니라 다른 친구도 나와 같은 에러가 나서 해결하기 위해 이미지를 지우고 재생성을 해보았지만 여전히 같은 오류가 나서 결국 해결하지 못하고 다음 실습으로 넘어갔다.
이후에는 도커로 MySQL을 실행시켜보는 실습을 하였다. 중간중간 docker ps로 컨테이너가 잘 실행되고 있는지 체크도 해주면서, my_db라는 이름으로 db를 만들어주었다. 그리고 파이썬 프로그램과도 연결해주어서 간단한 테이블을 작성해 추가해주었다.
그 결과 SQL워크벤치에 가서 확인해보면 내가 파이썬으로 만든 girl테이블과 boy테이블이 정상적으로 들어간 것을 볼 수 있었다.
이후 수업 막바지에는 파이스파크(PySpark) 실습 환경을 구성하기 위해 파이스파크와 주피터 노트북을 포함하는 파일을 만들어 도커 이미지 설치 후 컨테이너 실행을 해보았다. 이번에도 브라우저에서 내 ip주소:8888로 직접 연결했는데 이번에는 다행히 정상적으로 열렸다.
도커의 아키텍처와 주요 구성 요소들에 대한 개념을 정리하고, 직접 실습을 통해 체득할 수 있었다. 도커 클라이언트부터 엔진, 레지스트리까지 각 역할을 이해하며 전체 구조를 보는 시야가 넓어진 느낌이었다. 특히 nginx 이미지를 직접 만들어보는 실습은 웹서비스의 흐름을 몸으로 익힐 수 있는 기회였고, 비록 접속 오류로 결과를 확인하지는 못했지만 그 과정 자체가 많은 도움이 되었다. 같은 오류를 다른 사람도 겪은 걸 보며 실습 중 발생하는 문제를 함께 고민하고 해결해보려는 시도가 의미 있었다. 내가 작성한 코드가 실제 데이터베이스에 반영되는 걸 보니 도커의 실용성이 조금은 느껴졌다.
너무 좋은 글이네요!