데이터 한 그릇

데이터 크롤링(1) 본문

크롤링

데이터 크롤링(1)

장사이언스 2021. 6. 30. 17:31

urllib 모듈

 

import urllib.request
from urllib.request import urlopen
import requests

url = 'https://www.naver.com'
html = urlopen(url)
print(html.status) #응답코드

 

응답코드가 200이 나온다면 제대로 인터넷 사이트에 접속했다고 할 수 있다.

하지만 400대가 나온다면 오류가 뜬 상태.

request 모듈

url = 'https://www.naver.com'
cont = requests.get(url)
print(cont)
print(type(cont))
print(dir(cont))
print(cont.status_code)

print(cont.text) #=> 문자로 가져옴(string)
print(cont.content) #바이트 자료형으로 가져옴

 

url 을 설정해주고 request.get(<url>) 을 입력해서 사이트 정보를 받아온다.

이때 request.get(<url>) 으로 받아온 정보에 .text 를 사용하면 문자열로 받아오는 것이고 .content 를 사용하면 바이트 자료형으로 정보를 가져온 것.

정보 안에는 html 정보들이 담겨 있음 (태그, 속성 등등)

여기까지는 모든 정보를 다 가져왔다면 자신이 원하는 정보를 가져와야 한다.

예를 들어서 원하는 태그만을 가져오고 싶을 수 있고, 원하는 태그의 속성을 가져오고 싶을 수 있다.

BeatifulSoup

 

import requests
import bs4

url = 'https://www.naver.com' #여기까지 되면 데이터를 url 에서 읽어와야 됨
res = requests.get(url)#데이터를 읽어오는 콛

bs_obj = bs4.BeautifulSoup(res.text) #res.text 는 string 타입형 content가 바이트

print(bs_obj)
print(type(bs_obj))

 

request 임포트 해주고 bs4 를 임포트 해준다.

앞선 방법처럼 사이트의 정보를 모두 받아서 res 에 넣어준다.

사이트의 문자형 자료형들을 bs4 Beautiful 객체에 넣어준다.

프린트 해보면 정보가 다 나오고 있음을 알 수 있다.

 

1)find

반환 데이터 타입 tag

 

print(bs_obj.find('div')) #요소 찾기는 find
#최초로 발견되는 div를 가져온다.

find 괄호 안에 원하는 태그를 넣어주면 사이트의 모든 정보 중에서 첫 번째 원하는 태그 정보를 가져와 준다

밑의 코드는 find 예시

 

import bs4

#request.get 안하고 바로 쓰기
html_str = '<html><div>hello</div></html>'
bs_obj = bs4.BeautifulSoup(html_str,'lxml')
print(bs_obj)
print(bs_obj.find('div'))
print(type(bs_obj.find('div')))
<html><body><div>hello</div></body></html>
<div>hello</div>
<class 'bs4.element.Tag'>

 

위와 같은 결과를 가져온다.

bs_obj.find('div') 의 값은 태그가 달린 정보이다.

태그 안의 메시지를 찾고 싶다면 bs_obj.find('div').text 를 하면 된다.

 

ul = bs_obj.find('ul')
print(ul)

print('--------------------------')
ul_li = ul.find('li')
print(ul_li)
ul_li.text

 

ul 태그를 찾고 그 안에 첫 번째 li 를 찾고 싶다면

find 로 ul 을 찾고 찾은 것에서 다시 한번 find 해주면 된다.

 

bs_obj.a
print(bs_obj.find('a').get_text())
print(bs_obj.a.get_text())

 

find에서 태그 접근법이 . 만 찍어도 가능.

get_text() 로도 텍스트 접근 가능

2)find_all()

find는 하나만 가져오지만 find_all 은 해당 사항을 모두 가져온다.

 

html_str = """
<html>
    <body>
        <ul>
            <li>hello</li>
            <li>bye</li>
            <li>welcome</li>
        </ul>
    </body>
</html>
"""

bs_obj = bs4.BeautifulSoup(html_str, 'lxml')
ul = bs_obj.find('ul')
ul_li = ul.find_all('li')
print(ul_li)

for element in ul_li:
    print(element.text)
    
ul_li[0]

 

앞서서는 find를 두 번 사용해서 하나의 li 를 가져왔다면 모든 li 를 가지고 오고 싶을 때 find_all 을 사용한다.

 

s_obj.find_all('a')
bs_obj.find_all('a')[0].get_text()
bs_obj.find_all('a')[1].get_text()

 

이때 li 는 시퀀스의 특징을 가지기 때문에 인덱스를 사용할 수 있다.

하나만 가져오는 find와 . 을 사용한 접근법은 시퀀스 특징 x. 따라사 인덱스 사용 불가.

 

html_str = """
<html>
    <body>
        <ul class="greet">
            <li>hello</li>
            <li>bye</li>
            <li>welcome</li>
        </ul> 
        <ul class="reply">
            <li>ok</li>
            <li>no</li>
            <li>sure</li>
        </ul>
    </body>
</html>
"""
bs_obj = bs4.BeautifulSoup(html_str,'lxml')
ul_reply = bs_obj.find('ul', {"class":"reply"}) #속성값은 딕셔너리로
print(ul_reply)

 

find와 findall을 이용해서 특정 태그를 가져올 수 있음을 살펴봤다.

