Jayden1116 2022. 1. 27. 01:51

keyword : 크둀링, μ›Ή μŠ€ν¬λ ˆμ΄ν•‘, HTML/CSS/JS, DOM, Request, BeautifulSoup

HTML/CSS/JS

HTML : μ›Ήμ˜ ꡬ쑰λ₯Ό μ„€μ •ν•΄μ£ΌλŠ” μ–Έμ–΄(갖닀놓기)

  • Element : μš”μ†Œ λΌλŠ” 의미둜 head, body, div λ“±κ³Ό 같은 νƒœκ·Έλ‘œ ν‘œν˜„λ˜λ©° ꡬ성 λ‚΄μ—μ„œμ˜ 역할을 λ‚˜νƒ€λ‚΄μ€€λ‹€.(μ›Ή μŠ€ν¬λ ˆμ΄ν•‘ μ‹œ, νƒœκ·Έλ₯Ό 톡해 κ°€μ Έμ˜€λŠ” 방법이 μžˆμœΌλ―€λ‘œ μ•Œμ•„λ‘κΈ°)

  • Parent/Children

<ul>
    <li>Hello</li>
    <li>World</li>
    <li>!</li>
</ul>

ul 은 li 의 μƒμœ„ νƒœκ·Έ, liλŠ” ul의 ν•˜μœ„ νƒœκ·Έ

CSS : HTML에 μ—¬λŸ¬κ°€μ§€ μŠ€νƒ€μΌμ„ λ„£μ–΄μ£ΌλŠ” μ–Έμ–΄(κΎΈλ―Έκ³ )

  • Selector : νŠΉμ • μš”μ†Œλ₯Ό 선택할 수 μžˆλŠ” 방법, 더 μ‰½κ²Œ μ›ν•˜λŠ” μš”μ†Œλ“€μ„ 선택해 μ ‘κ·Ό κ°€λŠ₯

    1. Type selector: CSS νƒ€μž…μ— λ”°λΌμ„œ 선택할 수 μžˆμŠ΅λ‹ˆλ‹€ (예λ₯Ό λ“€μ–΄ 'p', 'div' λ“±)
    2. Class selector: ν΄λž˜μŠ€μ— 따라 선택할 수 μžˆμŠ΅λ‹ˆλ‹€.
    3. Id selector: id 에 따라 선택할 수 μžˆμŠ΅λ‹ˆλ‹€.
  • 상속 : CSSλŠ” μš”μ†Œμ˜ μœ„μΉ˜μ— 따라 μƒμœ„ μš”μ†Œμ˜ μŠ€νƒ€μΌμ„ 상속, 단 μƒμ†λ°›λŠ” 쑰건보닀 본인이 κ°–κ³  μžˆλŠ” 쑰건이 더 μš°μ„ 

<div style="color:red">
    <p>I have no style</p>
</div>
  • 클래슀(μ›Ή μŠ€ν¬λ ˆμ΄ν•‘ μ‹œ μ€‘μš”) : μ–΄λ–€ νŠΉμ • μš”μ†Œλ“€μ˜ μŠ€νƒ€μΌμ„ μ •ν•˜κ³  싢을 λ•Œ μ‚¬μš©, λ™μ‹œμ— μ—¬λŸ¬ 개의 μš”μ†Œλ“€μ— λŒ€ν•œ μŠ€νƒ€μΌμ„ μ •ν•  λ•Œ 클래슀λ₯Ό μ§€μ •ν•˜μ—¬ 상속을 받도둝 함.(ν΄λž˜μŠ€λŠ” . 으둜 ν‘œν˜„ν•©λ‹ˆλ‹€. ex) .banana)
