본게시글은 HTTP 헤더 이해와 Requests의 설치가 되어있어야 합니다. (바로가기)
또한 requests의 라이브러리를 자세하게 살펴보는 게시글 입니다.
Requests: HTTP for Humans 공식문서 바로가기
단순 GET 요청
사용방법
1 2 3 4 5 6 7 8 9 | import requests response = requests.get('https://www.naver.com') .post .put .delete .head .options .trace | cs |
주의사항
그대로 받아와서 response를 출력한다면 1과 같이 응답 코드가 등장하므로
2번과 같이 .text를 통하여 변환을 시켜주고 출력하셔야 정상적으로 출력이 됩니다.
html코드는 어디서 오는것일까?
크롬환경에서 f12키를 누르시면 코드가 나오는데 이 코드를 가져오는것입니다.
beautiful soup을 활용한 크롤링 (많은 html코드중 제가 원하는 부분을 잘라보겠습니다)
일단은 마우스 우클릭->페이지 소스보기로 살펴보겠습니다.
코드를 살펴보면 영화 순위 테이블을 발견할 수 있습니다
우리는 이것을 영화제목만 뽑아보겠습니다.
1 2 3 4 5 | import requests response = requests.get('http://movie.naver.com/movie/sdb/rank/rmovie.nhn?sel=cnt&date=20170714') html = response.text print(html) | cs |
코드를 통해
실행을 확인해 보면
잘나오네요 여기서 이제 BeautifulSoup를 통해 원하는 랭킹만 뽑아보겠습니다.
자세히 보시면 div class="tit3">의 규칙성을 보이는것을 확인하실수 있습니다.
이제 이렇게 잘라보겠습니다.
1 2 3 4 5 6 7 8 9 | import requests response = requests.get('http://movie.naver.com/movie/sdb/rank/rmovie.nhn?sel=cnt&date=20170714') html = response.text from bs4 import BeautifulSoup #BeautifulSoup import soup = BeautifulSoup(html, 'html.parser') #html.parser를 사용해서 soup에 넣겠다 soup.select('div[class=tit3]')#div[class=tit3]인 애들만 선택해서 출력하 | cs |
코드 추가 하겠습니다.
출력이 잘되지만 불필요한 태그가 껴있으니 없애보겠습니다.
1 2 3 4 5 6 7 8 9 10 | import requests response = requests.get('http://movie.naver.com/movie/sdb/rank/rmovie.nhn?sel=cnt&date=20170714') html = response.text from bs4 import BeautifulSoup #BeautifulSoup import soup = BeautifulSoup(html, 'html.parser') #html.parser를 사용해서 soup에 넣겠다 for tag in soup.select('div[class=tit3]'): print(tag.text) | cs |
반목문을 사용해서 tit3에 있는 텍스트만 뽑아보겠습니다
깔끔하게 출력되지만 공백이 아쉽네요
공백을 없애보겠습니다.
1 2 3 4 5 6 7 8 9 10 | import requests response = requests.get('http://movie.naver.com/movie/sdb/rank/rmovie.nhn?sel=cnt&date=20170714') html = response.text from bs4 import BeautifulSoup #BeautifulSoup import soup = BeautifulSoup(html, 'html.parser') #html.parser를 사용해서 soup에 넣겠다 for tag in soup.select('div[class=tit3]'): print(tag.text.strip()) | cs |
출력할때 공백을 제거하는 .strip()을 사용해봅시다
예쁘게 출력됩니다.
requests를 사용하지 않고 BeautifulSoup의 사용 바로가기
이 코드를 보시면 똑같은 영화 리스트를 출력하였는데 코드가 좀더 복잡한 것을 보실수 있습니다.
urllib를 사용하였는데 조금더 복잡한 것을 확인하실 수 있습니다.
때문에 저는 requests와 함께 사용하는 것을 추천하겠습니다.
GET요청시 커스텀헤더 지정
1 2 3 4 5 6 7 8 9 10 11 12 13 | import requests response = requests.get('http://movie.naver.com/movie/sdb/rank/rmovie.nhn?sel=cnt&date=20170714') html = response.text ##==========커스텀 헤더============## request_headers = { 'User-Agent': ('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 ' '(KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36'), 'Referer': 'http://movie.naver.com/movie/sdb/rank/rmovie.nhn?sel=cnt&date=20170714', # 영화랭킹 } response = requests.get('http://movie.naver.com/movie/sdb/rank/rmovie.nhn?sel=cnt&date=20170714', headers=request_headers) print(response) | cs |
request_headers={}안에 ()는 1줄입니다.
만약 전에 사용하던 default헤더가 있다면 오버라이트와 함께 재정의됩니다.
User-Agent 출처는 nomade.kr 강의입니다.
결과확인
이렇게 사용자가 직접 헤더를 커스텀해서 요청을 보내도 올바른 응답이 오는것을 확인하실 수 있습니다.
GET요청시 GET인자 지정하기
비교실험화면
@다수의 지정이 불가능한 dict 지정 예제
1 2 3 4 5 6 | import requests #get_params = (('k1', 'v1'), ('k1', 'v3'), ('k2', 'v2')) get_params = dict([('k1', 'v1'), ('k1', 'v3'), ('k2', 'v2')]) response = requests.get('http://httpbin.org/get', params=get_params) print(response.json()) | cs |
결과값을 보시면 k1이라는 키에는 v3만 들어가 있습니다.
v1은 처음에 들어갔지만 v3으로 오버라이팅 되었기 때문에 v3만 표현되겠습니다.
@다수 지정이 가능한 tuple 지정 예제
1 2 3 4 5 | import requests get_params = (('k1', 'v1'), ('k1', 'v3'), ('k2', 'v2')) response = requests.get('http://httpbin.org/get', params=get_params) print(response.json()) | cs |
http://httpbin.org는 http의 응답을 보내주는 사이트입니다. 제가 요청했을때 응답이 오면 제대로 요청한 것을 확인할 수 있기 때문에 예제 사이트로 지정했습니다.
결과를 보시면 k1이라는 Key에 v1, v3의 값이 들어가는것을 확인할 수 있습니다.
웹에서는 동일키를 지원해주기 때문에 다수의 인자값 지정이 가능한 tuple타입으로 사용하는게 맞다고 보면 됩니다. 그렇다고 dict타입을 사용하지 않는게 아닙니다. 사용해야 할때도 있기 때문에 필요에 따라 사용하시면 되겠습니다.
응답헤더
content-type이나 Content-Type 대소문자 가리지 않고 출력되는것을 확인하실 수 있습니다.
응답 body
1 2 3 4 | with open('flower.jpg', 'wb') as f: #flower.jpg를 열고 / f: 파일 오브젝트 획득 f.write(response.content) #response.content이미지 데이터를 가지고 파일에다(f) 데이터를 씀(write) | cs |
1 2 3 4 5 6 7 | html = response.text #.text 사용해서 html코드 획득 html = response.content.decode('utf8') #response.content를 사용하여 decode를 획득 가능 #두가지 방법중 원하는 것을 사용하면 | cs |
응답이 json포맷일경우
이렇게 json파일도 원하는 값만 가져올 수 있는데 이것을 deserialize 라고 합니다.
보기쉽죠?
이렇게 json파일도 원하는 값만 가져올 수 있는데 이것을 deserialize 라고 합니다.
(2)번이 조금다 간결해서 (2)사용을 추천합니다.
HTTP POST요청
단순 POST 요청
get과 똑같지만 get대신 post를 사용하는 점만 다릅니다. 참쉽죠?
POST요청시 커스텀헤어, GET인자 지정
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | import requests request_headers = { 'User-Agent': ('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 ' '(KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36'), 'Referer': 'http://httpbin.org', } get_params = {'k1': 'v1', 'k2': 'v2'} response = requests.post( 'http://httpbin.org/post', headers=request_headers, params=get_params) print(response) | cs |
GET요청시 커스텀헤더와 똑같습니다. 단지 get을 post로 바꿨다는 점 말고는요(9번째줄)
하지만 12번째 줄을 보시면 get_params로 해주는것에 의문이 생길수 있는데 왜 그런것일까요?
12번째줄의 params는 무조건 get_params만 올수 있습니다. 무조건 get인자이며 post는 다르게 해줘야함
그렇다면 get 인자가 도대체 무엇일까?
http://news.naver.com/main/main.nhn?mode=LSD&mid=shm&sid1=103 가 주소라는것은 다 아실것입니다.
그 주소 안에 ?부터 있는 mode=LSD&mid=shm&sid1=103 가 GET인자가 되는 것입니다.
그래서 이 주소에 대한 POST요청을 날린다고 말할수 있으니 POST요청에서는 GET인자를 사용할 수 있다 볼 수 있습니다.
정리하자면
params는
GET인자일때는 GET인자만 지정이 가능하지만
POST인자 일때는 GET POST 둘다 지정이 가능합니다.
일반적인 form 전송/요청
앞서 GET요청의 GET인자의 경우 params=get_params였지만
글쓰기의 인자는 post로 하기 때문에 인자도 data=data or fields=fields로 지정해 줄 수 있습니다.
둘다 사용도 가능합니다
get인자와 post인자를 둘다 data로 지정할 경우 get인자로는 get인자로 post인자는 post로 data를 보내게 됩니다.
json으로 출력해보면 form으로 잘들어 오는것을 확인하실 수 있습니다.
?mode=LSD&mid=shm&sid1=103 이렇게 쓰는것을 말합니다.
key=value & key=value .....이며json으로 출력했을때 form으로 잘 넘어오는 것을 확인하실 수 있습니다.
JSON POST 요청
서버에서 JsonAPI를 지원하는데 그때 우리가 맞춰서 데이터를 올려 보내보겠습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 | import requests import json json_data = {'k1': 'v2', 'k2': [1,2,3], 'name': 'rednooby'} # json포맷 문자열로 변환 후, data인자로 지정 json_string = json.dumps(json_data)#문자열로 변환 response = requests.post('http://httpbin.org/post', data=json_data)#서버로 보낸다 response = requests.post('http://httpbin.org/post', json=json_data) #json= 으로 처리해주면 내부에서 자동으로 json.dump 처리를 하기때문에 7째줄이 필요없겠죠 print(response) print(response.json()) |
무엇이 다른가 살펴보면 앞에서 한 출력값들은 args나 form에 데이터들이 들어있었지만 이번에는 data에 들어있는 것을 확인할 수 있습니다.
파일 업로드 요청
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | import requests from bs4 import BeautifulSoup files = { 'photo1': open('C:\\f1.jpg', 'rb'),#rb: 읽기 바이러니모드 'photo2': open('C:\\f2.jpg', 'rb'), 'photo3': ('f3.jpg', open('C:\\f3.jpg', 'rb'), 'image/jpeg', {'Expires': '0'}), # 파일명 파일오브젝트 컨텍트타입 헤더 #photo1과 2는 단순하기 때문에 3처럼 넣는것이 베스트 } post_params = {'k1': 'v1'} response = requests.post('http://httpbin.org/post', files=files, data=post_params) print(response) print(response.json()) | cs |
files에 파일이 전송된것을 확인할 수 있습니다.
파일은 경로내에 동일한 이름의 파일이 있어야 하며 files에 있는 값은 json으로 변경된 값입니다.
post_params는 form에 응답이 잘 와있습니다.
이것을 왜 알아야 하는가?(마무리 정리)
'파이썬 프로그래밍 > 파이썬 크롤링' 카테고리의 다른 글
[Python] 크롤링 연습문제. reddit 크롤링 풀이 (0) | 2017.07.18 |
---|---|
[Python] BeautifulSoup4 라이브러리와 기초 (멜론차트 크롤링) (3) | 2017.07.17 |
[Python] 크롤링 기초 개념과 requests를 이용한 기초실습(설치부터) (1) | 2017.07.15 |
[Python] 파이썬의 Beautiful Soup를 이용한 파싱 (9) | 2016.05.19 |
[Python] 파이썬을 이용한 크롤링 (2) | 2016.05.19 |