| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | |
| 7 | 8 | 9 | 10 | 11 | 12 | 13 |
| 14 | 15 | 16 | 17 | 18 | 19 | 20 |
| 21 | 22 | 23 | 24 | 25 | 26 | 27 |
| 28 | 29 | 30 |
Tags
- computer vision
- Python
- 밑바닥부터 시작하는 딥러닝2
- file system
- Multimedia
- CPP
- Linux
- C++
- RNN
- Machine Learning
- Seoul National University
- BFS
- SQLD
- Optimization
- Process
- CNN
- Robocup@Home 2026
- do it! 알고리즘 코딩테스트: c++편
- paper review
- deep learning
- System Call
- Baekjoon
- DFS
- ROS2
- Humble
- cs231n
- Data Science
- On-memory file system
- Gentoo2
- Operating System
Archives
- Today
- Total
newhaneul
[Advanced Python Programming] Lecture 15. Web Crawling 본문
4. University Study/Advanced Python Programming
[Advanced Python Programming] Lecture 15. Web Crawling
뉴하늘 2026. 5. 27. 01:13728x90
포스팅은 인하대학교 허혜선 교수님의 [202601-EEC3408-001] 고급파이썬프로그래밍을 수강하고 공부한 내용을 정리하기 위한 포스팅입니다.
1. HTML 소스 분석 및 BeautifulSoup 활용법
웹 브라우저에서 소스 보기
- 웹 브라우저의 빈 곳에서 마우스 오른쪽 버튼을 클릭하여 [페이지 원본 보기](크롬은 페이지 소스 보기) 또는 [검사]를 선택하면 HTML 코드를 확인할 수 있다.
- 브라우저의 [개발자 도구]를 활용하면 원하는 웹페이지 요소의 정확한 HTML 태그 위치와 정보를 손쉽게 찾아낼 수 있다.

