[Data Mining] Getting Data Part.1
Getting Data
from collections import Counter
import math, random, csv, json, re
from bs4 import BeautifulSoup
import requests
์๋ฅผ ๋ค์ด, beautifulsoup ๊ฐ์, ์ด๋ค ๋ชจ๋์ด ์ค์น๋์ง ์์๋ค๋ฉด? ์ด๋ป๊ฒ ํด์ผ ํ ๊น์?
- googling: ์๋์ฝ๋ค beautifulsoup ์ค์น ๋ฐฉ๋ฒ
- ๊ตฌ๊ธ ๋ต๋ณ์์ ์๋์ฝ๋ค ํด๋ผ์ฐ๋๋ฅผ ์ฐพ์ผ์ธ์. ๋ชจ๋๋ค์ด ํ ์คํธ๋๊ณ ์์ ํ ๊ณณ์ ๋๋ค.
- ์ด์ , ์ฌ๋ฌ๋ถ์ ๋ถ๋๋ฌ์ด ์ ๋๋ก ๋ง์ ์๊ฐ์ acquiring(ํ๋), cleaning(์ ๋ฆฌ), and transforming data(๋ฐ์ดํฐ ๋ณํ)์ ํ ์ ํ๊ฒ ๋ ๊ฒ์ ๋๋ค.
stdin and stdout
Number of lines containing numbers
์ซ์๊ฐ ํฌํจ๋ ํ์ผ์ ํ ์๋ฅผ ์ ์ ์์ต๋๋ค.
sys.stdin(Keyboard) ๋ฐ sys.stdout(Monitor)์ ์ฌ์ฉํ์ฌ ๋ฐ์ดํฐ๋ฅผ ํ์ดํํ ์ ์์ต๋๋ค.
import sys, re
# sys.argv๋ ๋ช
๋ น์ค ์ธ์์ ๋ฆฌ์คํธ์
๋๋ค.
# sys.argv[0]์ ํ๋ก๊ทธ๋จ ์์ฒด์ ์ด๋ฆ์
๋๋ค.
# sys.argv[1]์ ๋ช
๋ น์ค์์ ์ง์ ํ ์ ๊ท ํํ์์ด ๋ ๊ฒ์
๋๋ค.
regex = sys.argv[1]
# ์คํฌ๋ฆฝํธ์ ์ ๋ฌ๋ ๊ฐ ์ค์ ๋ํด
for line in sys.stdin:
# ๋ง์ฝ ์ ๊ท ํํ์๊ณผ ์ผ์นํ๋ ๊ฒฝ์ฐ, ๊ทธ๊ฒ์ stdout์ ์๋๋ค.
if re.search(regex, line): # Regular Expression๊ณผ ๋ง๋ ๋ผ์ธ
sys.stdout.write(line)
- ๋ช ๋ น์ค์์ ์ฌ์ฉ์๊ฐ ์ง์ ํ ์ ๊ท ํํ์์ ์ด์ฉํ์ฌ ์ ๋ ฅ์ผ๋ก ๋ฐ์ ๊ฐ ์ค์ ๋ํด ๊ฒ์ํ๊ณ , ํด๋น ์ ๊ท ํํ์๊ณผ ์ผ์นํ๋ ๊ฒฝ์ฐ ํด๋น ์ค์ ํ์ค ์ถ๋ ฅ์ ์๋๋ค.
import sys
count = 0
# sys.stdin์์ ๊ฐ ์ค์ ์ฝ์ด๋ค์ฌ์
for line in sys.stdin:
# count ๋ณ์๋ฅผ ์ฆ๊ฐ์ํต๋๋ค.
count += 1
# print ํจ์๋ sys.stdout์ ์ถ๋ ฅ๋ฉ๋๋ค.
print(count)
0
# Windows
!type the_bible.txt | python egrep.py "[0-9]" | python line_count.py
/bin/bash: line 1: type: the_bible.txt: not found
python3: can't open file '/content/egrep.py': [Errno 2] No such file or directory
python3: can't open file '/content/line_count.py': [Errno 2] No such file or directory
Most Common Words
์ ๋ ฅ๋ ๋จ์ด๋ฅผ ์ธ์ด ๊ฐ์ฅ ์ผ๋ฐ์ ์ธ ๋จ์ด๋ฅผ ์์ฑํ๋ ์คํฌ๋ฆฝํธ ์ ๋๋ค.
import sys
from collections import Counter
# ์ฒซ ๋ฒ์งธ ์ธ์๋ก ๋จ์ด์ ์๋ฅผ ์ ๋ฌํฉ๋๋ค.
try:
num_words = int(sys.argv[1]) # ๋ช
๋ น์ด argument -> Command
except:
print("usage: most_common_words.py num_words")
sys.exit(1) # ๋น์ ์์ ์ข
๋ฃ ์ฝ๋๋ ์ค๋ฅ๋ฅผ ๋ํ๋
๋๋ค.
# ํ์ค ์
๋ ฅ์์ ๊ฐ ์ค์ ์ฝ์ด๋ค์ฌ์
# ์๋ฌธ์๋ก ๋ณํํ ๋จ์ด๋ฅผ ์นด์ดํธํฉ๋๋ค.
counter = Counter(word.lower() # ์๋ฌธ์๋ก ๋ณํ๋ ๋จ์ด
for line in sys.stdin # ํ์ค ์
๋ ฅ์ผ๋ก๋ถํฐ์ ๊ฐ ์ค
for word in line.strip().split() # ๊ณต๋ฐฑ์ผ๋ก ๋ถ๋ฆฌ๋ ๋จ์ด๋ค
if word) # ๋น '๋จ์ด'๋ ๊ฑด๋๋๋๋ค.
# ๊ฐ์ฅ ๋น๋๊ฐ ๋์ ๋จ์ด๋ฅผ ์ฐพ์ ์ถ๋ ฅํฉ๋๋ค.
for word, count in counter.most_common(num_words):
sys.stdout.write(str(count)) # ๋น๋๋ฅผ ์ถ๋ ฅํฉ๋๋ค.
sys.stdout.write("\\t") # ํญ ๋ฌธ์๋ก ๊ตฌ๋ถํฉ๋๋ค.
sys.stdout.write(word) # ๋จ์ด๋ฅผ ์ถ๋ ฅํฉ๋๋ค.
sys.stdout.write("\\n") # ์ค ๋ฐ๊ฟ ๋ฌธ์๋ก ์ค์ ๋ฐ๊ฟ๋๋ค.
# Windows
!type the_bible.txt | python most_common_words.py 10
64193 the
51380 and
34753 of
13643 to
12799 that
12560 in
10263 he
9840 shall
8987 unto
8836 for
Reading Files
The Basics of Text Files
# 'r'์ ์ฝ๊ธฐ ์ ์ฉ์ ์๋ฏธํฉ๋๋ค.
file_for_reading = open('reading_file.txt', 'r')
# 'w'๋ ์ฐ๊ธฐ๋ฅผ ์๋ฏธํฉ๋๋ค — ์ด๋ฏธ ํ์ผ์ด ์กด์ฌํ๋ฉด ํ์ผ์ ํ๊ดดํฉ๋๋ค!
file_for_writing = open('writing_file.txt', 'w')
# 'a'๋ ์ถ๊ฐ๋ฅผ ์๋ฏธํฉ๋๋ค — ํ์ผ ๋์ ์ถ๊ฐํฉ๋๋ค.
file_for_appending = open('appending_file.txt', 'a')
# ํ์ผ์ ์ฌ์ฉํ ํ์๋ ํ์ผ์ ๊ผญ ๋ซ์์ผ ํฉ๋๋ค.
file_for_writing.close() # Why? Open file ๊ฐ์๊ฐ ์ ํด์ ธ ์๊ธฐ ๋ผ๋ฌธ
- ํ์ผ์ ๋ซ๋ ๊ฒ์ ์๊ธฐ ์ฝ๊ธฐ ๋๋ฌธ์ ํญ์ ๋ธ๋ก๊ณผ ํจ๊ป ์ฌ์ฉํด์ผ ํ๋ฉฐ, ๋ธ๋ก์ด ๋๋๋ฉด ์๋์ผ๋ก ๋ซํ๋๋ค.
with open(filename, 'r') as f:
# 'f'๋ฅผ ํตํด ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ ํจ์๋ฅผ ํธ์ถํ์ฌ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ต๋๋ค.
data = function_that_gets_data_from(f)
# ์ด ์์ ์์ 'f'๋ ์ด๋ฏธ ๋ซํ์ผ๋ฏ๋ก ์ฌ์ฉํ์ง ๋ง์ญ์์ค.
# ๊ฐ์ ธ์จ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํฉ๋๋ค.
process(data)
starts_with_hash = 0
# 'input.txt' ํ์ผ์ ์ฝ๊ธฐ ๋ชจ๋๋ก ์ฝ๋๋ค.
with open('input.txt', 'r') as f:
# ํ์ผ์ ๊ฐ ์ค์ ํ์ธํฉ๋๋ค.
for line in f: # ํ์ผ์ ๊ฐ ์ค์ ํ์ธํฉ๋๋ค.
if re.match("^#", line): # ์ ๊ท์์ ์ฌ์ฉํ์ฌ ์ค์ด '#'๋ก ์์ํ๋์ง ํ์ธํฉ๋๋ค.
starts_with_hash += 1 # ๋ง์ฝ ๊ทธ๋ ๋ค๋ฉด, ์นด์ดํธ์ 1์ ๋ํฉ๋๋ค.
def get_domain(email_address):
"""'@'๋ฅผ ๊ธฐ์ค์ผ๋ก ๋ถํ ํ๊ณ ๋ง์ง๋ง ๋ถ๋ถ์ ๋ฐํํฉ๋๋ค."""
return email_address.lower().split("@")[-1]
# 'email_addresses.txt' ํ์ผ์ ์ฝ๊ธฐ ๋ชจ๋๋ก ์ฝ๋๋ค.
with open('email_addresses.txt', 'r') as f:
# ํ์ผ์ ๊ฐ ์ค์ ๋ํด ๋๋ฉ์ธ์ ๊ฐ์ ธ์์ ์นด์ดํธํฉ๋๋ค.
# ์ฃผ์์ '@'๊ฐ ์๋ ์ค๋ง ์ฒ๋ฆฌํฉ๋๋ค.
domain_counts = Counter(get_domain(line.strip()) # ๊ฐ ์ค์ ๋๋ฉ์ธ์ ๊ฐ์ ธ์์
for line in f # ํ์ผ์ ๊ฐ ์ค์ ๋ํด
if "@" in line) # '@'๊ฐ ์๋ ์ค๋ง ์ฒ๋ฆฌํฉ๋๋ค.
Delimited Files
csv ํ์ผ : ์ด๋ฌํ ํ์ผ์ ์ผํ๋ก ๊ตฌ๋ถ๋๊ฑฐ๋ ํญ์ผ๋ก ๊ตฌ๋ถ๋๋ ๊ฒฝ์ฐ๊ฐ ๋ง์ต๋๋ค.
!type tab_delimited_stock_prices.txt
6/20/2014 AAPL 90.91
6/20/2014 MSFT 41.68
6/20/2014 FB 64.5
6/19/2014 AAPL 91.86
6/19/2014 MSFT 41.51
6/19/2014 FB 64.34
- csv.reader๋ ์ค ๋จ์ ํํ ์์ฑ๊ธฐ์ ๋๋ค.
- ํญ์ผ๋ก ๊ตฌ๋ถ๋ ํ ์คํธ ํ์ผ์ ์ฝ์ด๋ค์ฌ์ ๊ฐ ํ์ ๋ ์ง, ๊ธฐํธ ๋ฐ ์ข ๊ฐ๋ฅผ ์ถ์ถํ๊ณ ์ถ๋ ฅํฉ๋๋ค.
- CSV ๋ชจ๋์ csv.reader() ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ํ์ผ์ ํญ์ผ๋ก ๊ตฌ๋ถํ์ฌ ์ฝ์ต๋๋ค.
import csv
# 'tab_delimited_stock_prices.txt' ํ์ผ์ ์ฝ๊ธฐ ๋ชจ๋๋ก ์ฝ๋๋ค.
with open('tab_delimited_stock_prices.txt', 'r') as f:
# ํ์ผ์ ํญ์ผ๋ก ๊ตฌ๋ถํ์ฌ ์ฝ๋ CSV ๋ฆฌ๋๋ฅผ ์์ฑํฉ๋๋ค.
reader = csv.reader(f, delimiter='\\t')
# CSV ํ์ผ์ ๊ฐ ํ์ ๋ฐ๋ณตํ๋ฉด์
for row in reader:
# ๊ฐ ํ์ ์ด์ ์ถ์ถํฉ๋๋ค.
date = row[0] # ์ฒซ ๋ฒ์งธ ์ด: ๋ ์ง
symbol = row[1] # ๋ ๋ฒ์งธ ์ด: ๊ธฐํธ
closing_price = float(row[2]) # ์ธ ๋ฒ์งธ ์ด: ์ข
๊ฐ (๋ถ๋ ์์์ ์ผ๋ก ๋ณํ)
# ๋ ์ง, ๊ธฐํธ ๋ฐ ์ข
๊ฐ๋ฅผ ์ถ๋ ฅํฉ๋๋ค.
print(date, symbol, closing_price)
6/20/2014 AAPL 90.91
6/20/2014 MSFT 41.68
6/20/2014 FB 64.5
6/19/2014 AAPL 91.86
6/19/2014 MSFT 41.51
6/19/2014 FB 64.34
%%bash
cat colon_delimited_stock_prices.txt
date:symbol:closing_price
6/20/2014:AAPL:90.91
6/20/2014:MSFT:41.68
6/20/2014:FB:64.5
- ์ฝ๋ก ์ผ๋ก ๊ตฌ๋ถ๋ ํ ์คํธ ํ์ผ์ ์ฝ์ด๋ค์ฌ์ ๊ฐ ํ์ ๋ ์ง, ๊ธฐํธ ๋ฐ ์ข ๊ฐ๋ฅผ ์ถ์ถํ๊ณ ์ถ๋ ฅํฉ๋๋ค.
- CSV ๋ชจ๋์ csv.DictReader() ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ํ์ผ์ ์ฝ๊ณ , ๊ฐ ํ์ ๋์ ๋๋ฆฌ๋ก ๋ํ๋ ๋๋ค.
import csv
# 'colon_delimited_stock_prices.txt' ํ์ผ์ ์ฝ๊ธฐ ๋ชจ๋๋ก ์ฝ๋๋ค.
with open('colon_delimited_stock_prices.txt', 'r') as f:
# ํ์ผ์ ์ฝ๋ก ์ผ๋ก ๊ตฌ๋ถํ์ฌ ์ฝ๋ CSV ๋์
๋๋ฆฌ ๋ฆฌ๋๋ฅผ ์์ฑํฉ๋๋ค.
reader = csv.DictReader(f, delimiter=':')
# CSV ํ์ผ์ ๊ฐ ํ์ ๋ฐ๋ณตํ๋ฉด์
for row in reader:
# ๊ฐ ํ์ ํ๋ ๊ฐ์ ๋์
๋๋ฆฌ์์ ์ถ์ถํฉ๋๋ค.
date = row["date"] # 'date' ํ๋
symbol = row["symbol"] # 'symbol' ํ๋
closing_price = float(row["closing_price"]) # 'closing_price' ํ๋ (๋ถ๋ ์์์ ์ผ๋ก ๋ณํ)
# ๋ ์ง, ๊ธฐํธ ๋ฐ ์ข
๊ฐ๋ฅผ ์ถ๋ ฅํฉ๋๋ค.
print(date, symbol, closing_price)
6/20/2014 AAPL 90.91
6/20/2014 MSFT 41.68
6/20/2014 FB 64.5
%%bash
cat comma_delimited_stock_prices.txt
FB,64.5
MSFT,41.68
AAPL,90.91
- ์ค๋์ ์ฃผ๊ฐ๋ฅผ ๋ํ๋ด๋ ๋์ ๋๋ฆฌ๋ฅผ ์ฝค๋ง๋ก ๊ตฌ๋ถ๋ ํ ์คํธ ํ์ผ์ ์ฐ๋ ์์ ์ ๋๋ค.
- CSV ๋ชจ๋์ csv.writer() ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ํ์ผ์ ์ฐ๊ณ , ๊ฐ ์ฃผ์๊ณผ ๊ฐ๊ฒฉ์ ๋ฆฌ์คํธ๋ก ๋ง๋ค์ด์ ํ์ผ์ ์๋๋ค.
import csv
# ์ค๋์ ์ฃผ๊ฐ๋ฅผ ๋ํ๋ด๋ ๋์
๋๋ฆฌ์
๋๋ค.
today_prices = {'AAPL': 90.91, 'MSFT': 41.68, 'FB': 64.5}
# 'comma_delimited_stock_prices_1.txt' ํ์ผ์ ์ฐ๊ธฐ ๋ชจ๋๋ก ์ฝ๋๋ค.
with open('comma_delimited_stock_prices_1.txt', 'w') as f:
# ํ์ผ์ ์ฝค๋ง๋ก ๊ตฌ๋ถํ์ฌ ์ฐ๋ CSV ๋ผ์ดํฐ๋ฅผ ์์ฑํฉ๋๋ค.
writer = csv.writer(f, delimiter=',')
# ์ค๋์ ์ฃผ๊ฐ ๋์
๋๋ฆฌ์์ ๊ฐ ์ฃผ์๊ณผ ๊ฐ๊ฒฉ์ ๊ฐ์ ธ์์ ํ์ผ์ ์ฐ๊ธฐํฉ๋๋ค.
for stock, price in today_prices.items():
# ๊ฐ ์ฃผ์๊ณผ ๊ฐ๊ฒฉ์ ๋ฆฌ์คํธ๋ก ๋ง๋ค์ด์ ์ฐ๊ธฐํฉ๋๋ค.
writer.writerow([stock, price])
%%bash
cat comma_delimited_stock_prices_1.txt
AAPL,90.91
MSFT,41.68
FB,64.5
results = [["test1", "success", "Monday"],
["test2", "success, kind of", "Tuesday"],
["test3", "failure, kind of", "Wednesday"],
["test4", "failure, utter", "Thursday"]]
# don't do this!
with open('bad_csv.txt', 'w') as f:
for row in results:
f.write(",".join(map(str, row))) # might have too many commas in it!
f.write("\\n") # row might have newlines as well!
%%bash
cat bad_csv.txt
test1,success,Monday
test2,success, kind of,Tuesday
test3,failure, kind of,Wednesday
test4,failure, utter,Thursday
Scraping the Web
๋ฐ์ดํฐ๋ฅผ ์ป๋ ๋ ๋ค๋ฅธ ๋ฐฉ๋ฒ์ ์น ํ์ด์ง์์ ์คํฌ๋ฉํ๋ ๊ฒ์ ๋๋ค
HTML & Parsing
<html>
<head>
<title>A web page</title>
</head>
<body>
<p id="author">Joel Grus</p>
<p id="subject">Data Science</p>
</body>
</html>
- for python3:
!pip install html5lib
!pip install beautifulsoup4
- for anaconda
conda install -c anaconda html5lib
conda install -c anaconda beautifulsoup4
Html5Lib :: Anaconda.org
Description html5lib is a pure-python library for parsing HTML. It is designed to conform to the WHATWG HTML specification, as is implemented by all major web browsers.
anaconda.org
Login :: Anaconda.org
Sign in to Anaconda.org I forgot my password. I forgot my username. Register for an account.
anaconda.org
DOM Lesson One
- Hello World! - John | Doe | Alaska
from bs4 import BeautifulSoup
html = """
<html>
<head>
<title>A web page</title>
</head>
<body>
<p id="author">Joel Grus</p>
<p id="subject">Data Science</p>
<p class="price">30</p>
</body>
</html>"""
soup = BeautifulSoup(html, 'html5lib')
์ค์: Tag, Attribute, Text
soup = BeautifulSoup(html, 'html5lib')→ Parsing ํด์ ์๋ฃ๊ตฌ์กฐํ ํฉ๋๋ค.(Dict ํ)
Query 1: Find title (์ ๋ชฉ ์ฐพ๊ธฐ)
soup.title.text
# 'A web page'
Query 2: Find title's text (์ ๋ชฉ ํ ์คํธ ์ฐพ๊ธฐ)
soup.title.text
# 'A web page'
Query 3: Find p of body (p์ ๋ณธ๋ฌธ ์ฐพ๊ธฐ)
soup.body.p
# <p id="author">Joel Grus</p>
Query 4: Find all p under body (p์๋ ๋ณธ๋ฌธ ์ฐพ๊ธฐ)
soup.body('p')
[<p id="author">Joel Grus</p>,
<p id="subject">Data Science</p>,
<p class="price">30</p>]
Query 5: Find second p's text of body (๋ ๋ฒ์งธ p์ ๋ณธ๋ฌธ ์ฐพ๊ธฐ)
soup.body('p')[1].text
# 'Data Science'
Query 6: Find last p of body (p์ ๋ง์ง๋ง ๋ถ๋ถ ์ฐพ๊ธฐ)
soup.body('p')[-1]
# <p class="price">30</p>
Query 7: Loop over all p of body (p์ ๋ชจ๋ ๋ถ๋ถ์ ๋ฃจํ๋ฅผ ์์ฐ๊ธฐ)
for i, p in enumerate(soup.body('p')):
print('paragraph {}: {}'.format(i, p.text))
paragraph 0: Joel Grus
paragraph 1: Data Science
paragraph 2: 30
Query 8: Find first p's id attribute's value (์ฒซ ๋ฒ์งธ p์ ID ์์ฑ ๊ฐ ์ฐพ๊ธฐ)
soup.p['id']
# 'author'
Query 9: Find all p whose attribute id is 'author' (์์ฑ ID๊ฐ '์ ์'์ธ ๋ชจ๋ p ์ฐพ๊ธฐ)
soup('p', {'id':'author'})
# [<p id="author">Joel Grus</p>]
Query 10: Find all p whose attribute class is 'price' (์์ฑ ํด๋์ค๊ฐ '๊ฐ๊ฒฉ'์ธ ๋ชจ๋ p ์ฐพ๊ธฐ)
soup('p', 'price')
#soup('p', {'class':'price'})
[<p class="price">30</p>]
Query 11: Find all texts (๋ชจ๋ ํ ์คํธ ์ฐพ๊ธฐ)
soup.text # List
# '\\n A web page\\n \\n \\n Joel Grus\\n Data Science\\n 30\\n \\n'
first_paragraph = soup.find('p') # ๋๋ soup.p
print(first_paragraph) # ์ฒซ ๋ฒ์งธ <p> ํ๊ทธ์ ๋ด์ฉ์ ์ถ๋ ฅํฉ๋๋ค.
print(type(first_paragraph)) # ๊ฒฐ๊ณผ์ ํ์
์ ์ถ๋ ฅํฉ๋๋ค.
<p id="author">Joel Grus</p>
<class 'bs4.element.Tag'>
- ์ฒซ ๋ฒ์งธ <p> ํ๊ทธ์ ๋ด์ฉ์ด ๋ค์ด ์์ ๊ฒ์ด๋ฉฐ, <p> ํ๊ทธ ๋ด์ฉ์ ํ์ ์ BeautifulSoup์ ํน์ํ ํ์ ์ธ Tag ์ ๋๋ค.
first_paragraph_text = soup.p.text
first_paragraph_text
# 'Joel Grus'
first_paragraph_words = soup.p.text.split()
first_paragraph_words
# ['Joel', 'Grus']
- ์ฒซ ๋ฒ์งธ <p> ํ๊ทธ์ ํ ์คํธ ๋ด์ฉ์ ์ถ์ถํ ํ, .split() ๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ฌ ๊ณต๋ฐฑ์ ๊ธฐ์ค์ผ๋ก ๋จ์ด ๋จ์๋ก ๋ถํ ํฉ๋๋ค.
first_paragraph_id = soup.p['id'] # 'id' ์์ฑ์ด ์์ผ๋ฉด KeyError๋ฅผ ๋ฐ์์ํต๋๋ค.
first_paragraph_id
#type(soup.p)
# Result: 'author'
- soup์์ ์ฒซ ๋ฒ์งธ <p> ํ๊ทธ์ id ์์ฑ ๊ฐ์ ๊ฐ์ ธ์์ first_paragraph_id ๋ณ์์ ํ ๋นํฉ๋๋ค.
- ๋ง์ฝ ํด๋น ํ๊ทธ์ id ์์ฑ์ด ์๋ค๋ฉด KeyError๊ฐ ๋ฐ์ํฉ๋๋ค.
first_paragraph_id2 = soup.p.get('id') # 'id' ์์ฑ์ด ์์ผ๋ฉด None์ ๋ฐํํฉ๋๋ค.
print(first_paragraph_id2)
# Result: 'author'
- soup์์ ์ฒซ ๋ฒ์งธ <p> ํ๊ทธ์ id ์์ฑ ๊ฐ์ ๊ฐ์ ธ์์ first_paragraph_id2 ๋ณ์์ ํ ๋นํฉ๋๋ค.
- ๋ง์ฝ ํด๋น ํ๊ทธ์ id ์์ฑ์ด ์๋ค๋ฉด None์ ๋ฐํํฉ๋๋ค.
all_paragraphs = soup.find_all('p') # ๋๋ soup('p')๋ก๋ ๊ฐ๋ฅํฉ๋๋ค.
print(all_paragraphs)
[<p id="author">Joel Grus</p>, <p id="subject">Data Science</p>]
- soup์์ ๋ชจ๋ <p> ํ๊ทธ๋ฅผ ์ฐพ์์ all_paragraphs ๋ณ์์ ํ ๋นํฉ๋๋ค.
- ๊ทธ ๊ฒฐ๊ณผ๋ ๋ฆฌ์คํธ ํํ๋ก ๋ฐํ๋ฉ๋๋ค.
soup('p')
# [<p id="author">Joel Grus</p>, <p id="subject">Data Science</p>]
soup('p', {'id':'subject'})
# [<p id="subject">Data Science</p>]
- id ์์ฑ์ด 'subject'์ธ ๋ชจ๋ <p> ํ๊ทธ๋ฅผ ์ฐพ๋ ์์์ ๋๋ค.
- ๊ฒฐ๊ณผ๋ ํด๋น ์กฐ๊ฑด์ ๋ง๋ <p> ํ๊ทธ๋ค์ ํฌํจํ๋ ๋ฆฌ์คํธ๋ก ๋ฐํํฉ๋๋ค.
- soup์์ id ์์ฑ์ด 'subject' ์ธ ๋ชจ๋ <p> ํ๊ทธ๋ฅผ ์ฐพ์ ๋ฐํํฉ๋๋ค.
- ๋ ๋ฒ์งธ ์ธ์๋ก๋ ๋์ ๋๋ฆฌ๋ฅผ ์ฌ์ฉํ์ฌ ์ํ๋ ์์ฑ๊ณผ ๊ทธ ๊ฐ์ ์กฐ๊ฑด์ ์ง์ ํฉ๋๋ค.
paragraphs_with_ids = [p for p in soup('p') if p.get('id')]
paragraphs_with_ids
[<p id="author">Joel Grus</p>, <p id="subject">Data Science</p>]
- BeautifulSoup ๊ฐ์ฒด soup์์ ๋ชจ๋ <p> ํ๊ทธ๋ฅผ ์ฐพ์ ํ, ๋ฆฌ์คํธ ์ปดํ๋ฆฌํจ์ ์ ์ฌ์ฉํ์ฌ id ์์ฑ์ ๊ฐ์ง ํ๊ทธ๋ค๋ง ๋ชจ์์ paragraphs_with_ids ๋ฆฌ์คํธ์ ์ ์ฅํฉ๋๋ค.
- ๊ฒฐ๊ณผ๋ id ์์ฑ์ ๊ฐ์ง <p> ํ๊ทธ๋ค์ ๋ฆฌ์คํธ๋ก ๋ฐํ๋ฉ๋๋ค.
important_paragraphs = soup('p', {'class': 'important'})
# [<p id="author">Joel Grus</p>, <p id="subject">Data Science</p>]
- soup์์ ํด๋์ค๊ฐ 'important'์ธ ๋ชจ๋ <p> ํ๊ทธ๋ฅผ ์ฐพ์ ๋ฐํํฉ๋๋ค.
- ๋ ๋ฒ์งธ ์ธ์๋ก๋ ๋์ ๋๋ฆฌ๋ฅผ ์ฌ์ฉํ์ฌ ์ํ๋ ํด๋์ค์ ๊ทธ ๊ฐ์ ์กฐ๊ฑด์ ์ง์ ํฉ๋๋ค.
# ๋ค์ด๋ฒ ํํ์ด์ง์ HTML์ ๊ฐ์ ธ์ต๋๋ค.
html = requests.get("<http://www.naver.com>").text
# HTML์ BeautifulSoup์ผ๋ก ํ์ฑํฉ๋๋ค.
soup = BeautifulSoup(html, 'html5lib')
- requests ๋ชจ๋์ ์ฌ์ฉํ์ฌ ๋ค์ด๋ฒ ํํ์ด์ง์ GET ์์ฒญ์ ๋ณด๋ด๊ณ , ํด๋น ํ์ด์ง์ HTML์ ๊ฐ์ ธ์ต๋๋ค.
- ๊ทธ ํ, BeautifulSoup์ ์ฌ์ฉํ์ฌ HTML์ ํ์ฑํ์ฌ ๊ฐ์ฒด๋ก ์ ์ฅํฉ๋๋ค.
- ์ด๋ ๊ฒ ํ๋ฉด ์น ํ์ด์ง์ ๊ตฌ์กฐ๋ฅผ ํ์ํ๊ณ ์ํ๋ ์ ๋ณด๋ฅผ ์ถ์ถํฉ๋๋ค.
# ๊ฒฝ๊ณ : ๋ง์ฝ <span>์ด ์ฌ๋ฌ ๊ฐ์ <div> ์์ ์๋ ๊ฒฝ์ฐ, ๊ฐ์ <span>์ ์ฌ๋ฌ ๋ฒ ๋ฐํํ ์ ์์ต๋๋ค.
# ๋ง์ฝ ๊ทธ๋ ๋ค๋ฉด ์ข ๋ ๋๋ํ๊ฒ ์ฒ๋ฆฌํด์ผ ํฉ๋๋ค.
spans_inside_divs = [span # <span>์ ๊ฐ๊ฐ ๋ฆฌ์คํธ์ ์ถ๊ฐํฉ๋๋ค.
for div in soup('div') # ํ์ด์ง์ ๊ฐ <div>์ ๋ํด
for span in div('span')] # ๊ทธ ์์ ์๋ ๊ฐ <span>์ ์ฐพ์ต๋๋ค.
- soup์์ ๋ชจ๋ <div> ํ๊ทธ๋ฅผ ์ฐพ์ ํ, ๊ฐ <div> ํ๊ทธ ์์ ์๋ ๋ชจ๋ <span> ํ๊ทธ๋ฅผ ์ฐพ์ ๋ฆฌ์คํธ์ ์ถ๊ฐํฉ๋๋ค.
- ๊ทธ๋ฌ๋ ๋ง์ฝ <span> ํ๊ทธ๊ฐ ์ฌ๋ฌ ๊ฐ์ <div> ํ๊ทธ ์์ ์กด์ฌํ๋ ๊ฒฝ์ฐ, ๋์ผํ <span>์ ์ฌ๋ฌ ๋ฒ ๋ฐํํฉ๋๋ค.
spans_inside_divs
- spans_inside_divs ๋ณ์์๋ ๋ชจ๋ <div> ํ๊ทธ ์์ ์๋ ๋ชจ๋ <span> ํ๊ทธ๊ฐ ํฌํจ๋ ๋ฆฌ์คํธ๊ฐ ์ ์ฅ๋์ด ์์ ๊ฒ์ ๋๋ค.
- ์ด ๋ฆฌ์คํธ๋ ๊ฐ <div> ํ๊ทธ์ ๋ํด ๊ทธ ์์ ์๋ ๋ชจ๋ <span> ํ๊ทธ๋ฅผ ํฌํจํ๊ณ ์์ต๋๋ค.
- ์ด ๋ฆฌ์คํธ๋ฅผ ์ถ๋ ฅํ๋ฉด ํด๋น ์ ๋ณด๋ฅผ ํ์ธํฉ๋๋ค.