안녕, 세상!

데이터 크롤링(스크래핑) 기본 본문

It공부/Data science

데이터 크롤링(스크래핑) 기본

dev_Lumin 2021. 2. 4. 00:15

( 본 글의 크롤링은 크롤링이라기보다 스크래핑이 더 가깝습니다.

 보통 사람들이 스크래핑도 크롤링이라고 부르는 경향이 있는 것 같습니다.

 저도 일단 대중적인 표현으로 크롤링이라고 표현하겠습니다만

 이 부분을 염두해주고 봐주시면 감사하겠습니다. )

 

(1) 크롤링이란

크롤러(crawler)는 자동화된 방법으로 웹을 탐색하는 컴퓨터 프로그램을 말합니다.

 

① 웹 크롤러(web crawling) 

웹 서비스 내 정보를 수집하는 일입니다.

웹에서 필요한 정보가 있다면 API를 확인하고, API가 없다면 직접 크롤링을 해야 합니다.

다만 직접 크롤링을 하는 것은 웹 서비스 제공자의 입자에서는 별로 좋지 않을 것입니다.

 

② 웹 크롤링의 전반적인 과정

1. 정보를 가져오고자 하는 url 정의

 

2. url 정보로 requests로 정보 요청 

    requests는 요청한 정보를 받을 수 있지만 text로만 받습니다. 

 

3. text 정보를 html로 변환

 

4. html, json에서 우리가 필요한 정보만 선별

 

html의 경우 : BeautifulSoup 사용

json의 경우 : json을 decoding 해서 사용 (json -> dict

 

 

이제 간단한 크롤링 작업을 해보겠습니다.

크롤링 작업 환경 : Anaconda Jupyter notebook

(2) 간단한 크롤링

import numpy as np
import pandas as pd
import requests
from bs4 import BeautifulSoup

url = 'https://naver.com'

# requests로 url에 정보요청
response = requests.get(url) 
response

requests 해서 얻은 정보에 대한 응답은 크게 5가지로 나뉩니다.

 

100 : 서버는 요청한 부분의 일부를 받았고 나머지를 기다리고 있음을 나타냄 (유저는 계속 요청을 보내야 함) 

200 : 접속 성공

300 : 사이트의 도메인이 변경될 경우이며, 변경된 도메인으로 안내해줌

400 : 유저가 요청을 잘못했을 경우

500 : 서버 문제

 

보통 response [200]이 나오면 접속이 잘 된 것입니다.

 

이제 받은 request내용을 텍스트 형태로 한 번 봅니다.

response.text

그럼 텍스트를 보고 해당 내용이 html형식인지 json형식인지 파악할 수 있습니다.

위의 경우 html형식이 나왔습니다.

 

html형식이 보이므로 이제 이 text를 BeautifulSoup를 이용하여 html로 바꿔줍니다.

html = BeautifulSoup(response.text, 'html.parser')
html

html형태로 잘 바뀐 것을 확인할 수 있습니다.

 

여기까지의 과정을 통해서 특정 주소의 페이지에 있는 데이터를 얻을 수 있으며,

이를 html혹은 json형태로 바꿔서 필요한 부분을 추출할 수 있을 것이라는 사실을 알 수 있습니다.

그렇다면 어떻게 원하는 부분을 추출할 수 있을까요?

 

html의 경우 tag들을 통해 원하는 데이터에 접근할 수 있으며,

json의 경우 indexing을 통해 원하는 데이터에 접근할 수 있습니다.

 

 

(3) 원하는 데이터에 접근

우선 위에서 html의 텍스트가 나왔으니 위의 실습 기반으로 html의 tag를 이용해 특정 데이터에 접근을 해보겠습니다.

html에 여러 tag가 있는데 그중에 <span> 태그에 접근해보겠습니다.

import numpy as np
import pandas as pd
import requests
from bs4 import BeautifulSoup

# url정의
url = 'https://naver.com'

# requests로 url에 정보요청
response = requests.get(url)    

# 정보를 html 변환
html = BeautifulSoup(response.text, "html.parser")

html.select('span')[0:10]

이렇게 특정 정보들을 나름 추출할 수 있다는 것을 확인할 수 있습니다.

코드를 보면 select함수를 사용하고 매개변수를 html의 특정 tag를 사용한다는 것을 확인할 수 있습니다.

이렇게 html의 특정 tag에 접근할 수 있도록 하는 것을 셀렉터(selector)라고 합니다.

 

셀렉터

html에서 원하는 내용을 tag를 통해 접근하여 얻을 수 있는 메소드입니다.

 

① 단일 셀렉터

단일 태그에만 접근합니다. 

태그 안에 여러 정보들이 있는데 해당 정보들에 대해서 셀렉터 메소드에서 다음과 같이 입력하면 됩니다.

 

  • tag  :  태그명           ex) span
  • class  :  .클래스명      ex) .blind
  • id(고유값)  :  #id값     ex) #1234

