개발하고 싶어요
정적, 동적 웹크롤링 본문
정적 웹크롤링¶
In [1]:
import urllib.request
from bs4 import BeautifulSoup # 특정 웹 페이지의 HTML을 스크랩하여 데이터를 수집할 때 사용
In [169]:
response = urllib.request.urlopen('https://www.naver.com') # 응답
html_str = response.read().decode('utf-8') # 응답한 내용을 가져오기
In [170]:
bs_obj = BeautifulSoup(html_str, 'html.parser') # 'html.parser'는 BeautifulSoup이 사용할 파서를 지정하는 부분
print(type(bs_obj))
<class 'bs4.BeautifulSoup'>
In [13]:
# 'strong' tag 첫 번째 요소 찾기
print(bs_obj.strong)
# 'a'tag 첫 번째 요소 찾기
print('\n', bs_obj.a)
# 'a'tag 요소 찾기
print('\n', bs_obj.find_all('a'))
# .(클래스), #(id)
print('\n', bs_obj.select_one(".tit"))
# 태그 안으로 들어가기
print('\n', bs_obj.select_one('#NM_THEME_CONTAINER > div.group_topstory'))
<strong class="tit">최근 검색어</strong>
<a href="#topAsideButton"><span>상단영역 바로가기</span></a>
[<a href="#topAsideButton"><span>상단영역 바로가기</span></a>, <a href="#shortcutArea"><span>서비스 메뉴 바로가기</span></a>, <a href="#newsstand"><span>새소식 블록 바로가기</span></a>, <a href="#shopping"><span>쇼핑 블록 바로가기</span></a>, <a href="#feed"><span>관심사 블록 바로가기</span></a>, <a href="#account"><span>MY 영역 바로가기</span></a>, <a href="#widgetboard"><span>위젯 보드 바로가기</span></a>, <a href="#viewSetting"><span>보기 설정 바로가기</span></a>, <a aria-pressed="false" class="item _delAll" href="#" role="button">전체삭제</a>, <a class="kwd_help" data-clk="sly.help" href="https://help.naver.com/alias/search/word/word_35.naver" target="_blank">도움말</a>, <a class="kwd_help" data-clk="sly.help" href="https://help.naver.com/alias/search/word/word_35.naver" target="_blank">도움말</a>, <a class="close _keywordOnOff" href="#">자동저장 끄기</a>, <a data-clk="sly.help" href="https://help.naver.com/alias/search/word/word_35.naver" target="_blank">도움말</a>, <a class="close _close" href="#">닫기</a>, <a aria-pressed="false" class="btn_help _tg_btn" href="#" role="button"><i class="imgsvg ico_alert">이 정보가 표시된 이유</i></a>, <a class="btn_close _tg_btn" href="#" role="button"><i class="imgsvg ico_close">레이어 닫기</i></a>, <a class="link _alert_link" href="#" target="_blank">자세히보기</a>, <a class="link_dsc" data-clk="sug.cxhelp" href="https://help.naver.com/alias/search/word/word_16.naver" target="_blank">관심사를 반영한 컨텍스트 자동완성<i class="imgsvg ico_help">도움말</i></a>, <a aria-pressed="false" class="bt_switch active _plus_btn" href="#" role="button"><i class="imgsvg ico_option">컨텍스트 자동완성</i></a>, <a class="link_view" data-clk="sug.cxlink" href="https://help.naver.com/alias/search/word/word_16.naver" target="_blank">자세히 보기</a>, <a class="link_view" data-clk="sug.cxlink" href="https://help.naver.com/support/alias/search/word/word_16.naver" target="_blank">자세히 보기</a>, <a class="btn btn_login" data-clk="sug.cxlogin" href="https://nid.naver.com/nidlogin.login"><i class="imgsvg ico_naver">네이버</i>로그인</a>, <a class="btn_close _plus_layer_close" href="#" role="button"><i class="imgsvg ico_close">컨텍스트 자동완성 레이어 닫기</i></a>, <a class="close _suggestOnOff" href="#">자동완성 끄기</a>, <a data-clk="sug.help" href="https://help.naver.com/alias/search/word/word_17.naver" target="_blank">도움말</a>, <a class="report" data-clk="sug.report" href="https://help.naver.com/alias/search/word/word_18.naver" target="_blank">신고</a>, <a class="close _close" href="#">닫기</a>]
<strong class="tit">최근 검색어</strong>
None
베스트 셀러 제목 가져오기¶
In [51]:
from bs4 import BeautifulSoup
import urllib.request
response = urllib.request.urlopen("https://search.shopping.naver.com/book/search?bookTabType=BEST_SELLER&catId=50005542&pageIndex=1&pageSize=40&query=%EB%B2%A0%EC%8A%A4%ED%8A%B8%20%EC%85%80%EB%9F%AC&sort=REL")
html_str = response.read().decode("utf-8")
bs_obj = BeautifulSoup(html_str, 'html.parser')
In [47]:
# 순번, 제목 가져오기
rank = bs_obj.select('.bookListItem_num__6P2ec')
print(rank[:5])
title = bs_obj.select('.bookListItem_text__bglOw > span:nth-child(2)')
print(title[:5])
[<span class="bookListItem_num__6P2ec">1</span>, <span class="bookListItem_num__6P2ec">2</span>, <span class="bookListItem_num__6P2ec">3</span>, <span class="bookListItem_num__6P2ec">4</span>, <span class="bookListItem_num__6P2ec">5</span>]
[<span>오케팅 양장(업그레이드 특별판 리커버 에디션)</span>, <span>박근혜 회고록 1: 어둠을 지나 미래로</span>, <span>마흔에 읽는 쇼펜하우어</span>, <span>박근혜 회고록 2: 어둠을 지나 미래로</span>, <span>아이는 무엇으로 자라는가</span>]
영화¶
In [171]:
from bs4 import BeautifulSoup
import urllib.request
url = "https://search.naver.com/search.naver?where=nexearch&sm=top_hty&fbm="+str(1)+"&ie=utf8&query=%EC%98%81%ED%99%94#"
response = urllib.request.urlopen(url)
html = response.read().decode("utf-8")
bs_obj = BeautifulSoup(html,"html.parser")
In [172]:
# 제목 가져오기
title = bs_obj.select('.area_text_box > a')
for tit in title:
print(tit.string)
도그데이즈
소풍
건국전쟁
웡카
시민덕희
데드맨
아가일
스노우 퍼핀즈
멜론차트¶
In [173]:
from bs4 import BeautifulSoup
import urllib.request
import pandas as pd
hdr = {
'accept-language': 'ko,th;q=0.9,en-US;q=0.8,en;q=0.7,ru;q=0.6,ko-KR;q=0.5,la;q=0.4',
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36"
}
url = "https://www.melon.com/chart/index.htm"
html = requests.get(url, headers=hdr).text
bs_obj = BeautifulSoup(html,"html.parser")
In [174]:
rank = bs_obj.select('.rank')[1:51]
# print(rank)
title = title = bs_obj.select('.wrap > .wrap_song_info > .ellipsis.rank01 > span > a')[:51]
# print(title)
name = bs_obj.select('.wrap > .wrap_song_info > .ellipsis.rank02 > a')[:51]
# print(name)
lst_result = []
for i, name, tit in zip(rank, name, title):
# print(i.string , '순위 : ' , name.string, '-', tit.string)
lst_result.append([i.string + '순위', name.string, tit.string])
df = pd.DataFrame(lst_result, columns = ['순위', '가수', '제목'])
df
Out[174]:
순위 | 가수 | 제목 | |
---|---|---|---|
0 | 1순위 | 아이유 | Love wins all |
1 | 2순위 | TWS (투어스) | 첫 만남은 계획대로 되지 않아 |
2 | 3순위 | 태연 (TAEYEON) | To. X |
3 | 4순위 | 임재현 | 비의 랩소디 |
4 | 5순위 | RIIZE | Love 119 |
5 | 6순위 | 이무진 | 에피소드 |
6 | 7순위 | LE SSERAFIM (르세라핌) | Perfect Night |
7 | 8순위 | 너드커넥션 (Nerd Connection) | 그대만 있다면 (여름날 우리 X 너드커넥션 (Nerd Connection)) |
8 | 9순위 | aespa | Drama |
9 | 10순위 | 박재정 | 헤어지자 말해요 |
10 | 11순위 | (여자)아이들 | Super Lady |
11 | 12순위 | (여자)아이들 | Wife |
12 | 13순위 | 범진 | 인사 |
13 | 14순위 | 임영웅 | 사랑은 늘 도망가 |
14 | 15순위 | 정국 | Seven (feat. Latto) - Clean Ver. |
15 | 16순위 | 비비 (BIBI) | 밤양갱 |
16 | 17순위 | IVE (아이브) | I AM |
17 | 18순위 | 태연 (TAEYEON) | 꿈 |
18 | 19순위 | VIVIZ (비비지) | MANIAC |
19 | 20순위 | RIIZE | Get A Guitar |
20 | 21순위 | 임영웅 | 모래 알갱이 |
21 | 22순위 | IVE (아이브) | Baddie |
22 | 23순위 | 임영웅 | 우리들의 블루스 |
23 | 24순위 | AKMU (악뮤) | Love Lee |
24 | 25순위 | 성시경 | 너의 모든 순간 |
25 | 26순위 | 임영웅 | Do or Die |
26 | 27순위 | 임영웅 | 다시 만날 수 있을까 |
27 | 28순위 | 제니 (JENNIE) | You & Me |
28 | 29순위 | NewJeans | Super Shy |
29 | 30순위 | 우디 (Woody) | 사막에서 꽃을 피우듯 |
30 | 31순위 | (여자)아이들 | 퀸카 (Queencard) |
31 | 32순위 | NewJeans | Hype Boy |
32 | 33순위 | 임영웅 | 이제 나만 믿어요 |
33 | 34순위 | 임영웅 | 무지개 |
34 | 35순위 | DAY6 (데이식스) | 예뻤어 |
35 | 36순위 | AKMU (악뮤) | 후라이의 꿈 |
36 | 37순위 | 로이킴 | 잘 지내자, 우리 (여름날 우리 X 로이킴) |
37 | 38순위 | NewJeans | Ditto |
38 | 39순위 | 임영웅 | London Boy |
39 | 40순위 | 임영웅 | 아버지 |
40 | 41순위 | 멜로망스 | 사랑인가 봐 |
41 | 42순위 | NewJeans | ETA |
42 | 43순위 | 임영웅 | Polaroid |
43 | 44순위 | 정국 | Standing Next to You |
44 | 45순위 | DAY6 (데이식스) | 한 페이지가 될 수 있게 |
45 | 46순위 | 임영웅 | 인생찬가 |
46 | 47순위 | AKMU (악뮤) | 어떻게 이별까지 사랑하겠어, 널 사랑하는 거지 |
47 | 48순위 | aespa | Spicy |
48 | 49순위 | 임영웅 | A bientot |
49 | 50순위 | 윤하 (YOUNHA) | 사건의 지평선 |
쿠팡¶
In [256]:
from bs4 import BeautifulSoup
import urllib.request
hdr = {
'accept-language': 'ko,th;q=0.9,en-US;q=0.8,en;q=0.7,ru;q=0.6,ko-KR;q=0.5,la;q=0.4',
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36"
}
url = "https://www.coupang.com/np/search?q=%EC%9D%B8%EA%B0%84%EC%82%AC%EB%A3%8C&channel=user&component=&eventCategory=SRP&trcid=&traid=&sorter=scoreDesc&minPrice=&maxPrice=&priceRange=&filterType=&listSize=36&filter=&isPriceRange=false&brand=&offerCondition=&rating=0&page=1&rocketAll=false&searchIndexingToken=1=9&backgroundColor="
html = requests.get(url, headers = hdr).text
bs_obj = BeautifulSoup(html, 'html.parser')
In [257]:
# 상품 이름 가격
names = bs_obj.select('.descriptions-inner > .name')
prices = bs_obj.select('div.price > em > strong')
In [258]:
lst_result = []
for name, price in zip(names, prices):
lst_result.append([name.string, price.string + '원'])
df = pd.DataFrame(lst_result, columns = ['이름', '가격'])
df
Out[258]:
이름 | 가격 | |
---|---|---|
0 | 곰곰 클래식 체다치즈쿠키, 60g, 10개 | 9,990원 |
1 | 리치 오트밀 미니바이트 스낵, 1kg, 1개 | 10,840원 |
2 | 삼립 누네띠네 벌크, 2.5kg, 1개 | 21,500원 |
3 | 삼립 누네띠네, 12g, 120개 | 21,600원 |
4 | 풍심당 호롱칩 햅쌀 현미+귀리+곤약 누룽지 칩 과자 (1팩당 18개입) 부모님 사... | 22,000원 |
5 | 날씬한크리스피21+ 60입 국내산곡물과자, 1개, 600g | 12,500원 |
6 | 삼립 잼있는 미니사과쿠키, 16g, 100개 | 15,210원 |
7 | 삼립 한과 미니꿀약과 선물세트, 200개 | 16,530원 |
8 | 유밀가 우유 약과 336g 1개 | 27,900원 |
9 | 자연이야기 23곡 곡물과자 100p, 1.1kg, 1박스 | 18,410원 |
10 | 당뇨인들이 찾는 조리퐁맛 카무트뻥 호라산밀 뻥튀기 뻥과자, 200g, 4개 | 19,900원 |
11 | 종합과자선물세트 세계 수입 과자 추억의 간식 젤리 과자박스 이벤트선물, 추억의간식... | 19,800원 |
12 | \n ... | 21,600원 |
13 | \n ... | 21,600원 |
14 | \n ... | 13,670원 |
15 | \n ... | 20,000원 |
16 | \n ... | 18,230원 |
17 | \n ... | 9,480원 |
18 | \n ... | 9,830원 |
19 | \n ... | 9,950원 |
20 | \n ... | 5,410원 |
21 | \n ... | 7,330원 |
22 | [안녕골목마켓]사무실 과자 세트 10종 탕비실 간식 오예스미니+초코하임+화이트하임... | 26,800원 |
23 | 오트밀 초콜릿 미니바이트 대용량 과자 300개 | 19,800원 |
24 | 포테이토 크리스프 스낵 바베큐맛 20g x 50p + 사워크림맛 20g x 50p... | 14,900원 |
25 | 칼라 마카로니, 1개, 1.6kg | 13,370원 |
26 | 쿠키마스타 낱개포장 카페서비스용쿠키 탕비실간식 대용량과자, 1kg, 1박스, 초코... | 14,600원 |
27 | 신흥 초코쿠키 대용량 업소용 대용량과자 수입쿠키 수입과자 벌크 안주 간식 행사용과... | 13,350원 |
28 | 오트밀 미니바이트 인간사료 대용량 귀리과자 300개 | 19,550원 |
29 | 신흥제과 감자크래커, 1.8kg, 1개 | 11,170원 |
30 | 게리 치즈 크래커 900g (18g X 50개입) 대용량 과자 사무실 간식, 1개 | 15,900원 |
31 | 먹태깡 큰사발면 청양마요맛 118g, 16개 | 21,310원 |
32 | 동서 오레오 화이트 샌드위치 쿠키, 1kg, 1개 | 9,830원 |
33 | 곡물과자 21곡 크리스피롤 100개입, 1kg, 1개 | 17,820원 |
34 | 고멧 참깨 코코넛 크래커, 520g, 2개 | 11,900원 |
35 | 쿠키마스타 낱개포장 카페서비스용쿠키 탕비실간식 대용량과자, 900g, 1박스, 6... | 16,400원 |
36 | 신흥제과 앙금쿠키, 1.8kg, 2개 | 22,420원 |
37 | 리치 오트밀 미니바이트, 800g, 1개 | 12,250원 |
38 | 오트밀 미니바이트 인간사료 대용량 귀리과자 200개 | 12,590원 |
39 | 신흥제과 행복 버터 쿠키, 1kg, 1개 | 7,330원 |
40 | 삼립 미니 사과맛 쿠키 100개입, 16g, 200개 | 29,890원 |
41 | 청우 델로스 오리지날 커피쿠키, 630g, 5개 | 26,410원 |
42 | 우리 참맛콘 뻥튀기, 3kg, 1개 | 18,230원 |
43 | 리치 오트밀 미니바이트 스낵, 1kg, 2개 | 20,500원 |
44 | 신흥식품 닭다리형 꼬꼬스낵, 1.6kg, 2개 | 20,260원 |
45 | 코코넛 라떼 쿠키 지퍼팩 200p, 1kg, 1개 | 11,700원 |
커피빈 매장 정보 가져오기¶
re.sub() 함수는 문자열을 대체하는 함수
이 함수는 세 개의 인자를 받는다
- 첫 번째 인자: 패턴(pattern)을 나타내는 문자열. 여기서는 ([a-zA-Z0-9]+) : 패턴을 사용
- 두 번째 인자: 대체할 문자열. 여기서는 r"'\1' :"를 사용. 여기서 \1은 첫 번째 캡처 그룹을 의미따라서 정규 표현식에 매칭되는 문자열을 따옴표로 묶고 콜론을 추가하여 반환됩니다.
- 대체할 문자열은 r"'\1' :" -> 여기서 \1은 첫 번째 캡처 그룹을 의미.
- 세 번째 인자: 대상 문자열 여기서는 response.text를 사용
In [219]:
import requests
import json
import re # 정규식 처리 모듈
url_head = 'https://www.coffeebeankorea.com/store/store_data2.asp?lat=&lng=&chk1=0&chk2=0&chk3=0&chk4=0&chk5=0&chk6=0&chk7=0&chk8=0&chk9=0&chk10=0&chk11=0&chk12=0&keyword=&StoreLocal='
url_tail = '&StoreLocal2=&storeNo='
store_locals = ('서울', '경기', '인천', '강원', '경남', '광주', '대구', '대전', '부산', '제주', '충남', '충북')
sum = 0
store_lst = []
for local in store_locals:
response = requests.get(url_head + local + url_tail)
# re.sub (정규 표현식 -> 키값에 ' '가 없어 붙여줌)
quotes_json = re.sub('([a-zA-Z0-9]+) :', r"'\1' :", response.text)
# '를 "로 변경
data_json = quotes_json.replace("'", '"')
data_local = json.loads(data_json)
# 매장 총 갯수 구하기
for store in data_local:
# print(store['StoreName'],store['StoreOpendate'])
store_lst.append([store['StoreName'], store['StoreOpendate']])
sum += 1
print('총 매장 수 : ', sum)
df = pd.DataFrame(store_lst, columns = ['매장명', '오픈 시간'])
df
총 매장 수 : 135
Out[219]:
매장명 | 오픈 시간 | |
---|---|---|
0 | 삼성본관빌딩점 | 월-금 07:00-19:00 | 토/일/공휴일 휴점 |
1 | 고대안암병원신관점 | l 월~금 07:00~22:00 l 주말,공휴일 09:00~20:00 l |
2 | 압구정로데오2호점 | 월-목 08:00~23:00 | 금-토 08:00~24:00 | 일/공휴일 08:0... |
3 | 종로YBM별관점 | | 월~금 07:30~22:00 l 주말,공휴일 08:00~22:00 l |
4 | 서울시청점 | 매일 07:00-22:00 |
... | ... | ... |
130 | 부산광복동점 | 월~목 08:30-21:30 | 금~일 08:30-22:00 |
131 | 제주애월DT점 | 평일 08:00 ~ 21:00 | 주말,공휴일 07:00 ~ 22:00 |
132 | 제주아라점 | 매일 07:00~22:00 |
133 | 천안신부동점 | 평일/주말 08:30~21:00 |
134 | 청주지웰시티점 | 평일/주말 07:30~22:00 |
135 rows × 2 columns
동적 웹크롤링¶
In [261]:
# !pip install selenium
In [292]:
## 크롬 드라이버 다운로드
## 웹브라우저를 직접제어 크롤링하기
from selenium import webdriver
from bs4 import BeautifulSoup
from selenium.webdriver.common.by import By
wd = webdriver.Chrome()
wd.get('http://naver.com')
elem1 = wd.find_element(By.CLASS_NAME, "MyView-module__link_login___HpHMW") # 해당요소 찾기
elem1.click() #로그인이 클릭된 상태
# wd.back() #뒤로가기
# wd.forward() #앞으로가기
# wd.refresh() #새로고침
elem2 = wd.find_element(By.ID, "id")
elem2.send_keys('aaa') #키보드 누르기
wd.find_element(By.ID, "pw").send_keys("aaa")
wd.find_element(By.CLASS_NAME, "btn_login").click()
#현재상태의 페이지 얻기
html = wd.page_source
soup = BeautifulSoup(html,"html.parser")
'PYTHON' 카테고리의 다른 글
네이버 검색 - 웹크롤링 (2) | 2024.02.16 |
---|---|
범죄데이터 분석 & 시각화 (0) | 2024.01.21 |
global (1) | 2023.12.27 |
람다 표현식 (1) | 2023.12.27 |
함수 - 재귀호출 (0) | 2023.12.27 |