핵심 추출 함수와 속성 활용
HTML을 알아볼 수 있는 형태로 변경해주고 더불어 필요한 내용들을 추출하기 위해서는 BeautifulSoup을 사용해야 한다.
import urllib.request
import bs4
nateUrl = "https://www.nate.com"
htmlObject = urllib.request.urlopen(nateUrl)
bsObject = bs4.BeautifulSoup(htmlObject, "html.parser")
print(bsObject)
<!DOCTYPE html>
<html lang="ko">
<head>
<meta content="IE=Edge" http-equiv="X-UA-Compatible"/>
<meta content="//www.nate.com/" name="msapplication-starturl"/>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type"/>
<meta content="" name="nate:title"/>
<meta content="네이트 이슈UP" name="nate:description"/>
<meta content="네이트 홈" name="nate:site_name"/>
<meta content="https://www.nate.com/" name="nate:url"/>
<meta content="" name="nate:image"/>
<meta content="새로워진 네이트에서 당신의 오늘을 만나보세요" name="description"/>
<meta content="width=device-width, initial-scale=1" name="viewport"/>
<meta content="네이트" property="og:title"/>
<meta content="https://www.nate.com/" property="og:url"/>
<meta content="https://main.nateimg.co.kr/img/v7/OpenGraphTag_nate_240x240.png" property="og:image"/>
<meta content="새로워진 네이트에서 당신의 오늘을 만나보세요" property="og:description"/>
<title>네이트</title>
<link href="/css/common.min.css?v=202601291101_02" rel="stylesheet" type="text/css"/>
<link href="//main.nateimg.co.kr/img/v7/favicon_32.ico" rel="shortcut icon" type="image/x-icon">
<link href="https://www.nate.com" rel="canonical"/>
<!-- script type="text/javascript" src="/js/common/jquery-1.9.1.min.js"></script-->
<!-- jquery 3.x 적용을 테스트를 위한 migrate 테스트 적용 -->
...
<!--natemain-->
<script type="text/javascript">//<![CDATA[
CFN_type = ''; CFN_id = ''; CFN_cn = ''; CFN_cmn = ''; CFN_link = ''; CFN_link_id = ''; id = (CFN_type == 'N') ? CFN_id : CFN_link_id; cyid = (CFN_type == 'C') ? CFN_id : CFN_link_id; name = CFN_cn; isEmpas = ('' == '1'); refererDomain = ''; CFN_cust_tp_cd = ''; CFN_sex_cd = ''; loginType = ''; isMobile = 'F'; CFN_link_cust_tp_cd = ''; CFN_link_stat_cd = ''; var ndrLoginStatus = (isNateLogin) ? 'login' : ((bLogout) ? 'byebye' : 'logout'); try { divReferer(refererDomain); } catch (e) { } try { if (isNateLogin) fillPersonInfo();} catch (e) { } pageEnd('', '/');//]]>
</script></body></html>
Output is truncated. View as a scrollable element or open in a text editor. Adjust cell output settings...
긴 HTML 코드에서 필요한 부분을 추출하여 사용할 때는 BeautifulSoup 객체를 생성한 후, 다음과 같은 함수를 사용하여 데이터를 탐색한다.
# Sample02.html
<html>
<head>
</head>
<body>
<div> 요기를 클릭하세요 </div>
<ul>
<li> 한빛출판네트워크 </li>
<li> 비기너 </li>
<li> 데이터 분석 </li>
</ul>
</body>
</html>
import bs4
webPage = open('Sample02.html', 'rt', encoding='utf-8').read()
bsObject = bs4.BeautifulSoup(webPage, "html.parser")
print(bsObject)
<html>
<head>
</head>
<body>
<div> 요기를 클릭하세요 </div>
<ul>
<li> 한빛출판네트워크 </li>
<li> 비기너 </li>
<li> 데이터 분석 </li>
</ul>
</body>
</html>
- find('태그명'): 조건에 맞는 태그 중 가장 먼저 나오는 1개만 추출한다.
import bs4
webPage = open('Sample02.html', 'rt', encoding='utf-8').read()
bsObject = bs4.BeautifulSoup(webPage, "html.parser")
tag_div = bsObject.find('div')
print(tag_div)
<div> 요기를 클릭하세요 </div>
- find_all('태그명'): 조건에 맞는 모든 태그를 추출하여 리스트 형태로 반환한다.
import bs4
webPage = open('Sample02.html', 'rt', encoding='utf-8').read()
bsObject = bs4.BeautifulSoup(webPage, "html.parser")
tag_ul = bsObject.find('ul')
print(tag_ul)
print()
tag_li = bsObject.find('li')
print(tag_li)
print()
tag_li_all = bsObject.find_all('li')
print(tag_li_all)
<ul>
<li> 한빛출판네트워크 </li>
<li> 비기너 </li>
<li> 데이터 분석 </li>
</ul>
<li> 한빛출판네트워크 </li>
[<li> 한빛출판네트워크 </li>, <li> 비기너 </li>, <li> 데이터 분석 </li>]
- 속성 지정 추출: find('태그명', {'속성명': '속성값'}) 형식을 사용하여 특정 id나 class를 가진 태그만 골라낼 수 있다.
# Sample03.html
<html>
<head>
</head>
<body>
<div id='myId1'> 아기공룡 </div>
<div class='myClass1'> 내 친구 </div>
<ul class='myClass2'>
<li> 한빛아카데미 </li>
<li> 한빛미디어 </li>
</ul>
<a href="www.daum.net"> 다음 바로가기 </a>
<div class='myClass1'> 둘리 </div>
<ul>
<li class='myClass3'> 비기너 </li>
<li class='myClass3'> 시리즈 </li>
</ul>
<a href="www.nate.com"> 네이트 바로가기 </a>
<a href="www.naver.com"> 네이버 바로가기 </a>
</body>
</html>
import bs4
webPage = open('Sample03.html', 'rt', encoding='utf-8').read()
bsObject = bs4.BeautifulSoup(webPage, "html.parser")
tag = bsObject.find('div', {'id': 'myId1'})
print(tag)
print()
tag = bsObject.find('div', {'class': 'myClass1'})
print(tag)
print()
tag = bsObject.find_all('div', {'class': 'myClass1'})
print(tag)
<div id="myId1"> 아기공룡 </div>
<div class="myClass1"> 내 친구 </div>
[<div class="myClass1"> 내 친구 </div>, <div class="myClass1"> 둘리 </div>]
import bs4
webPage = open('Sample03.html', 'rt', encoding='utf-8').read()
bsObject = bs4.BeautifulSoup(webPage, "html.parser")
ul_value = bsObject.find('ul', {'class': 'myClass2'})
print(ul_value)
print()
li_list = bsObject.find('li', {'class': 'myClass3'})
print(li_list)
print()
<ul class="myClass2">
<li> 한빛아카데미 </li>
<li> 한빛미디어 </li>
</ul>
<li class="myClass3"> 비기너 </li>
- tag['속성명'] (예: aTag['href']) 형식을 사용하면 태그가 가진 속성의 값(URL 등)을 가져올 수 있다.
import bs4
webPage = open('Sample03.html', 'rt', encoding='utf-8').read()
bsObject = bs4.BeautifulSoup(webPage, "html.parser")
a_list = bsObject.find_all('a')
for aTag in a_list:
print(aTag['href'])
www.daum.net
www.nate.com
www.naver.com
- 텍스트 및 속성값 가져오기: * .text를 사용하면 태그 내부의 순수한 문자열만 추출된다.
import bs4
webPage = open('Sample03.html', 'rt', encoding='utf-8').read()
bsObject = bs4.BeautifulSoup(webPage, "html.parser")
tag_li_all = bsObject.find_all('li')
print(tag_li_all)
for tag_li in tag_li_all:
print(tag_li.text)
print()
for i in range(len(tag_li_all)):
print(tag_li_all[i].text)
[<li> 한빛아카데미 </li>, <li> 한빛미디어 </li>, <li class="myClass3"> 비기너 </li>, <li class="myClass3"> 시리즈 </li>]
한빛아카데미
한빛미디어
비기너
시리즈
한빛아카데미
한빛미디어
비기너
시리즈
LAB 1: 웹사이트 정보 추출
- 개발자 도구를 사용해서 웹 페이지의 소스 위치를 찾을 수 있다.

