๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
Python

[python] ๋ฐ์ดํ„ฐ ์ˆ˜์ง‘ - ์›น ํฌ๋กค๋ง

by clolee 2025. 3. 25.

 

๐Ÿ“Š ๋ฐ์ดํ„ฐ ๊ตฌ๋ถ„

  • ๋‚ด๋ถ€ ๋ฐ์ดํ„ฐ: ๋‚ด๊ฐ€ ์ง์ ‘ ๋งŒ๋“  ๋ฐ์ดํ„ฐ, ๋กœ์ปฌ์— ์ €์žฅ๋œ ํŒŒ์ผ ๋“ฑ
  • ์™ธ๋ถ€ ๋ฐ์ดํ„ฐ: ์›น์—์„œ ์ˆ˜์ง‘ํ•˜๊ฑฐ๋‚˜ ์™ธ๋ถ€ API๋กœ ๋ฐ›์•„์˜ค๋Š” ๋ฐ์ดํ„ฐ (โ†’ ์›น ํฌ๋กค๋ง, API ์š”์ฒญ ๋“ฑ ํ™œ์šฉ)

๐ŸŒ ์›น ๋ฐ์ดํ„ฐ ์ˆ˜์ง‘ (์›น ํฌ๋กค๋ง)

โ— ์›น ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ง‘ํ•  ๋•Œ๋Š” ๋ฐ˜๋“œ์‹œ ๊ณต๊ฐœ๋œ ๋ฐ์ดํ„ฐ๋งŒ ์ˆ˜์ง‘ํ•ด์•ผ ํ•จ.
๋กœ๊ทธ์ธํ•ด์•ผ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ ํŽ˜์ด์ง€, ์ €์ž‘๊ถŒ ์žˆ๋Š” ์ฝ˜ํ…์ธ ๋ฅผ ๋ฌด๋‹จ์œผ๋กœ ๊ธ๋Š” ๊ฑด ๋ถˆ๋ฒ•์ผ ์ˆ˜ ์žˆ์Œ.

 

- ๋Œ€๋ถ€๋ถ„์˜ ์›น์‚ฌ์ดํŠธ๋Š” robots.txt์— ํฌ๋กค๋ง ํ—ˆ์šฉ/๋น„ํ—ˆ์šฉ ๊ฒฝ๋กœ๋ฅผ ๋ช…์‹œํ•จ

   https://์›น์‚ฌ์ดํŠธ์ฃผ์†Œ/robots.txt ํ™•์ธ

- API๊ฐ€ ์žˆ๋‹ค๋ฉด ํฌ๋กค๋ง๋ณด๋‹ค API ์‚ฌ์šฉ์ด ๋” ์•ˆ์ „ํ•˜๊ณ  ํ•ฉ๋ฒ•์ ์ž„

โœ… ์ˆ˜์ง‘ ๋Œ€์ƒ ์˜ˆ์‹œ

  • ๊ณต๊ฐœ๋œ XML, JSON, CSV ํฌ๋งท ๋ฐ์ดํ„ฐ
  • ๊ณต๊ณต ๋ฐ์ดํ„ฐ ํฌํ„ธ API
  • HTML ํŽ˜์ด์ง€์—์„œ ํŠน์ • ์ •๋ณด๋งŒ ์ถ”์ถœ

 

 


โœ… ์‚ฌ์šฉ ๊ธฐ์ˆ  ์Šคํƒ

  • requests: ์›น ์š”์ฒญ์„ ๋ณด๋‚ด๊ณ  ์‘๋‹ต์„ ๋ฐ›๊ธฐ ์œ„ํ•œ ๊ธฐ๋ณธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
  • BeautifulSoup(bs4): HTML์„ ๊ตฌ์กฐํ™”ํ•ด์„œ ํŒŒ์‹ฑํ•˜๊ธฐ ์œ„ํ•œ ๋„๊ตฌ
  • selenium: ๋ธŒ๋ผ์šฐ์ € ์ž๋™ํ™” ๋„๊ตฌ โ†’ ์—ฌ๊ธฐ์„  ์‚ฌ์šฉํ•˜์ง€ ์•Š์Œ (๋ณดํ†ต ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๊ธฐ๋ฐ˜ ํŽ˜์ด์ง€์— ํ•„์š”ํ•จ)