<p class="banana">I have a banana class</p>
<p class="banana fruit orange">I have many classes</p> # μ—¬λŸ¬κ°œμ˜ ν΄λž˜μŠ€λ„ λΆ€μ—¬ κ°€λŠ₯
  • ID : ν΄λž˜μŠ€μ™€ λΉ„μŠ·ν•˜μ§€λ§Œ ν΄λž˜μŠ€κ°€ 집단을 μ„ νƒν•œλ‹€λ©΄, IDλŠ” κ°œλ³„ ν•˜λ‚˜ν•˜λ‚˜λ₯Ό μ§€μ •(IDλŠ” #으둜 ν‘œν˜„ν•©λ‹ˆλ‹€. ex) #pink)
<p id="pink">My id is pink</p>

JS : λ™μž‘μ„ λ‹΄λ‹Ή(μ‹œν‚¨λ‹€)

μ›Ή μŠ€ν¬λ ˆμ΄ν•‘μ„ μœ„ν•΄ 기본적인 μ›Ή ꡬ쑰λ₯Ό μ•„λŠ” 것이 ν•„μš”!! μ›Ήμ—μ„œ F12λ₯Ό 눌러 웹에 μžˆλŠ” 정보가 μ–΄λ–»κ²Œ κ΅¬μ„±λ˜μ–΄μžˆλŠ”μ§€, μœ„μΉ˜λ₯Ό μ•Œ 수 μžˆλ„λ‘ ν•΄μ•Όν•œλ‹€.

DOM(Document Object Model ; λ¬Έμ„œ 객체 λͺ¨λΈ)

DOM은 HTML, XML λ“± λ¬Έμ„œμ˜ ν”„λ‘œκ·Έλž˜λ° μΈν„°νŽ˜μ΄μŠ€λ‘œ ν”„λ‘œκ·Έλž˜λ° μ–Έμ–΄λ₯Ό ν†΅ν•΄μ„œ HTML λ¬Έμ„œ 등에 μ ‘κ·Όν•  수 μžˆλ„λ‘ λ„μ™€μ€λ‹ˆλ‹€.

DOM은 λ¬Έμ„œλ₯Ό ν•˜λ‚˜μ˜ κ΅¬μ‘°ν™”λœ ν˜•μ‹μœΌλ‘œ ν‘œν˜„μ„ ν•˜κΈ° λ•Œλ¬Έμ— μ΄λŸ¬ν•œ ꡬ쑰λ₯Ό μ΄μš©ν•΄μ„œ μ›ν•˜λŠ” λ™μž‘(νŠΉμ • 클래슀, νƒœκ·Έμ˜ 값을 κ°€μ Έμ˜¨λ‹€λ“ μ§€)을 ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

DOM은 μžλ°”μŠ€ν¬λ¦½νŠΈμ—μ„œ μ‚¬μš©λ˜λŠ” 데이터 ꡬ쑰 쀑 ν•˜λ‚˜μΈ 'object'둜 ν‘œν˜„μ„ ν•˜λŠ”λ°, μ΄λŠ” νŒŒμ΄μ¬μ—μ„œμ˜ dictionary와 λΉ„μŠ·ν•œ ν˜•νƒœμž…λ‹ˆλ‹€.

DOM을 톡해 ν”„λ‘œκ·Έλž˜λ° μ–Έμ–΄μ—μ„œ μ‚¬μš©ν•  수 μžˆλŠ” 데이터 ꡬ쑰 ν˜•νƒœλ‘œ μž‘μ—…μ„ μˆ˜ν–‰ν•  수 있기 λ•Œλ¬Έμ— μ›Ή νŽ˜μ΄μ§€λ₯Ό ν†΅ν•œ μž‘μ—…(μŠ€ν¬λ ˆμ΄ν•‘, 크둀링 λ“±)μ—μ„œ 맀우 μ€‘μš”ν•œ κ°œλ…μž…λ‹ˆλ‹€.

DOM λ©”μ†Œλ“œ

  • μ›Ή λΈŒλΌμš°μ €μ—μ„œ 개발자 도ꡬ(F12)λ₯Ό μ—΄μ–΄ μ½˜μ†” 창으둜 λ“€μ–΄κ°€ μžλ°”μŠ€ν¬λ¦½νŠΈλ₯Ό 톡해 μ‚¬μš©ν•΄λ³΄κΈ°
document.querySelectorAll('p')

=> 'p' νƒœκ·Έλ₯Ό μ‚¬μš©ν•˜λŠ” μš”μ†Œλ“€μ„ 담은 μœ μ‚¬ λ°°μ—΄(NodeList)을 λ°›κ²Œ λ©λ‹ˆλ‹€.

  • getElementsbyTagName: νƒœκ·Έ μ΄λ¦„μœΌλ‘œ λ¬Έμ„œμ˜ μš”μ†Œλ“€μ„ λ¦¬ν„΄ν•©λ‹ˆλ‹€.
  • getElementById: 'id' κ°€ μΌμΉ˜ν•˜λŠ” μš”μ†Œλ“€μ„ λ¦¬ν„΄ν•©λ‹ˆλ‹€.
  • getElementsByClassName: '클래슀' κ°€ μΌμΉ˜ν•˜λŠ” μš”μ†Œλ“€μ„ λ¦¬ν„΄ν•©λ‹ˆλ‹€. classλ₯Ό ν†΅ν•œ 호좜이 자주 μ‚¬μš©λ©λ‹ˆλ‹€.
  • querySelector: μ…€λ ‰ν„°(λ“€)κ³Ό μΌμΉ˜ν•˜λŠ” μš”μ†Œλ₯Ό λ¦¬ν„΄ν•©λ‹ˆλ‹€.
  • querySelectorAll: μ…€λ ‰ν„°(λ“€)κ³Ό μΌμΉ˜ν•˜λŠ” λͺ¨λ“  μš”μ†Œλ“€μ„ λ¦¬ν„΄ν•©λ‹ˆλ‹€.

DOM과 크둀링

νŒŒμ΄μ¬μ—μ„œ 크둀링을 ν•˜μ—¬ μ›ΉνŽ˜μ΄μ§€μ˜ 정보λ₯Ό λͺ¨λ‘ str ν˜•νƒœλ‘œ κ°€μ Έμ˜¨λ‹€ν•΄λ„ 이λ₯Ό κ΅¬λΆ„ν•΄μ„œ 데이터λ₯Ό κ°€μ Έμ˜€λŠ” κ²ƒμ—λŠ” ν•œκ³„κ°€ μžˆμŠ΅λ‹ˆλ‹€. μ΄λ•Œ, μ›ΉνŽ˜μ΄μ§€λ₯Ό ν…μŠ€νŠΈ ν˜•μ‹μ΄ μ•„λ‹Œ DOM ν˜•μ‹μœΌλ‘œ ν™œμš©ν•©λ‹ˆλ‹€.

μ˜ˆμ‹œ)