- nate 사이트의 로고를 클릭할 때 연결되는 주소 및 로고에 지정된 글자를 추출하는 코드
import urllib.request
import bs4
nateUrl = "https://www.nate.com"
htmlObject = urllib.request.urlopen(nateUrl)
webPage = htmlObject.read()
bsObject = bs4.BeautifulSoup(webPage, "html.parser")
tag = bsObject.find('div', {'id': 'NateBi'})
print(tag, '\n')
a_tag = tag.find("a")
print(a_tag, '\n')
href = a_tag['href']
print(href, '\n')
text = a_tag.text
print(text)
<div class="area_bi" id="NateBi" role="banner">
<h1 class="bi" title="네이트"><a href="//www.nate.com/?f=bi" onmousedown="nc('NBI01');">네이트</a></h1>
</div>
<a href="//www.nate.com/?f=bi" onmousedown="nc('NBI01');">네이트</a>
//www.nate.com/?f=bi
네이트
LAB 2: 웹 사이트 메뉴 목록 가져오기
- 네이트 뉴스 사이트에 접속한 후, 메뉴 영역에 해당하는 <div class="snbArea">를 찾아 그 내부의 모든 하위 메뉴 텍스트를 한 줄로 가져오는 실습이다.


- 웹 페이지 메뉴 알아내기
import urllib.request
import bs4
nateUrl = "https://news.nate.com/"
htmlObject = urllib.request.urlopen(nateUrl)
webPage = htmlObject.read()
bsObject = bs4.BeautifulSoup(webPage, "html.parser")
tag = bsObject.find('div', {'class': 'snbArea'})
print("## 네이트 뉴스의 메뉴 목록 ##")
li_list = tag.find_all('li')
for li in li_list:
print(li.text, end = ' ')
## 네이트 뉴스의 메뉴 목록 ##
홈 최신뉴스 정치 경제 사회 세계 IT/과학 칼럼 포토 TV 라디오 랭킹뉴스 투데이댓글
LAB 3: 시간 간격 크롤러 생성 (날씨 정보 수집)
- 시간에 따라 실시간으로 변하는 데이터를 주기적으로 수집하여 저장하는 심화 응용이다.
- 사용 모듈: 파일 저장을 위한 csv, 지연 시간을 주기 위한 time, 현재 시간을 기록하기 위한 datetime 모듈을 함께 사용한다.
- 동작 방식: while True: 무한 루프를 활용하여 데이터를 요청하고, time.sleep(3600)을 통해 1시간마다 반복 동작하도록 설정한다.
- 동작 방식: while True: 무한 루프를 활용하여 데이터를 요청하고, time.sleep(3600)을 통해 1시간마다 반복 동작하도록 설정한다.