selenium ์–ธ์ œ ์‚ฌ์šฉ ?


  
๐Ÿ“Œ Selenium: ๋ธŒ๋ผ์šฐ์ € ์ž๋™ํ™” ๋„๊ตฌ
- ๋‚ด๊ฐ€ ์›ํ•˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์–ป๊ธฐ ์œ„ํ•ด **๋ธŒ๋ผ์šฐ์ € ์ ‘์†/๋กœ๊ทธ์ธ/ํด๋ฆญ/์ž…๋ ฅ** ๋“ฑ์˜ ์ž๋™ํ™” ํ•„์š”ํ•  ๋•Œ ์‚ฌ์šฉ
- ๋กœ๊ทธ์ธ ํ›„ ์ฝ˜ํ…์ธ , ๋ฒ„ํŠผ ํด๋ฆญํ•ด์•ผ ๋ณด์ด๋Š” ๋ฐ์ดํ„ฐ, JS๋กœ ์ƒ์„ฑ๋˜๋Š” ๋ฐ์ดํ„ฐ ๋“ฑ์— ์ ํ•ฉ
- ๋‹จ์ˆœ HTML ๊ธ๊ธฐ์—๋Š” ๋น„ํšจ์œจ์ 
๐ŸŸข ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ: ๋กœ๊ทธ์ธ ํ•„์š”, ๋ฒ„ํŠผ ํด๋ฆญ ๋“ฑ ์‚ฌ์šฉ์ž ํ–‰๋™ ํ•„์š”
๐Ÿ”ด ์‚ฌ์šฉ ์•ˆ ํ•˜๋Š” ๊ฒฝ์šฐ: HTML๋งŒ ์žˆ๊ฑฐ๋‚˜, API๋กœ ๋ฐ์ดํ„ฐ ์ œ๊ณต๋˜๋Š” ๊ฒฝ์šฐ

 

๋”๋ณด๊ธฐ

 

โœ… Selenium์ด๋ž€?

Selenium์€ ์‚ฌ๋žŒ์ฒ˜๋Ÿผ ์›น ๋ธŒ๋ผ์šฐ์ €๋ฅผ ์ž๋™์œผ๋กœ ์กฐ์ž‘ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ๋„๊ตฌ์˜ˆ์š”.
๋ธŒ๋ผ์šฐ์ € ์—ด๊ธฐ, ๋กœ๊ทธ์ธ ์ž…๋ ฅ, ๋ฒ„ํŠผ ํด๋ฆญ, ํŽ˜์ด์ง€ ์ด๋™, ์ •๋ณด ๋ณต์‚ฌ๊นŒ์ง€ ๋ชจ๋‘ ์ž๋™์œผ๋กœ ํ•  ์ˆ˜ ์žˆ์ฃ .


๐Ÿ“Œ Selenium์€ ์–ธ์ œ ์‚ฌ์šฉํ•˜๋Š”๊ฐ€?

1. ์ผ๋ฐ˜์ ์ธ ์›น ํฌ๋กค๋Ÿฌ๋กœ๋Š” ์•ˆ ๋  ๋•Œ

  • ๋กœ๊ทธ์ธ ํ›„์—๋งŒ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ ๋ฐ์ดํ„ฐ
  • ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ(JS)๋กœ ๋™์ ์œผ๋กœ ๋กœ๋”ฉ๋˜๋Š” ์ฝ˜ํ…์ธ  (ex. ์Šคํฌ๋กคํ•ด์•ผ ๋ณด์ด๋Š” ๊ฒŒ์‹œ๊ธ€, ๋ฒ„ํŠผ ๋ˆ„๋ฅด๋ฉด ์—ด๋ฆฌ๋Š” ์ •๋ณด ๋“ฑ)
  • ๋ฐ์ดํ„ฐ๊ฐ€ HTML์— ๋ฐ”๋กœ ์•ˆ ๋ณด์ด๊ณ , ๋ฒ„ํŠผ์„ ํด๋ฆญํ•ด์•ผ ์ƒ๊ธฐ๋Š” ๊ฒฝ์šฐ

๐Ÿ“ ์˜ˆ:

๋„ค์ด๋ฒ„์— ๋กœ๊ทธ์ธํ•ด์„œ ๋‚ด ๋ฉ”์ผํ•จ์„ ํฌ๋กค๋งํ•˜๊ฑฐ๋‚˜,

์‡ผํ•‘๋ชฐ์—์„œ ๋กœ๊ทธ์ธ ํ›„ ์žฅ๋ฐ”๊ตฌ๋‹ˆ/๊ตฌ๋งค์ด๋ ฅ ํŽ˜์ด์ง€์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์–ป๊ณ  ์‹ถ์„ ๋•Œ.