<!DOCTYPE html>
<html>
    <head>
    </head>
    <body>
        <h1>h1 νƒœκ·Έμž…λ‹ˆλ‹€.</h1>
        <p>p νƒœκ·Έμž…λ‹ˆλ‹€.</p>
    </body>
</html>

'h1' νƒœκ·Έμ— ν•΄λ‹Ήν•˜λŠ” λ‚΄μš©μ„ μ•Œκ³  μ‹Άλ‹€λ©΄ DOM을 ν™œμš©ν•©λ‹ˆλ‹€! λ§Œμ•½ μœ„μ˜ 값듀을 κ·Έλƒ₯ λ¬Έμžμ—΄λ‘œ λ°›κ³  κ·Έ 뒀에 νŒŒμ΄μ¬μ—μ„œ μž¬κ΅¬μ‘°ν™”ν•˜λ €λ©΄ λ„ˆλ¬΄ λΉ„νš¨μœ¨μ μ΄κΈ° λ•Œλ¬Έμž…λ‹ˆλ‹€.

μ›Ή μŠ€ν¬λ ˆμ΄ν•‘/크둀링

μŠ€ν¬λ ˆμ΄ν•‘ : 긁어λͺ¨μœΌκΈ° -> μ›Ήμ—μ„œ νŠΉμ • 정보λ₯Ό κ°€μ Έμ˜€λŠ” 것이 λͺ©μ 

  • μ›Ήμ—μ„œ 데이터λ₯Ό μΆ”μΆœν•˜λŠ” 것뿐 μ•„λ‹ˆλΌ ꡬ쑰λ₯Ό λΆ„μ„ν•˜λŠ” λ•Œμ—λ„ μ‚¬μš©ν•©λ‹ˆλ‹€.

