본문 바로가기
NLP

Chapter 2. API로 추출하는 텍스트 속 통찰

by Night Fury 2023. 3. 26.

젠스 알브레히트, 시다르트 라마찬드란, 크리스티안 윙클러, 『파이썬 라이브러리를 활용한 텍스트 분석 Blueprints for Text Analytics Using Python』, 심상진, 한빛미디어-OREILLY(2022), p69-96.

Learned

API

통신할 수 있도록 해주는 인터페이스

  • 사용자가 소프트웨어 응용 프로그림애나 구성 요소, 서비스 등이 어떻게 구현되는지 몰라도 됨
  • 사용할 수 있는 요청의 종류, 사용되는 데이터 형식, 예상 응답을 포함하는 일련의 정의 및 프로토콜을 제공
  • 웹사이트 스크랩보다 선호되는 접근 방식
    • 호출 가능한 함수로 설계됨
    • 사용하기 쉽고 자동화할 수 있음
  • 데이터가 자주 변경되거나 프로젝트에 최신 정보를 반영해야 할 때 권장

SOAP vs REST vs GraphQL

  • SOAP (Simple Object Access Protocol)
    • 표준 인터페이스를 사용해 서로 다른 소프트웨어 모듈이 통신하는 초기 방법의 하나
    • XML을 사용해 캡슐화된 표준 메시징 형식을 사용
    • 모든 통신 프로토콜 (ex. HTTP, TCP)을 사용해 메시지를 전송
    • 일반적으로 오래된 프로토콜로 간주됨 (주로 대기업 레거스 응용 프로그램 내에서 사용됨)
  • REST (Representational State Transfer)
    • 통신 프로토콜로써 상태 코드를 사용해 호출의 성공 or 실패 정보를 표현하는 HTTP에 의존
    • 데이터 유형을 훨씬 느슨하게 정의
    • 보통 JSON을 사용
    • 여러 웹 기반 서비스에서 채택하여 사용하는 형식
    • 단일 정보를 검색하려면 다른 리소스를 여러 번 호출해야한다는 단점이 있음
  • GraphQL
    • 그래프 쿼리 언어
    • SQL 쿼리 작성과 유사한 API와 상호 작용하는 방법을 정의하는 방식
    • 단일 정보를 검색하는데 유용함 (w. SQL 쿼리)

Python - requests

headers 객체

  • 서버명, 응답 타임스탬프, 상태 등 자세한 정보를 담고 있는 사전형 객체

상태 코드 (Status Code)

검색 API 사용

response = requests.get(
    'https://api.github.com/search/repositories',  
    params={'q': 'data_science+language:python'}, # 매개변수
    headers={'Accept': 'application/vnd.github.v3.text-match+json'}
) # header

print(response.status_code) # 200

 

  • 페이지 매기기
    • 응답 개수를 제한하기 위해 사용하는 기술로 많은 API가 사용
    • 응답 객체의 links 필드에 다음(next) 페이지와 마지막(last) 페이지 URL 정보를 제공함
def get_all_pages(url, params=None, headers=None):
    output_json = []
    response = requests.get(url, params=params, headers=headers)
    if response.status_code == 200:
      output_json = response.json()
      if 'next' in response.links:
          next_url = response.links['next']['url']
          if next_url is not None:
              output_json += get_all_pages(next_url, params, headers)
    return output_json

out = get_all_pages(
    "https://api.github.com/repos/pytorch/pytorch/issues/comments",
    params={
      'since': '2020-07-01T10:00:01Z',
      'sorted': 'created',
      'direction': 'desc'
    },
    headers={'Accept': 'application/vnd.github.v3+json'}
)

df = pd.DataFrame(out)

 

  • 속도 제한 (rate limit)
    • API가 모든 사용자에게 서비스를 제공하면서 인프라에 대한 부하를 방지하기 위함
    • Ex. Github (Maximum 60/1hour)
      • IP 주소를 기반으로 요청 수를 판단
        • X-Ratelimit-Limit: 1시간 당 요청 수
        • X-Ratelimit-Remaining: 현재 속도 제한을 넘기지 않고 보낼 수 있는 요청 수
        • X-RateLimit-Reset: 요청 수가 재설정되는 시간
        • 속도 제한을 초과하는 요청을 수행하는 경우, API는 403 응답