태그에 접근하여 태그를 불러올 때 특정 태그를 지목할 수 있다.

class 를 이용하는 방법이 대표적인데 , 딕셔너리를 이용해서 가져온다.

인자에 불러오고 싶은 태그를 넣어주고, 오른쪽 매개변수에 딕셔너리 형태로 클래스 명을 넣어줘서 불러온다.

 

ul_reply = bs_obj.find('ul', attrs={"class":"reply"}) #이렇게 해도 됨
ul_reply

 

attrs 를 이용해서 불러올수도 있다.

 

import bs4

html_str = """
<html>
    <body>
        <ul class="ko">
            <li>
                <a href="https://www.naver.com/">네이버</a>
            </li>
            <li>
                <a href="https://www.daum.net/">다음</a>
            </li>
        </ul>
        <ul class="sns">
            <li>
                <a href="https://www.google.com/">구글</a>
            </li>
            <li>
                <a href="https://www.facebook.com/">페이스북</a>
            </li>
        </ul>
    </body>
</html>
"""

bs_obj = bs4.BeautifulSoup(html_str,'lxml')
atag = bs_obj.find_all('a')
print(atag)

for i in atag:
    print(i['href']) #요소의 속성을 불러오기

 

지금까지 우리는 '태그' 를 불러오는 방법을 살펴봤다.

원하는 태그명을 집어 넣거나, 특정 태그를 불러오기 위해서 클래스를 이용해서 딕셔너리에 클래스명을 넣어 불러왔다.

이번에는 특정 태그의 속성을 불러오는 방법이다.

<태그>[<요소명>] 을 적어주면 태그 속성의 값을 가져올 수 있다.

 

print(bs_obj.a.attrs)
print(bs_obj.find('a').attrs)
print(bs_obj.a['href'])
print(bs_obj.a.attrs['href'])
print(bs_obj.a.get('href'))

 

태그의 요소값을 불러오는 방식은 다양하다.

 

uclass =bs_obj.find(True,{"class":'ko'})
print(uclass)

 

앞서서 딕셔너리를 이용해서 특정 클래스의 값을 가져왔는데,

단 하나만 가져왔다. 이때 태그와 상관없이 모든 특정 class 값들을 불러오고 싶다면 위와 같이

태그를 적는 란에 True를 적어준다.

 

bs_obj = bs4.BeautifulSoup(html_str,'lxml')
dv = bs_obj.find(id='result') #find 한거랑 똑같은 결과
print(dv)

 

위의 코드는 속성값을 이용하여 태그들을 가져오는 방법.

3)select_one()

 

import bs4

html_str = """
<html>
    <body>
        <ul class="ko">
            <li>
                <a href="https://www.naver.com/">네이버</a>
            </li>
            <li>
                <a href="https://www.daum.net/">다음</a>
            </li>
        </ul>
        <ul class="sns">
            <li>
                <a href="https://www.google.com/">구글</a>
            </li>
            <li>
                <a href="https://www.facebook.com/">페이스북</a>
            </li>
        </ul>
        <div id = "result">페이지</div>
    </body>
</html>
"""

bs_obj = bs4.BeautifulSoup(html_str,'lxml')
ul_li = bs_obj.select_one('ul') #find 한거랑 똑같은 결과
ul_li = bs_obj.select_one('ul>li')

 

select_one() 은 find와 똑같은 효과를 가진다.

 

4)select()

select() 는 find_all 과 같은 효과를 가진다.

 

bs_obj.select('a') #select 는 find_all 과 같은 역할

 

a태그를 모두 가져온다.

 

bs_obj.select('.ko')

 

select 안에 .<클래스명> 을 적어줘서 class가 ko인 값들을 모두 가져온다.

 

bs_obj.select('ul.sns > li:nth-of-type(2)')

 

부모, 자식의 선택자 기법을 이용해서 특정 태그도 가져올 수 있다.

406 오류가 뜰 때 웹에서 데이터를 가져오는 방법

 

import bs4
import requests

#200 이 떠야지 정상
#Response [406] 은 기계가 사이트 접속하려고 할 때 사이트에서 자체 차단하는 오류임
url = 'https://www.melon.com/'
header = {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"}
res = requests.get(url, headers = header)
bs_melon = bs4.BeautifulSoup(res.text,'lxml')
print(bs_melon)

 

header 없이 가져오게 된다면 response가 406 이 뜨게 된다.

406은 기계가 사이트 접속하려고 할 때 사이트에서 자체 차단하는 오류다.

res = requests.get(url, headers = header) 가 해결 방법.

우리가 url 을 통해서 데이터를 요청할 때 오류가 발생하는 경우,

headers 에다가 클라이언트(유저) 정보를 딕셔너리 방식으로 넣어주면 된다.

그럼 데이터 정보를 받아올 수 있다.

user-agent 경로 찾는 순서

f12 -> ctrl+r -> network -> news.naver.com -> user-agent

'크롤링' 카테고리의 다른 글

Selenium 크롤링(2) : 커피빈 크롤링  (0) 2021.07.01
Selinium 크롤링(1)  (0) 2021.07.01
크롤링 연습_할리스 커피  (0) 2021.06.30
데이터 크롤링(2)  (0) 2021.06.30
Comments