id는 페이지에 딱 한 개 밖에 없는 고윳값이므로 단일로 가져올 수 있습니다.

 

② 복합 셀렉터

1. 조합 셀렉터

태그 안에 여러 정보가 있다고 했는데 태그 안의 여러 정보로 좀 더 구체적으로 접근합니다.

예시를 들어서 설명하겠습니다.

태그 이름이 span이고 클래스 이름이 apple인 라인을 찾고 싶다   :  span.apple

li 태그 중에서 id가 banana인 라인을 찾고 싶다  :   li#banana

 

2. 경로 셀렉터

조합 셀렉터보다 더 구체적이며 경로 형태로 특정 라인을 접근합니다.

예시를 들어서 설명하겠습니다.

ul 태그 안 li 태그 안 span 라인을 찾고 싶다  :  ul > li > span

 

 

원하는 데이터에 접근하는 또 다른 좋은 방법은

해당 크롬 브라우저 환경에서 특정 웹 주소에서 개발자 도구를 사용하는 것입니다.

(4) 개발자 모드

이제부터 하는 실습 환경은 크롬 브라우저가 반드시 있어야 합니다.

크롬 브라우저에는 개발자 도구(developer tool)가 있습니다.

이 개발자 도구로 원하는 부분의 정보를 추출할 수 있습니다.

개발자 도구는 다음과 같이 실행시킬 수 있습니다.

또는 크롬 환경에서 단축키로 f12를 누르면 개발자 도구가 창 한쪽에서 나옵니다.

 

네이버에 '로또번호'라고 검색해보고 개발자 도구를 실행시켜보겠습니다.

위의 사진에서 초록색 네모 박스 버튼 부분을 누른 채

해당 웹페이지의 특정 부분을 마우스로 올리면 다음과 같이 해당 부분에 대한 html 코드를 확인할 수 있습니다.

 

이를 통해 원하는 부분의 데이터의 html 코드가 무엇인지 알 수 있습니다.

이제 코드를 알았으니 무슨 태그 인지도 알게 되는 것입니다.

로또 번호에 대한 태그는

<span class="num ball30"> </span> 입니다.

여기서 클래스 부분을 보면 num과 ball30이 띄어쓰기로 구분되어 있는데 이는 서로 다른 클래스입니다!

둘 중 어떤 클래스의 데이터를 추출할지는 유저의 역량입니다.

 

 

이번에는 위의 로또번호 6개를 추출해보겠습니다.

import numpy as np
import pandas as pd
import requests
from bs4 import BeautifulSoup
url = 'https://search.naver.com/search.naver?where=nexearch&sm=top_hty&fbm=0&ie=utf8&query=로또'
response = requests.get(url)
html = BeautifulSoup(response.text, "html.parser")
html.select('span.num')

url을 지정할 때 복붙 하게 된다면 검색 단어 부분은 특수문자로 변환돼서 복사가 될 텐데

검색 단어로 바꿔줘야 합니다.

(url 부분 중 '로또'부분을 말하는 것입니다.)

 

앞서 로또번호에 대한 태그가 span안에 num클래스인 것을 알았으므로

'span.num'으로 셀렉터를 지정합니다.

 

위의 코드 결과는 다음과 같이 나올 것입니다.

여기서 중요한 것은 html.select() 즉 셀렉터를 통해 나온 결과가 리스트로 나온다는 것입니다.

이는 인덱싱이 가능한 것입니다.

그렇다면 원하는 로또번호 6개만 인덱싱을 하여 추출해보겠습니다.

for num in html.select('span.num')[:6]:
    print(num)

로또 번호 6개에 대한 라인을 추출했지만 아직 만족스러운 결과는 아닙니다.

필자는 로또번호 값을 추출하고 싶습니다.

이는 다음과 같이 함으로써 해결할 수 있습니다.

lotto_list=[]
for num in html.select('span.num')[:6]:
    lotto_list.append(num.text)
lotto_list

다음과 같이 특정 리스트에 번호를 추출하여 잘 저장한 것을 확인할 수 있습니다.

 

 

Comments