response = requests.head('https://api.github.com/repos/pytorch/pytorch/issues/comments')
print('X-Ratelimit-Limit', response.headers['X-Ratelimit-Limit']) # 60 (1시간 당 요청 수)
print('X-Ratelimit-Remaining', response.headers['X-Ratelimit-Remaining']) # 12 (현재 속도 제한을 넘기지 않고 보낼 수 있는 요청 수)

# Converting UTC time to human-readable format

import datetime  
print(  
'Rate Limits reset at',  
datetime.datetime.fromtimestamp(int(response.headers\['X-RateLimit-Reset'\])).strftime('%c')  
) # Rate Limits reset at Tue Jan 24 17:28:19 2023

 

  • 속도 제한 준수 code
from datetime import datetime  
import time

def handle\_rate\_limits(response):  
now = datetime.now()  
reset\_time = datetime.fromtimestamp(  
int(response.headers\['X-RateLimit-Reset'\]))  
remaining\_requests = response.headers\['X-Ratelimit-Remaining'\]  
remaining\_time = (reset\_time - now).total\_seconds()  
intervals = remaining\_time / (1.0 + int(remaining\_requests))  
print('Sleeping for', intervals)  
time.sleep(intervals)  
return True

 

  •  재시도
    • requests 라이브러리는 재시도를 구현하지 않음
    • Retry를 활용해서 별도로 구현해야됨
      • 지정된 실패 조건의 경우 API 호출을 다시 시도할 수 있음
      • backoff_factor: 각 시도 사이의 시간 지연을 점차적으로 증가시키는 용도
        • time_delay = {backoff_factor} * (2 ** ({총 재시도 횟수} - 1))
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.retry import Retry

retry_strategy = Retry(
    total=5, # 총 재시도 횟수
    status_forcelist=[500, 503, 504], # 지정된 에러만 다시 시도
    backoff_factor=1 # 각 시도 사이의 시간 지연을 증가시킴
)

retry_adapter = HTTPAdapter(max_retries=retry_strategy)

http = requests.Session()
http.mount("https://", retry_adapter)
http.mount("http://", retry_adapter)

response = http.get('https://api.github.com/search/repositories',
                   params={'q': 'data_science+language:python'})

Twitter Example

  • 지난 7일 동안 게시된 최근 트윗의 샘플만 검색 가능
  • 페이지 매기기 → Cursor 객체로 가능
    • lang: 언어 설정
    • tweet_mode=’extended’: 모든 트윗의 전체 텍스트를 검색
    • count: 한 번의 호출로 최대 검색 트윗 수 (속도 제한 용)
    • items: 총 추출할 트윗 수
  search_term = 'cryptocurrency OR crypto -filter:retweets'
  
  tweets = tweepy.Cursor(api.search,
                         q=search_term, # 검색할 단어
                         lang="en", # 언어 설정
                         tweet_mode='extended', # 모든 트윗의 전체 텍스트를 검색
                         count=30).items(12000) # count : 한 번의 호출로 최대 검색 트윗 수 제한, # items: 12,000개 트윗으로 제한

 

  • 속도 제한 초과 여부 확인
    • wait_on_rate_limit: 자동 대기 기능 활성화
    • wait_on_rate_limit_notify: 대기 시간 알림
  api = tweepy.API(auth,
                   wait_on_rate_limit=True,
                   wait_on_rate_limit_notify=True,
                   retry_count=5,
                   retry_delay=10)
  • 트윗에서 암호화폐와 함께 사용되는 해시태그 -> 메르세데스(Left) vs 페라리 트윗(Right)
    • 메르세데스: 참가한 레이스에 초점
    • 페라리: 상품과 드라이버를 홍보

 
반응형

댓글