웹 페이지 다운로드

파이썬으로 인터넷 상의 웹 페이지나 파일 등을 내려받을 때는 간편하게 활용할 수 있는 Requests 라이브러리를 이용하자.

라이브러리 다운로드

명령 프롬프트에서 다음 명령어를 입력해서 Requests 라이브러리를 설치한다.

$ python -m pip install requests

기본 사용법

Requests 라이브러리를 사용하려면 먼저 파이썬 코드에서 사용할 수 있게 requests 모듈을 임포트해야 한다.

>>> import requests

그러고 나면 코드 내에서 requests 모듈에 접근해 웹 페이지를 다운로드하는 데 사용할 수 있는 API를 사용할 수 있다.

여기서는 암호화폐 거래소 중 하나인 코인원에서 제공하는 API를 이용해 이더리움의 시세를 확인해 보자. 다음과 같이 requests 모듈의 get 함수를 호출하면서 코인원 API의 URL을 전달한다. 유추했겠지만 get 함수는 HTTP의 GET 요청(request)을 수행하는 함수다.

>>> url = 'https://api.coinone.co.kr/ticker?currency=eth'
>>> r = requests.get(url)

get 함수를 호출한 결과를 r 변수에 할당했다. 그럼 이 r 변수를 가지고 API 응답과 관련된 작업을 할 수 있다.

먼저 응답 결과를 유니코드 형식으로 인코딩된 텍스트로 확인하려면 text 프로퍼티를, JSON 형태로 변환하려면 json() 메서드를 호출하면 된다.

>>> r.text
'{"result":"success","errorCode":"0","timestamp":"1655989823","currency":"eth","first":"1417000.0","low":"1372000.0","high":"1467000.0","last":"1459000.0","volume":"12746.7004","yesterday_first":"1481000.0","yesterday_low":"1399000.0","yesterday_high":"1536000.0","yesterday_last":"1415000.0","yesterday_volume":"11688.7375"}'
>>> r.json()
{'result': 'success', 'errorCode': '0', 'timestamp': '1655989823', 'currency': 'eth', 'first': '1417000.0', 'low': '1372000.0', 'high': '1467000.0', 'last': '1459000.0', 'volume': '12746.7004', 'yesterday_first': '1481000.0', 'yesterday_low': '1399000.0', 'yesterday_high': '1536000.0', 'yesterday_last': '1415000.0', 'yesterday_volume': '11688.7375'}

그럼 위와 같이 GET 요청을 통해 가져온 이더리움 시세 정보를 확인할 수 있다. 이더리움 추락의 끝은 어디일까?

텍스트나 JSON 형식의 데이터를 읽어서 처리하면 되는데, 지금은 결괏값을 곧바로 처리하기에는 JSON이 더 낫다. 다음과 같이 각 JSON 항목에 접근한다.

>>> data = r.json()
>>> data['currency']
'eth'
>>> data['first']
'1417000.0'

참고로 응답이 잘 받아왔는지 확인하려면 다음과 같은 방법으로 응답 코드를 확인한다.

>>> r.status_code
200

응답 코드 외에도 r 변수가 가리키는 Response 객체에는 다음과 같은 다양한 속성이 있다.

>>> dir(r)
['__attrs__', '__bool__', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__enter__', '__eq__', '__exit__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__nonzero__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_content', '_content_consumed', '_next', 'apparent_encoding', 'close', 'connection', 'content', 'cookies', 'elapsed', 'encoding', 'headers', 'history', 'is_permanent_redirect', 'is_redirect', 'iter_content', 'iter_lines', 'json', 'links', 'next', 'ok', 'raise_for_status', 'raw', 'reason', 'request', 'status_code', 'text', 'url']

이 가운데 자주 사용되는 항목을 몇 가지 살펴보자.

>>> r.encoding
'utf-8'
>>> r.headers
{'Date': 'Thu, 23 Jun 2022 13:10:23 GMT', 'Content-Type': 'application/json', 'Transfer-Encoding': 'chunked', 'Connection': 'keep-alive', 'CF-Cache-Status': 'DYNAMIC', 'Expect-CT': 'max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"', 'Server': 'cloudflare', 'CF-RAY': '71fd76adad5b351a-ICN', 'Content-Encoding': 'gzip'}
>>> r.encoding
'utf-8'
>>> r.reason
'OK'

앞에서 본 Response 객체의 속성 중에는 request 속성에는 요청 정보가 담겨 있다.

>>> r.request
<PreparedRequest [GET]>
>>> dir(r.request)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_body_position', '_cookies', '_encode_files', '_encode_params', '_get_idna_encoded_host', 'body', 'copy', 'deregister_hook', 'headers', 'hooks', 'method', 'path_url', 'prepare', 'prepare_auth', 'prepare_body', 'prepare_content_length', 'prepare_cookies', 'prepare_headers', 'prepare_hooks', 'prepare_method', 'prepare_url', 'register_hook', 'url']
>>> r.request.url
'https://api.coinone.co.kr/ticker?currency=eth'
>>> r.request.path_url
'/ticker?currency=eth'
>>> r.request.method
'GET'
>>> r.request.headers
{'User-Agent': 'python-requests/2.25.1', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive'}

처음에 HTTP 요청을 보낼 때 지정했던 URL을 비롯해 HTTP 메서드, 자동으로 지정되는 헤더 정보 등이 담겨 있다.

POST 전송

requests 모듈에는 GET, HEAD, POST, PUT, DELETE, OPTIONS 같은 HTTP에 각각 대응하는 함수를 모두 제공한다. 앞에서 URL에 직접 데이터를 실어서 전송하는 get 함수를 살펴봤으니 이번에는 HTTP 본문(body)에 데이터를 실어서 전송하는 POST 요청을 사용해 보자.

requests 모듈에서 POST 요청을 수행하려면 post 함수를 사용하면 되는데, 이때 전송할 데이터는 post 함수의 data 매개변수로 보내면 된다. 가령 로그인할 때 아이디와 비밀번호를 입력한 후 POST 요청을 보내는데, 이를 다음과 같이 수행할 수 있다.

>>> url = 'https://example.com/login'
>>> auth_info = {'user_id': 'my_id', 'user_pw': 'my_password'}
>>> r = requests.post(url, data=auth_info)

참고로 HTTP는 상태가 없는(stateless) 프로토콜이기 때문에 요청 간에 상태가 유지되지 않는다. 즉, 위와 같은 코드로 로그인에 성공하더라도 한 번의 요청-응답 사이클이 끝나는 순간 로그인도 끊어지게 된다. 따라서 이때는 세션을 생성해서 유지할 필요가 있다. 다음과 같이 requests 모듈의 Session 객체를 만들어 세션을 생성하고 적용해보자.

>>> url = 'https://example.com/login'
>>> auth_info = {'user_id': 'my_id', 'user_pw': 'my_password'}
>>> s = requests.Session()
>>> r = s.post(url, data=auth_info)

보다시피 Session 객체를 생성하고, Session 객체의 post 메서드를 이용해 POST 요청을 수행한다. 그런 다음 POST 요청의 결과로 반환된 응답을 r에 할당하고, 이 변수를 이용해 앞서 GET 요청과 마찬가지로 응답을 처리하면 된다.



※ 면책조항: 본 사이트에 게재된 내용에 대해 본 사이트 관리자는 어떠한 책임도 지지 않습니다.