import csv
import time
import datetime
import bs4
import urllib.request
csvName = 'sokcho_weather.csv'
with open(csvName, 'w', newline='', encoding='utf-8') as csvFp:
csvWriter = csv.writer(csvFp)
csvWriter.writerow(['연월일', '시분초', '온도', '습도', '강수량', '풍향'])
nateUrl = "https://news.nate.com/weather?areaCode=11D20401"
while True :
htmlObject = urllib.request.urlopen(nateUrl)
webPage = htmlObject.read()
bsObject = bs4.BeautifulSoup(webPage, "html.parser")
tag = bsObject.find('div', {'class': 'right_today'})
temper = tag.find('p', {'class': 'celsius'}).text
humid = tag.find('p', {'class': 'humidity'}).text
rain = tag.find('p', {'class': 'rainfall'}).text
wind = tag.find('p', {'class': 'wind'}).text
now = datetime.datetime.now()
yymmdd = now.strftime('%Y-%m-%d')
hhmmss = now.strftime('%H:%M:%S')
weather_list = [yymmdd, hhmmss, temper, humid, rain, wind]
with open(csvName, 'a', newline='', encoding='utf-8') as csvFp:
csvWriter = csv.writer(csvFp)
csvWriter.writerow(weather_list)
time.sleep(3600)
# sokcho_weather.csv
연월일,시분초,온도,습도,강수량,풍향
2026-05-27,00:06:58,18℃,습도93%,강수량0.0mm,풍향 북북서 0.8 m/s
2025-1 기말고사

import urllib.request
import bs4
naverUrl = "https://finance.naver.com/marketindex/"
htmlObject = urllib.request.urlopen(naverUrl)
webPage = htmlObject.read().decode('cp949')
bsObject = bs4.BeautifulSoup(webPage, "html.parser")
h_list = bsObject.find_all('h3', {'class': 'h_lst'})
h_texts = []
p_list = bsObject.find_all('span', {'class': 'value'})
p_texts = []
result = {}
for h in h_list:
h_texts.append(h.text)
for p in p_list:
p_texts.append(p.text)
for i in range(0, 4):
result[h_texts[i]] = float(p_texts[i].replace(',', ''))
print(result)
nation = input("원화 입력: ")
price = float(input("금액 입력: "))
src_weight = 100.0 if "100" in nation else 1.0
krw_value = price * (result[nation] / src_weight)
print(f"{nation} {price}")
for key in result.keys():
if key != nation:
print(f"{key} {float(krw_value / result[key]):.4f}")
{'미국 USD': 1506.0, '일본 JPY(100엔)': 945.21, '유럽연합 EUR': 1750.27, '중국 CNY': 221.91}
중국 CNY 1000.0 원
미국 USD 147.3506
일본 JPY(100엔) 234.7732
유럽연합 EUR 126.7862728x90
'4. University Study > Advanced Python Programming' 카테고리의 다른 글
| [Advanced Python Programming] Lecture 16. Web Scrapping (0) | 2026.05.27 |
|---|---|
| [Advanced Python Programming] Lecture 13. Data Visualization (0) | 2026.05.25 |
| [Advanced Python Programming] Lecture 12. Pandas (0) | 2026.05.24 |
| [Advanced Python Programming] 중간고사 암기 (0) | 2026.04.17 |
| [Advanced Python Programming] Lecture 11. Numpy (0) | 2026.04.17 |