크둱링 : μ›Ή(Web)μ΄λž€ 거미쀄을 κΈ°μ–΄λ‹€λ‹ˆκΈ° -> μΈν„°λ„·μ˜ μ‚¬μ΄νŠΈλ“€μ„ μΈλ±μ‹±ν•˜λŠ” λͺ©μ 

  • ν”„λ‘œκ·Έλž¨μ΄ μ›Ή μ‚¬μ΄νŠΈλ₯Ό μ •κΈ°μ μœΌλ‘œ 돌며 정보λ₯Ό μΆ”μΆœν•˜λŠ” 기술, 이 λ•Œ 이 ν”„λ‘œκ·Έλž¨μ„ '크둀러', 'μŠ€νŒŒμ΄λ”'라고 ν•©λ‹ˆλ‹€.

requests 라이브러리

μ›Ήκ³Ό νŽΈν•˜κ²Œ μ†Œν†΅ν•˜κ²Œ ν•΄μ£ΌλŠ” 라이브러리둜 νŒŒμ΄μ¬μ—μ„œ HTTP μš”μ²­μ„ 보낼 λ•Œ μ‚¬μš©ν•©λ‹ˆλ‹€.

$ pip install requests
import requests
requests.get('https://google.com') # <Response [200]> κ³Ό 같은 HTTP 응닡 객체가 λ¦¬ν„΄λ©λ‹ˆλ‹€. (μ„œλ²„μ— μ—°κ²°ν•  수 μ—†λ‹€λ©΄ 404)

보톡 μ•„λž˜μ™€ 같이 μ‚¬μš©ν•©λ‹ˆλ‹€.


import requests

url = 'https://google.com'

resp = requests.get(url)

resp.status_code # μ‘λ‹΅μ˜ μƒνƒœ μ½”λ“œλ₯Ό 확인 (μˆ«μžκ°€ λ‚˜μ˜΄)

μ‘λ‹΅μ˜ 성곡여뢀λ₯Ό μƒνƒœ λ©”μ‹œμ§€μ™€ 번호λ₯Ό λΆ€μ—¬ν•˜μ—¬ ν‘œν˜„ν•©λ‹ˆλ‹€.

  • 200은 성곡을 μ˜λ―Έν•˜κ³ , μ›Ή νŽ˜μ΄μ§€λ₯Ό 찾을 수 없을 λ•ŒλŠ” 404둜 ν‘œν˜„λ©λ‹ˆλ‹€.

200이 성곡이, 404은 μ‹€νŒ¨κ³  λ“± 보닀 더 μ€‘μš”ν•œ 것은 κ²°κ΅­, μ›Ή νŽ˜μ΄μ§€λ₯Ό λ¬΄μ‚¬νžˆ λ°›μ•˜λŠλƒ μž…λ‹ˆλ‹€.

import requests
from requests.exceptions import HTTPError

url = 'https://google.com'

try:
    resp = requests.get(url)

    resp.raise_for_status()
except HTTPError as Err:
    print('HTTP μ—λŸ¬κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€.')
except Exception as Err:
    print('λ‹€λ₯Έ μ—λŸ¬κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€.')
else:
    print('성곡')

