빅데이터 서비스 교육/크롤링

크롤링 기초

Manly 2022. 5. 12. 12:47
반응형

# 크롤링 : 주로 인터넷상의 웹페이지를 수집해서 분류하고 저장하는 것

 

# server로 request 하는 라이브러리

import requests as req

 

url = 'https://www.naver.com/'
req.get(url) # server로 부터 response 된 웹페이지정보를 가져온다.


#<Response [200]> : 응답성공

<Response [200]>

url = 'https://www.melon.com/'
req.get(url)

# <Response [406]> : 응답실패   

<Response [406]>

 

네이버 블로그 글자 가져오기

url = 'https://www.naver.com/'
res = req.get(url) # server로 부터 response 된 웹페이지정보를 가져온다.
res.text

'\n<!doctype html>                
<html lang="ko" data-dark="false"> <head> <meta charset="utf-8"> <title>NAVER</title> 
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=1190"> 
<meta name="apple-mobile-web-app-title" content="NAVER"/> <meta name="robots" content="index,nofollow"/>
<meta name="description" content="네이버 메인에서 다양한 정보와 유용한 컨텐츠
......................

이중 블로그를 찾아서 가져오기 힘들기 때문에

Beautifulsoup 사용

  • 웹페이지 정보를 파싱해주는 라이브러리

from bs4 import BeautifulSoup as bs

# 파싱할 데이터, 파싱방법
bs(res.text, 'lxml')

<!DOCTYPE html>
<html data-dark="false" lang="ko"> <head> <meta charset="utf-8"/> 
<title>NAVER</title> <meta content="IE=edge" http-equiv="X-UA-Compatible"/> 
<meta content="width=1190" name="viewport"/> <meta content="NAVER" name="apple-mobile-web-app-title"/>
<meta content="index,nofollow" name="robots"/>
<meta content="네이버 메인에서 다양한 정보와 유용한 컨텐츠를 만나 보세요" name="description"/>
....................

파싱을 해서 문자열에서 위와 같이 바뀌었다

 

soup.select() 로 원하는 태그만 가져올 수 있다.

블로그는 a태그에 들어 있으므로

 

soup.select('a')

