[TIL]53. Web_Scraping
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 : νΉμ μμλ₯Ό μ νν μ μλ λ°©λ², λ μ½κ² μνλ μμλ€μ μ νν΄ μ κ·Ό κ°λ₯
- Type selector: CSS νμ μ λ°λΌμ μ νν μ μμ΅λλ€ (μλ₯Ό λ€μ΄ 'p', 'div' λ±)
- Class selector: ν΄λμ€μ λ°λΌ μ νν μ μμ΅λλ€.
- 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μ΄ λ³νκ³ /λ΄μ©λ¬Ό λ¬λΌμ§λ κ²½μ° 'μ μ μ€ν¬λ μ΄ν'