[데이터 수집] BeautifulSoup, Selenium
Y
Yerim
- ML
- DataAnalysis
정적 웹페이지 | 동적 웹페이지 | ||
BeautifulSoup | O (페이지 내의 고정 html만 전달받음) | X | |
Selenium | O | O | 원래 테스트 엔지니어링을 돕는 프로그램 |
파서 (parser) | 선언 | 장점 | 단점 |
html.parser | BeautifulSoup(markup, ‘html.parser’) | 설치 필요 없음 적절한 속도 | |
lxml HTML parser | BeautifulSoup(markup, ‘lxml’) | 매우 빠름 | lxml 추가 설치 필요 |
lxml XML parser | BeautifulSoup(markup, ‘xml’) | 매우 빠름 유일한 xml parser | lxml 추가 설치 필요 |
html5lib | BeautifulSoup(markup, ‘html5lib’) | 웹 브라우저와 같은 방식으로 파싱 유용한 HTML5 생성 | html5lib 추가 설치 필요 매우 느림 |
# BeautifulSoup 설치
!pip install beautifulsoup4%%writefile example.html
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
</head>
<body>
<h1>Heading</h1>
<p>Paragraph</p>
<div>
<a href="www.google.com">google</a>
</div>
<div class="class1">
<p>a</p>
<a href="www.naver.com">naver</a>
<p>b</p>
<p>c</p>
</div>
<div id = "id1">
Example Page
<p>g</p>
</div>
</body>
</html>from bs4 import BeautifulSoup
import urllib.request
with open("example.html") as fp:
soup = BeautifulSoup(fp, 'html.parser')
print(soup.prettify())soup.title # title 태그만
soup.title.name # title 태그의 이름만
soup.title.string # title 태그의 문자만
soup.title.parent # title 태그의 부모 태그
soup.h1 # h1 태그
soup.p # p 태그
soup.div # div태그, div에 포함된 태그들까지 함께 불러옴
soup.a # a태그soup.find('div') # 첫번째 div
soup.find('a').get('href') # a태그의 'href' 속성 값
soup.find('a').get_text() # a태그의 텍스트만soup.find_all('div') # div가 사용된 모든 태그
soup.find_all('div', {'id':'id1'} # attribute 중 id가 id1인 div태그
site_names = soup.find_all('a') # a태그가 사용된 모든 태그
for name in site_names:
print(name.get('href')) # a태그의 href만 출력
site_names = soup.find_all('a') # a태그가 사용된 모든 태그
for name in site_names:
print(name.get_text()) # a태그의 text만 출soup.select('div#id1') # id는 #으로 접근
soup.select('div.class1') # class는 .으로 접근
soup.select('div.class1 a') # class가 class1인 태그의 a태그
soup.select('div.class1 > a') # 위와 같음%%writefile anthem.html
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div>
<p id="title">애국가</p>
<p id="content">
동해물과 백두산이 마르고 닳도록 하느님이 보우하사 우리나라 만세. <br/>
무궁화 삼천리 화려 강산 대한 사람, 대한으로 길이 보전하세, <br/>
</p>
<p id="content">
남산 위에 저 소나무, 철갑을 두른 듯 바람 서리 불변함은 우리 기상일세. <br/>
무궁화 삼천리 화려 강산 대한 사람, 대한으로 길이 보전하세. <br/>
</p>
<p id="content">
가을 하늘 공활한데 높고 구름 없이 밝은 달은 우리 가슴 일편단심일세. <br/>
무궁화 삼천리 화려 강산 대한 사람, 대한으로 길이 보전하세, <br/>
</p>
<p id="content">
이 기상과 이 맘으로 충성을 다하여 괴로우나 즐거우나 나라 사랑하세. <br/>
무궁화 삼천리 화려 강산 대한 사람, 대한으로 길이 보전하세, <br/>
</p>
</div>
</body>
</html>with open("anthem.html") as fp:
soup = BeautifulSoup(fp, 'html.parser')
soup# 애국가의 가사만 가져오기
title = soup.find('p', {'id':'title'}) # id가 title인 p태그만
contents = soup.find_all('p', {'id':'content'}) # id가 content인 p태그만
print(title.get_text()) # title의 text 출력
for content in contents:
print(content.get_text()) # content의 text 출력url = "http://suanlab.com" # 가져오고 싶은 웹페이지 주소
html = urllib.request.urlopen(url).read() # 웹페이지 읽어오기
soup = BeautifulSoup(html, 'html.parser') # html parser 이용
souplabels = soup.find_all(['label']) # label 태그 모두
for label in labels:
print(label.get_text()) # label 태그의 text만labels = soup.select('#wrapper > section > div > div > div > div > div > label') # CSS selector 이용
for label in labels:
print(label.get_text())#1. 필요한 라이브러리 import 하기
import requests
from bs4 import BeautifulSoup
import re
import pandas as pd#2. 링크를 request.get으로 가져오기 (header가 필요한 경우 headers 입력)
res = requests.get('https://www.gmarket.co.kr/n/best?viewType=G&groupCode=G07') # 식품 카테고리
#header 입력
headers = {
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36"
}#3. BeautifulSoup을 이용해 파싱하기
soup = BeautifulSoup(res.content, 'html.parser')#4. 상품명 크롤링하여 리스트로 저장하기 (20점)
item_list = soup.select('a.itemname')
# 상품의 이름만 title_list에 저장
title_list = list()
for item in item_list:
title_list.append(item.get_text())#5. 정가 정보 크롤링하여 리스트로 저장하기 (10점)
item_list = soup.select('div.o-price')
# 상품의 정가 정보만 original_price_list에 저장
original_price_list = list()
for item in item_list:
original_price_list.append(item.get_text())#6. 할인가 정보 크롤링하여 리스트로 저장하기 (10점)
item_list = soup.select('div.s-price')
# 상품의 할인가 정보만 sale_price_list에 저장
sale_price_list = list()
for item in item_list:
sale_price_list.append(item.get_text())#7. 적절히 데이터 전처리를 하여 DataFrame 객체로 만들고 Excel 파일로 저장하기 (30점)
#이때, DataFrame의 열은 "상품명, 정가, 판매가"로 구성되어야 함.
# 정가, 판매가 서식
def extract_number(x):
price = re.findall("\d.*원", x)
try:
price_num = price[0].replace("원", "")
try:
price_num = int(price_num.replace(",", ""))
except:
price_num = int(price_num)
except:
pass
return price_num if price else None
# 정가 열이 na면 판매가를 대입
def fill_na_with_sales(row):
if pd.isna(row['정가']):
return row['판매가']
else:
return row['정가']
# gmarket_food_df에 상품명, 정가, 판매가의 정보를 DataFrame으로 저장
gmarket_food_df = pd.DataFrame([title_list, original_price_list, sale_price_list]).T
gmarket_food_df.columns = ['상품명', '정가', '판매가']
# extract_numer -> 정가, 판매가 숫자만 남기기
gmarket_food_df['정가'] = gmarket_food_df['정가'].apply(extract_number)
gmarket_food_df['판매가'] = gmarket_food_df['판매가'].apply(extract_number)
# fill_na_with_sale -> 정가의 빈값은 판매가로 채우기
gmarket_food_df['정가'] = gmarket_food_df.apply(fill_na_with_sales, axis=1)
gmarket_food_df['정가'] = gmarket_food_df['정가'].apply(int)
# 엑셀파일로 저장
gmarket_food_df.to_excel('gmarket_best_item.xlsx')