[<a href="#newsstand"><span>뉴스스탠드 바로가기</span></a>,
 <a href="#themecast"><span>주제별캐스트 바로가기</span></a>,
 <a href="#timesquare"><span>타임스퀘어 바로가기</span></a>,
 <a href="#shopcast"><span>쇼핑캐스트 바로가기</span></a>,
 <a href="#account"><span>로그인 바로가기</span></a>,
 ......

네이버 페이지에 있는 a태그가 전부 나왔는데 위에서 본 블로그의 class명 nav로 찾는다.

 

soup.select('a.nav')

[<a class="nav" data-clk="svc.mail" href="https://mail.naver.com/"><i class="ico_mail"></i>메일</a>,
 <a class="nav" data-clk="svc.cafe" href="https://section.cafe.naver.com/">카페</a>,
 <a class="nav" data-clk="svc.blog" href="https://section.blog.naver.com/">블로그</a>,
 <a class="nav" data-clk="svc.kin" href="https://kin.naver.com/">지식iN</a>,
 <a class="nav shop" data-clk="svc.shopping" href="https://shopping.naver.com/"><span class="blind">쇼핑</span></a>,
 <a class="nav shoplive" data-clk="svc.shoppinglive" href="https://shoppinglive.naver.com/home"><span class="blind">쇼핑LIVE</span></a>,
 <a class="nav" data-clk="svc.pay" href="https://order.pay.naver.com/home">Pay</a>,
 <a class="nav" data-clk="svc.tvcast" href="https://tv.naver.com/"><i class="ico_tv"></i>TV</a>,
 <a class="nav" data-clk="svc.dic" href="https://dict.naver.com/">사전</a>,
 <a class="nav" data-clk="svc.news" href="https://news.naver.com/">뉴스</a>,
 <a class="nav" data-clk="svc.stock" href="https://finance.naver.com/">증권</a>,
 <a class="nav" data-clk="svc.land" href="https://land.naver.com/">부동산</a>,
 <a class="nav" data-clk="svc.map" href="https://map.naver.com/">지도</a>,
 <a class="nav" data-clk="svc.vibe" href="https://vibe.naver.com/">VIBE</a>,
 <a class="nav" data-clk="svc.book" href="https://book.naver.com/">책</a>,
 <a class="nav" data-clk="svc.webtoon" href="https://comic.naver.com/">웹툰</a>]
​

a태그이면서  Class명이 nav인것들이 나온다.   여기서 나온 자료형은 [] 안에 있는 리스트형 이므로 인덱싱이 가능하다

 

soup.select('a.nav')[2]

<a class="nav" data-clk="svc.blog" href="https://section.blog.naver.com/">블로그</a>

soup.select('a.nav')[2].text

'블로그'

# 네이버 검색 결과 가져오기
# 1. 가져오고 싶은 데이터가 있는 url 요청
# 2. 가져온 웹페이지 정보 파싱
# 3. select를 활용하여 원하는 데이터 가져오기

url = 'https://search.naver.com/search.naver?where=nexearch&sm=tab_jum&query=%ED%8C%8C%EC%9D%B4%EB%A6%AC'
res = req.get(url)
res.text

 

soup = bs(res.text, 'lxml')

 

soup.select('a.link_tit')[0].text

' 파이리 - 나무위키 '

 

멜론페이지 응답받기

network -> f5로 표시 후 아무거나 클릭해서 -> headers에서 User-Agent

h = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36'}

 

딕셔너리형으로 {}에 넣어주고 키값, 벨류값을 문자형으로

 

url = 'https://www.melon.com/'
res = req.get(url, headers = h)
res

<Response [200]>

 

멜론차트, 최신음악...... 어학 까지 글자만 가져오기

이때 class명은 menu_bg menu01~ 인데 이중 클래스로 'span.menu_bg.menu01'로 쓰면 메뉴 01만 가져오므로

'span.menu_bg'를 쓰면 멜론차트~어학까지 전부 가져 올 수 있다.

 

 

soup = bs(res.text, 'lxml')
for i in soup.select('span.menu_bg'):
    print(i.text)

멜론차트
최신 음악
장르 음악
멜론DJ
멜론TV
스타포스트
매거진
뮤직어워드
어학
마이뮤직

 

# 멜론차트에서 1위부터 100위까지 제목 가져오기
url = 'https://www.melon.com/chart/index.htm'
res = req.get(url, headers = h)
res.text

 

soup = bs(res.text, 'lxml')
title = soup.select('div.ellipsis.rank01 > span>a')          -> > span>a   개행을 없애기위해서 썼다.
for i in title:
    print(i.text)                                  -># print(i.text.strip()) :    strip() 문자열 \n, \t 삭제

 

soup = bs(res.text, 'lxml')
title = soup.select('div.ellipsis.rank01 > span>a')
for i in title:
    print(i.text)
soup = bs(res.text, 'lxml')
title = soup.select('div.ellipsis.rank01 > span>a')
for i in title:
    print(i.text)
That That (prod. & feat. SUGA of BTS)
봄여름가을겨울 (Still Life)
LOVE DIVE
TOMBOY
사랑인가 봐
사랑은 늘 도망가
우리들의 블루스
Feel My Rhythm
다시 만날 수 있을까
LOVE me
GANADARA (Feat. 아이유)
정이라고 하자 (Feat. 10CM)
........................

# 멜론 차트 1~100 가수 가져오기

url = 'https://www.melon.com/chart/index.htm'
res = req.get(url, headers = h)
soup = bs(res.text, 'lxml')
singer = soup.select('div.ellipsis.rank02 >a:nth-child(1)')    -> 가수가 여려명일때 처음 가수 한명만    :nth-child(1)
for i in singer:
    print(i.text)

싸이 (PSY)
BIGBANG (빅뱅)
IVE (아이브)
(여자)아이들
멜로망스
임영웅
임영웅
Red Velvet (레드벨벳)
임영웅
박재범
BE'O (비오)
BIG Naughty (서동현)
김민석 (멜로망스)
.........

 

데이터프레임 만들기

import pandas as pd

title_list = []
singer_list = []
rank_list = []

for i in range(len(title)):
    title_list.append(title[i].text.strip())
    singer_list.append(singer[i].text.strip())
    rank_list.append(i+1)

print(len(title_list))
print(len(singer_list))
print(len(rank_list))

100
100
100

dic = {'순위' : rank_list, '제목' : title_list, '가수' : singer_list}

df = pd.DataFrame(dic)
df

	순위	제목	가수
0	1	That That (prod. & feat. SUGA of BTS)	싸이 (PSY)
1	2	봄여름가을겨울 (Still Life)	BIGBANG (빅뱅)
2	3	LOVE DIVE	IVE (아이브)
3	4	TOMBOY	(여자)아이들
4	5	사랑인가 봐	멜로망스
...	...	...	...
95	96	Christmas Tree	V
96	97	나는 트로트가 싫어요	태일 (TAEIL)
97	98	낙하 (with 아이유)	AKMU (악뮤)
98	99	Starlight	임창정
99	100	Darl+ing	세븐틴

df = df.set_index('순위', inplace =True)           # 순위를 인덱스로
df

 

#rename, drop등의 메서드를 사용할 때, 변경 값(변경될 데이터 프레임)을 저장 할 때 사용

inplace = False (저장 안 함)

inplace = True (저장함)

	제목	가수
순위		
1	That That (prod. & feat. SUGA of BTS)	싸이 (PSY)
2	봄여름가을겨울 (Still Life)	BIGBANG (빅뱅)
3	LOVE DIVE	IVE (아이브)
4	TOMBOY	(여자)아이들
5	사랑인가 봐	멜로망스
...	...	...
96	Christmas Tree	V
97	나는 트로트가 싫어요	태일 (TAEIL)
98	낙하 (with 아이유)	AKMU (악뮤)
99	Starlight	임창정
100	Darl+ing	세븐틴

 

# 네이버 영화랭킹에서 영화명 / 평점 가져오고 데이터 프레임까지 만들기

url = 'https://movie.naver.com/movie/sdb/rank/rmovie.naver?sel=cur&date=20220511'
res = req.get(url)
soup = bs(res.text,'lxml')
title = soup.select('div.tit5')    #'div.tit5 > a'
for i in title:
    print(i.text.strip())

씽2게더
극장판 귀멸의 칼날: 무한열차편
극장판 주술회전 0
피아니스트의 전설
벤허
코다
피의 연대기
비긴 어게인
중경삼림
화양연화
찬실이는 복도 많지
바닷마을 다이어리

......

 

평점

 

score=soup.select('td.point')
for i in score:
    print(i.text.strip())

9.39
9.27
9.26
9.25
9.23
9.14
9.09
9.04
8.90
8.81
8.77
8.73

......

title_list=[]
score_list=[]
rank_list=[]
for i in range(len(title)):
    title_list.append(title[i].text.strip())
    score_list.append(score[i].text.strip())
    rank_list.append(i+1)

 

dic = {'순위':rank_list,'영화제목':title_list, '평점':score_list}
df = pd.DataFrame(dic)
df = df.set_index('순위')
df

	영화제목	평점
순위		
1	씽2게더	9.39
2	극장판 귀멸의 칼날: 무한열차편	9.27
3	극장판 주술회전 0	9.26
4	피아니스트의 전설	9.25
5	벤허	9.23
6	코다	9.14
7	피의 연대기	9.09
8	비긴 어게인	9.04
9	중경삼림	8.90
10	화양연화	8.81
11	찬실이는 복도 많지	8.77
12	바닷마을 다이어리	8.73
13	귀향	8.67
14	배드 가이즈	8.67
15	세자매	8.67
16	안경	8.64
17	라라랜드	8.62
18	공기살인	8.60
19	나쁜 교육	8.46
20	아비정전	8.45
21	드라이브 마이 카	8.41
22	모가디슈	8.33
23	신은 죽지 않았다 3: 어둠 속의 빛	8.32
24	어나더 라운드	8.30

......................
반응형