일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- AWS
- javascript
- PYTHON
- java
- 백준
- js
- 알고리즘 풀이
- 파이썬
- django rest framework
- Baekjoon
- Git
- API
- web
- Django
- Algorithm
- 장고
- CSS
- 파이썬 알고리즘
- HTML
- DRF
- 알고리즘 연습
- react
- c++
- es6
- MAC
- django ORM
- 알고리즘
- 알고리즘 문제
- django widget
- form
- Today
- Total
수학과의 좌충우돌 프로그래밍
[crawling] 02. request를 통한 HTTP 요청 - GET 본문
requests
이번에는 requests 라는 라이브러리를 통해서 본격적으로 데이터를 가져와보도록 하겠습니다. 위에서 HTTP 메소드에 대해서 이야기를 했었고 requests를 통해서 모든 메소드에 대해서 접근이 가능하지만 가장 많이 쓰이고 중요한 GET과 POST 에 대해서만 다뤄보도록 하겠습니다.
GET 요청
데이터를 불러오는 방법은 생각보다 간단합니다. 그리고 그 간단함이 바로 requests 라이브러리의 가장 큰 장점 중 하나죠.
import requests
response = requests.get('http://naver.com')
response.text
결과를 확인하면 아래와 같습니다.
'<!doctype html>\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<html lang="ko">\n<head>\n<meta charset="utf-8">\n<meta name="Referrer" content="origin">\n<meta http-equiv="Content-Script-Type" content="text/javascript">\n<meta http-equiv="Content-Style-Type" content="text/css">\n<meta http-equiv="X-UA-Compatible" content="IE=edge">\n<meta name="viewport" content="width=1100">\n<meta name="apple-mobile-web-app-title" content="NAVER" />\n<meta name="robots" content="index,nofollow"/>\n<meta name="description" content="네이버 메인에서 다양한 정보와 유용한 컨텐츠를 만나 보세요"/>\n<meta property="og:tit [생략]
단 3줄만으로 naver 의 html 코드를 가져오는데 성공했습니다. 물론 저 데이터를 바로 사용할 수는 없지만 보기 좋게 가공하는 과정은 뒤에서 다루도록 하고 지금은 데이터를 성공적으로 가져오는데 초점을 맞추도록 하겠습니다.
requests 객체의 메소드
여기서부터는 requests 를 import 하는 과정은 생략하도록 하겠습니다. 맨 위에서 했다는 전제로 진행을 하죠.
이번에는 유용하게 사용되는 requests의 메소드들을 알아보도록 하겠습니다.
response = requests.get('http://naver.com')
response.status_code
response.ok
response.content
response.text
마찬가지로 naver 메인 페이지의 정보를 가져오는 상황입니다. 결과값을 확인하고 각 쓰임들을 알아보도록 하겠습니다.
200
True
b'<!doctype html>\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<html lang="ko">\n<head>\n<meta charset="utf-8">\n<meta name="Referrer" content="origin">\n<meta http-equiv="Content-Script-Type" content="text/javascript">\n<meta http-equiv="Content-Style-Type" content="text/css">\n<meta http-equiv="X-UA-Compatible" content="IE=edge">\n<meta name="viewport" content="width=1100">\n<meta name="apple-mobile-web-app-title" content="NAVER" />\n<meta na [생략]
'<!doctype html>\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<html lang="ko">\n<head>\n<meta charset="utf-8">\n<meta name="Referrer" content="origin">\n<meta http-equiv="Content-Script-Type" content="text/javascript">\n<meta http-equiv="Content-Style-Type" content="text/css">\n<meta http-equiv="X-UA-Compatible" content="IE=edge">\n<meta name="viewport" content="width=1100">\n<meta name="apple-mobile-web-app-title" content="NAVER" />\n<meta name="robots" content="index,nofollow"/>\n<meta name="description" content="네이버 메인에서 다양한 정보와 유용한 컨텐츠를 만나 보세요"/>\n<meta property="og:tit [생략]
status_code
응답 상태 코드
를 return하게 됩니다. 응답 상태 코드란 말 그대로 HTTP 요청에 대해서 요청이 성공했는지 실패했는지 혹은 어떤 상태인지를 말해줍니다. 각 요청에 대한 건 https://developer.mozilla.org/ko/docs/Web/HTTP/Status 에서 자세히 확인하실 수 있습니다. 결과 값으로 나온200
은 성공했다는 의미입니다.
ok
- status_code의 값을 통해 값이 결정되는데 200이상 400미만, 즉 성공했을 경우에는
True
를 그렇지 않을 경우에는False
를 return 하게 됩니다. 데이터를 잘 불러오고 있나 확인이 가능하죠.
- status_code의 값을 통해 값이 결정되는데 200이상 400미만, 즉 성공했을 경우에는
content
- content는 가져온 데이터를 bytes 타입으로 return 합니다. 일반적으로는 사람이 보고 데이터를 읽을 수가 없습니다. 그렇기 때문에 인코딩 작업이 필요하죠.
text
- 예시에서도 살펴봤듯이 str 타입의 데이터를 return 합니다. 기본적으로 content 의 bytes 타입의 데이터를 인코딩하는 방식이죠. 그 결과 우리도 데이터를 쉽게 읽을 수 있습니다.
그러면 여기서 한 가지 의문이 들 수 있습니다. requests는 content를 어떤 방식으로 디코딩 하여 text로 바꿔주는지 어떻게 알 수 있을까요? 정답은 응답헤더
에 있습니다.
응답헤더
헤더의 내용을 확인하기 위해서는 headers 메소드를 사용합니다.
response = requests.get('http://naver.com')
response.headers
그 결과는 아래와 같습니다.
{'Server': 'NWS', 'Date': 'Wed, 20 Mar 2019 16:19:26 GMT', 'Content-Type': 'text/html; charset=UTF-8', 'Transfer-Encoding': 'chunked', 'Connection': 'keep-alive', 'Set-Cookie': 'PM_CK_loc=d60457a8fc51c5f539b7c71e807c9cc3f89533c169b3a46c94604f64e7dff11c; Expires=Thu, 21 Mar 2019 16:19:26 GMT; Path=/; HttpOnly', 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'P3P': 'CP="CAO DSP CURa ADMa TAIa PSAa OUR LAW STP PHY ONL UNI PUR FIN COM NAV INT DEM STA PRE"', 'X-Frame-Options': 'DENY', 'X-XSS-Protection': '1; mode=block', 'Content-Encoding': 'gzip', 'Strict-Transport-Security': 'max-age=63072000; includeSubdomains', 'Referrer-Policy': 'unsafe-url'}
보기만 해도 어려워보이지만 지금 모든 내용을 다 알 필요는 없습니다. 그래도 한 가지 알 수 있는 건 dictionary
라는 점입니다. 확인해보도록 할까요?
type(response.headers)
결과는 예상과 다릅니다.
requests.structures.CaseInsensitiveDict
맨 뒤에 Dict가 붙은걸로 봐서 Dict 과 같은 기능을 하긴 하지만 requests 만의 dictionary 입니다. 가장 두드러진 특징은 key 값으로 접근 할 때 대소문자의 구분이 없다는 점이죠.
다시 본론으로 돌아와서 저 많은 내용 중에 디코딩, 인코딩과 관련된 내용은 다음과 같이 확인할 수 있습니다.
response.headers['content-type']
결과값은 아래와 같습니다.
'text/html; charset=UTF-8'
UTF-8 방식으로 디코딩 하는걸 확인할 수 있습니다. 이 방식만 알고 있다면, text
를 사용하지 않고 content
를 직접 디코딩해서 사용할 수 있습니다. 아래와 같이 말이죠.
response.content.decode('utf8')
결과는 text
와 동일합니다.
하지만 우리 마음대로 되지는 않을 겁니다. content-type
에 charset
이 지정되어있지 않으면 어떻게 될까요? 디코딩을 제대로 하지 못해 글자를 알 수 볼 수 없을 겁니다.
한글이 깨질 때는 어떻게 해야하지?
여태까지와 동일하게 크롤링을 시도했을 때, 한글이 깨지는 경우가 발생하기도 합니다. 아래 예시를 함께 보도록 하죠.
response = requests.get('http://www.puka.co.kr/')
response.text[50:60]
알아 볼 수 없는 결과가 출력이 됩니다.
Ä¡¿øÃÑ¿¬ÇÕȸ ºÎ»êÁöÈ'
위에서도 말했듯이, 그 이유는 charset
이 지정되어 있지 않기 때문입니다.
response.headers['content-type']
결과는 아래와 같습니다.
'text/html'
이럴 경우에는 어떤 방식으로 디코딩 되었는지 직접 찾아줘야 합니다. 해당 사이트로 접속한 후에, 다음과 같은 방법으로 페이지의 html 코드를 확인할 수 있습니다.
오른쪽 마우스 -> 페이지 소스보기
meta 태그
를 찾고 charset 이 어떻게 지정되어 있는지를 확인합니다.
<meta http-equiv="Content-Type" content="text/html; charset=euc-kr">
euc-kr
를 이용해서 디코딩하면 원하는 결과를 얻을 수 있을 겁니다.
# 방법 1
response.content.decode('euc-kr')
# 방법 2
response.encoding = 'euc-kr'
response.text
방법 1은 content
의 내용을 직접 디코딩하는 방식이고, 방법 2는 인코딩 방식을 알려줘서 text
가 제대로 된 방식을 찾도록 도와줍니다. 결과로 반가운 한글을 확인할 수 있습니다.
'\r\n<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">\r\n<html>\r\n<head>\r\n<title>::: 한국유치원총연합회 부산지회 :::</title>\r\n<meta h
queryString
뜬금없이 또 생소한 단어가 나왔지만 집고 넘어가야 할 부분입니다. 먼저 용어에 대한 설명부터 하자면,
웹 클라이언트에서 서버로 전달하는 데이터 방식
우리는 기존에 웹 클라이언트가 서버로 데이터를 전달할 때 url 을 통해 전달한다는 사실을 알았습니다. 그리고 url을 살펴보도록 하죠. 제가 아까 본 네이버 스포츠 뉴스의 기사입니다.
https://sports.news.naver.com/basketball/news/read.nhn?oid=065&aid=0000178691
우리가 주목해야할 부분은 ?
이후의 부분으로서 바로 이 부분을 queryString
이라고 합니다. & 와 = 을 통해 값들을 연결하고 있는데 이는 dictionary에서 , 와 : 에 대응됩니다. 즉 위 url 에서의 queryString 을 dictionary 로 나타내면 다음과 같습니다.
{'oid':'065', 'aid':'0000178691'}
그리고 복잡해보이던 위 url 을 좀 더 가독성 좋게 표현할 수 있습니다.
params = {'oid':'065', 'aid':'0000178691'}
response = requests.get('https://sports.news.naver.com/basketball/news/read.nhn', params = params)
response.text[520:560]
params 를 통해 queryString 에 해당하는 부분을 dictionary 로 넘겨줘도 데이터를 잘 불러올 수 있습니다.
[KBL시상식] 1위와 MVP의 엇갈림, 현대모비스와 KCC의 희비
'웹프로그래밍 > crawling' 카테고리의 다른 글
[crawling] 03. BeautifulSoup으로 웹 크롤링 하기 (0) | 2019.03.22 |
---|---|
[crawling] 01.크롤링을 알기 전, HTTP (0) | 2019.03.14 |