2. ์‚ฌ๋žŒ์ฒ˜๋Ÿผ ํ–‰๋™ํ•ด์•ผ ํ•  ๋•Œ

  • ๋‹จ์ˆœํžˆ HTML ๊ฐ€์ ธ์˜ค๋Š” ์ˆ˜์ค€์ด ์•„๋‹ˆ๋ผ,
    ๋ฒ„ํŠผ ํด๋ฆญ โ†’ ๋Œ€๊ธฐ โ†’ ๋‹ค์Œ ํŽ˜์ด์ง€๋กœ ์ด๋™ โ†’ ํผ ์ž…๋ ฅ โ†’ ์ œ์ถœ ๋“ฑ์˜ ํ๋ฆ„์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ

๐Ÿ“ ์˜ˆ:

์„ค๋ฌธ์กฐ์‚ฌ ์ž๋™ ์ œ์ถœ, ์ƒํ’ˆ ์ž๋™ ์ฃผ๋ฌธ, ์ •ํ•ด์ง„ ์‹œ๊ฐ„์— ์ถœ์„์ฒดํฌ ๋“ฑ


3. ํ…Œ์ŠคํŠธ ์ž๋™ํ™” ์šฉ๋„

  • ์›น ์„œ๋น„์Šค๋ฅผ ๋งŒ๋“ค๊ณ  ๋‚˜์„œ, ์‚ฌ๋žŒ์ด ์ง์ ‘ ๋ˆŒ๋Ÿฌ๋ณด๋ฉฐ ํ…Œ์ŠคํŠธํ•˜๋Š” ๋Œ€์‹ ,
    Selenium์œผ๋กœ ํ…Œ์ŠคํŠธ ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ์งœ์„œ ์ž๋™ํ™”ํ•จ

๐Ÿ“ ์˜ˆ:

"ํšŒ์›๊ฐ€์ž… โ†’ ๋กœ๊ทธ์ธ โ†’ ๋กœ๊ทธ์•„์›ƒ" ์ „์ฒด ํ๋ฆ„ ํ…Œ์ŠคํŠธ ์ž๋™ํ™”


๐Ÿ” Selenium์ด ์ž˜ ์•ˆ ๋งž๋Š” ์ƒํ™ฉ์€?

์ƒํ™ฉ  ๋Œ€์•ˆ ๋„๊ตฌ
๋‹จ์ˆœํžˆ HTML ์ฝ”๋“œ๋งŒ ๊ฐ€์ ธ์˜ค๋ฉด ๋˜๋Š” ์‚ฌ์ดํŠธ requests, BeautifulSoup, httpx ๋“ฑ
API๋กœ ๊น”๋”ํ•˜๊ฒŒ ๋ฐ์ดํ„ฐ ์ œ๊ณตํ•˜๋Š” ๊ฒฝ์šฐ requests + JSON ํŒŒ์‹ฑ
๋Œ€์šฉ๋Ÿ‰ ๋ฐ์ดํ„ฐ๋ฅผ ๋น ๋ฅด๊ฒŒ ์ˆ˜์ง‘ํ•ด์•ผ ํ•  ๊ฒฝ์šฐ Headless ํฌ๋กค๋Ÿฌ (Scrapy, Playwright ๋“ฑ)

๐Ÿง  ์ •๋ฆฌ ์š”์•ฝ

์ƒํ™ฉ  Selenium ์‚ฌ์šฉ ์—ฌ๋ถ€
๋กœ๊ทธ์ธ ํ•„์š” โœ… Yes
๋ฒ„ํŠผ ํด๋ฆญ/JS ๋กœ๋”ฉ ํ•„์š” โœ… Yes
๋‹จ์ˆœ HTML ๊ธ๊ธฐ โŒ No
๋ฐ์ดํ„ฐ๊ฐ€ API๋กœ ์ œ๊ณต๋จ โŒ No
์‚ฌ์šฉ์ž ํ…Œ์ŠคํŠธ ์‹œ๋‚˜๋ฆฌ์˜ค ํ•„์š” โœ… Yes

 

 


๐Ÿ“ฅ ์ˆ˜์ง‘ ํ๋ฆ„ ์š”์•ฝ

  1. requests๋กœ HTML ์š”์ฒญ ๋ณด๋‚ด๊ธฐ

  