μœ„μ™€ 같은 μ½”λ“œλ₯Ό 톡해 HTTP μš”μ²­ μ‹œ 성곡 유무λ₯Ό νŒλ‹¨ κ°€λŠ₯ν•©λ‹ˆλ‹€.
HTTPλ₯Ό μš”μ²­ν•˜λŠ” 것이 μŠ€ν¬λ ˆμ΄ν•‘, 크둀링의 κΈ°λ³Έμž…λ‹ˆλ‹€.

μ›Ή λΈŒλΌμš°μ €λŠ” κ²°κ΅­ 길게 μ£Όμ–΄μ§„ HTML을 μš°λ¦¬κ°€ 보기 νŽΈν•˜κ²Œ ν•΄μ£ΌλŠ” μ—­ν• μž…λ‹ˆλ‹€.
이 λ•Œ, requests 라이브러리λ₯Ό 톡해 μ›Ή λΈŒλΌμš°μ €κ°€ λ°›λŠ” λ™μΌν•œ HTML λ¬Έμ„œλ₯Ό 받을 수 μžˆμŠ΅λ‹ˆλ‹€.

resp = requests.get(url)
resp.text

BeautifulSoup 라이브러리

μ΄μ œλŠ” λŒλ €λ°›μ€ 응닡 λ‚΄μš©μ„ νŒŒμ‹±ν•˜κ³  정보λ₯Ό μ–»μ–΄λ‚Ό 수 μžˆμ–΄μ•Όν•©λ‹ˆλ‹€.(λ‹¨μˆœ λ¬Έμžμ—΄μ΄ μ•„λ‹Œ DOM ν˜•νƒœλ‘œ λ Œλ”λ§(λ°”κΏ”μ£ΌλŠ” μž‘μ—…))

pip install beautifulsoup4

import requests
from bs4 import BeautifulSoup

url = 'https://google.com'
page = requests.get(url)

soup = BeautifulSoup(page.content, 'html.parser')

즉, requests 라이브러리둜 λ¨Όμ € νŒŒμ‹±ν•  νŽ˜μ΄μ§€λ₯Ό λ°›μ•„μ˜¨ ν›„ λ¬Έμžμ—΄λ‘œ λ³€ν™˜ν•˜κ³  νŒŒμ„œλ₯Ό μ΄μš©ν•˜μ—¬ DOM ν˜•νƒœμ˜ soup을 λ§Œλ“€μ–΄μ€λ‹ˆλ‹€.
기본적으둜 'html.parser'λ₯Ό 주둜 μ‚¬μš©ν•˜κ³  λ‹€λ₯Έ νŒŒμ„œλŠ” μ—¬κΈ° μ°Έμ‘°

μš”μ†Œ μ°ΎκΈ°

find와 find_all (맀우 맀우 μ€‘μš”! μ •ν™•νžˆ μ΄ν•΄ν•˜κ³  있기)

  • find : bs4μ—μ„œ 1개의 μš”μ†Œλ₯Ό 찾을 λ•Œ μ‚¬μš©, 쑰건에 μΌμΉ˜ν•˜λŠ” 첫번째 κ²°κ³Όλ₯Ό 리턴
  • find_all : μ—¬λŸ¬ 개의 μš”μ†Œλ₯Ό 찾을 λ•Œ μ‚¬μš©, 쑰건에 μΌμΉ˜ν•˜λŠ” λͺ¨λ“  κ²°κ³Όλ₯Ό λ¦¬μŠ€νŠΈμ— λ‹΄μ•„ 리턴
dog_element = soup.find(id='dog')
cat_elements = soup.find_all(class_='cat')

idλŠ” 주둜 λ‹¨μΌκ°μ²΄μ΄λ―€λ‘œ findλ₯Ό μ‚¬μš©ν•˜κ³  classλŠ” μ—¬λŸ¬ 객체가 λͺ¨μ—¬μžˆμœΌλ―€λ‘œ find_all을 μ‚¬μš©ν•©λ‹ˆλ‹€.
주의) μœ„μ—μ„œ class_ 둜 μ‚¬μš©ν•œ 것은 파이썬의 class와 ꡬ뢄 μ§“κΈ° μœ„ν•¨μž…λ‹ˆλ‹€.