import requests
response = requests.get("https://example.com")
  1. ์ •์ƒ ์‘๋‹ต ์ฝ”๋“œ ํ™•์ธ

  
response.status_code == 200 # ์ •์ƒ์ ์ธ ์‘๋‹ต ํ™•์ธ
  1. BeautifulSoup์œผ๋กœ HTML ํŒŒ์‹ฑ

  
from bs4 import BeautifulSoup
soup = BeautifulSoup(response.text, 'html.parser')
# HTML ํ…์ŠคํŠธ๋ฅผ ํƒœ๊ทธ ๊ตฌ์กฐ๋กœ ๋ฐ”๊ฟ”์คŒ

๐Ÿ” ์›ํ•˜๋Š” ํƒœ๊ทธ ์ถ”์ถœํ•˜๊ธฐ

๐Ÿ“Œ find() / find_all() ๋ฉ”์„œ๋“œ

  • find(): ์กฐ๊ฑด์— ๋งž๋Š” ์ฒซ ๋ฒˆ์งธ ํƒœ๊ทธ ํ•˜๋‚˜๋งŒ ๋ฐ˜ํ™˜
  • find_all(): ์กฐ๊ฑด์— ๋งž๋Š” ์—ฌ๋Ÿฌ ํƒœ๊ทธ๋ฅผ ๋ฆฌ์ŠคํŠธ๋กœ ๋ฐ˜ํ™˜

โœ… ํƒœ๊ทธ ์ด๋ฆ„ + ์†์„ฑ์œผ๋กœ ์ฐพ๊ธฐ


  
soup.find(name="div", attrs={"class": "title"})
  • name: ์ฐพ๊ณ  ์‹ถ์€ ํƒœ๊ทธ ์ด๋ฆ„ (div, a, span ๋“ฑ)
  • attrs: ์†์„ฑ ์กฐ๊ฑด (์˜ˆ: ํด๋ž˜์Šค ์ด๋ฆ„, ์•„์ด๋”” ๋“ฑ)

๐Ÿท๏ธ ํƒœ๊ทธ์—์„œ ์ •๋ณด ์ถ”์ถœํ•˜๊ธฐ

0. ํ…์ŠคํŠธ๋งŒ ๋ฝ‘๊ธฐ

ํƒœ๊ทธ ์•ˆ์˜ ์ˆœ์ˆ˜ ํ…์ŠคํŠธ๋งŒ ๊ฐ€์ ธ์˜ค๊ณ  ์‹ถ์„ ๋•Œ


  
tag.text

1. ์†์„ฑ๊ฐ’ ์ถ”์ถœํ•˜๊ธฐ

์˜ˆ: <a href="๋งํฌ์ฃผ์†Œ">์—์„œ ๋งํฌ๋งŒ ๊ฐ€์ ธ์˜ค๊ณ  ์‹ถ์„ ๋•Œ


  
tag.attrs["href"]

๐Ÿ” ๋ฐ˜๋ณต๋ฌธ์œผ๋กœ ๋‹ค์ˆ˜์˜ ํƒœ๊ทธ ์ฒ˜๋ฆฌ

find_all()๋กœ ์ฐพ์€ ์—ฌ๋Ÿฌ ํƒœ๊ทธ์—์„œ ๋ฐ˜๋ณต๋ฌธ์„ ๋Œ๋ฉฐ ์›ํ•˜๋Š” ์ •๋ณด๋ฅผ ์ˆ˜์ง‘ํ•จ


  
results = []
for tag in soup.find_all(name="div", attrs={"class": "item"}):
title = tag.text
link = tag.attrs["data-url"]
results.append([title, link])

๐Ÿงพ ๋ฐ์ดํ„ฐํ”„๋ ˆ์ž„์œผ๋กœ ์ •๋ฆฌ

Pandas์˜ DataFrame์œผ๋กœ ์ €์žฅํ•˜๋ฉด

  • ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ํ–‰/์—ด ๊ตฌ์กฐ๋กœ ์ •๋ฆฌํ•  ์ˆ˜ ์žˆ๊ณ 
  • ์—‘์…€ ์ €์žฅ, DB ์ €์žฅ, ๋ถ„์„ ๋“ฑ์— ํ™œ์šฉํ•˜๊ธฐ ์‰ฌ์›€

  
import pandas as pd
df = pd.DataFrame(results, columns=["์ œ๋ชฉ", "๋งํฌ"])

 

๋Œ“๊ธ€