ν™œμš©)

cat_elements = soup.find_all(class_='cat')

for cat_el in cat_elements:
    cat_el.find(class_='fish') # cat_el[0], cat_el[1] λ“±μœΌλ‘œλ„ κ°€λŠ₯

νƒœκ·Έμ™€ 클래슀 λ™μ‹œ ν™œμš©)

cat_div_elements = soup.find_all('div', class_='cat') # 'div' νƒœκ·Έλ₯Ό κ°€μ§€λ©΄μ„œ λ™μ‹œμ— 'cat' 클래슀인 경우

string ν™œμš©)

  • μ–΄λ–€ νŠΉμ •ν•œ 글이 λ“€μ–΄κ°€ μžˆλŠ”μ§€ 보고싢을 λ•Œμ˜ κ²½μš°μž…λ‹ˆλ‹€.
soup.find_all(string='raining')
soup.find_all(string=lambda text: 'raining' in text.lower()) # 'raining'이 λŒ€μ†Œλ¬Έμž ꡬ뢄없이 μ°Ύκ³  싢을 λ•Œ

string 을 μ‚¬μš©ν•˜λ©΄ μ›ν•˜λŠ” 정보λ₯Ό 찾을 μˆ˜λŠ” μžˆμ§€λ§Œ 각 μš”μ†Œμ˜ .string 속성을 λΆˆλŸ¬μ˜€λŠ” 것이기 λ•Œλ¬Έμ— μš”μ†Œκ°€ μ•„λ‹Œ λ¬Έμžμ—΄λ‘œ 리턴이 λ©λ‹ˆλ‹€. λ”°λΌμ„œ ν•˜λ‚˜μ˜ μš”μ†Œλ‘œ λ°›κΈ° μœ„ν•΄μ„œλŠ” νƒœκ·Έλ„ 같이 μΆ”κ°€ν•΄μ€˜μ•Ό ν•©λ‹ˆλ‹€.

soup.find_all('h3', string='raining') # νƒœκ·Έλ„ 같이 μ μš©ν•΄μ•Ό ν•˜λ‚˜μ˜ μš”μ†Œλ‘œ 값을 받을 수 μžˆμŠ΅λ‹ˆλ‹€.

정보얻기)

<p class='cat'>This is a p-cat</p>

cat_el = soup.find('p', class_='cat')
cat_el.text #=> 'This is a p-cat'

cat_el.text.strip() # λΆˆν•„μš”ν•œ 띄어쓰기가 μžˆμ„ λ•Œ 정리λ₯Ό μœ„ν•΄ μ‚¬μš©
cat_el.text.split() # λ°›μ•„μ˜¨ λ¬Έμžμ—΄μ„ μ–΄λ–€ 기쀀에 따라 λ‚˜λˆ μ€˜μ•Όν•  λ•Œ μ‚¬μš© (자주 μ‚¬μš©ν•˜κ²Œ λœλ‹€)

+심화

정적 μŠ€ν¬λ ˆμ΄ν•‘ vs 동적 μŠ€ν¬λ ˆμ΄ν•‘
그리고
μ›Ή 슀크둀 내렸을 λ•Œ, url은 κ·ΈλŒ€λ‘œ/λ‚΄μš©λ¬Ό λ‹¬λΌμ§€λŠ” 경우 '동적 μŠ€ν¬λ ˆμ΄ν•‘' ~~ 크둀링
μ›Ή 슀크둀 μ˜¬μ•˜μ„ λ•Œ, url이 λ³€ν•˜κ³ /λ‚΄μš©λ¬Ό λ‹¬λΌμ§€λŠ” 경우 '정적 μŠ€ν¬λ ˆμ΄ν•‘'