o2o-castad-backend/poc/instagram2-simple/poc.md

8.6 KiB

Instagram Graph API POC

Instagram Graph API를 사용한 콘텐츠 게시 및 조회 클라이언트입니다.

개요

이 POC는 Instagram Graph API의 Content Publishing 기능을 테스트합니다.

지원 기능

기능 설명 메서드
미디어 목록 조회 계정의 게시물 목록 조회 get_media_list()
미디어 상세 조회 특정 게시물 상세 정보 get_media()
이미지 게시 단일 이미지 게시 publish_image()
비디오/릴스 게시 비디오 또는 릴스 게시 publish_video()
캐러셀 게시 2-10개 이미지 게시 publish_carousel()

동작 원리

1. 인증 흐름

[사용자] → [Instagram 앱] → [Access Token 발급]
                                    ↓
[InstagramClient(access_token=...)] ← 토큰 전달

Instagram Graph API는 OAuth 2.0 기반입니다:

  1. Meta for Developers에서 앱 생성
  2. Instagram Graph API 제품 추가
  3. 사용자 인증 후 Access Token 발급
  4. Token을 InstagramClient에 전달

2. 미디어 게시 프로세스

Instagram 미디어 게시는 3단계로 진행됩니다:

┌─────────────────────────────────────────────────────────────┐
│                    미디어 게시 프로세스                        │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  Step 1: Container 생성                                     │
│  POST /{account_id}/media                                   │
│  → Container ID 반환                                        │
│                                                             │
│  Step 2: Container 상태 대기                                 │
│  GET /{container_id}?fields=status_code                     │
│  → IN_PROGRESS → FINISHED (폴링)                            │
│                                                             │
│  Step 3: 게시                                               │
│  POST /{account_id}/media_publish                           │
│  → Media ID 반환                                            │
│                                                             │
└─────────────────────────────────────────────────────────────┘

캐러셀의 경우:

  1. 각 이미지마다 개별 Container 생성 (병렬 처리)
  2. 캐러셀 Container 생성 (children ID 목록 전달)
  3. 캐러셀 Container 상태 대기
  4. 게시

3. HTTP 클라이언트 재사용

InstagramClientasync with 블록 내에서 HTTP 연결을 재사용합니다:

async with InstagramClient(access_token="...") as client:
    # 이 블록 내의 모든 API 호출은 동일한 HTTP 클라이언트 사용
    await client.get_media_list()   # 연결 1
    await client.publish_image(...) # 연결 재사용 (4+ 요청)
    await client.get_media(...)     # 연결 재사용

환경 설정

1. 필수 환경변수

# Instagram Access Token (필수)
export INSTAGRAM_ACCESS_TOKEN="your_access_token"

2. 의존성 설치

uv add httpx pydantic

3. Access Token 발급 방법

  1. Meta for Developers에서 앱 생성
  2. Instagram Graph API 제품 추가
  3. 권한 설정:
    • instagram_basic - 기본 프로필 정보
    • instagram_content_publish - 콘텐츠 게시
  4. Graph API Explorer에서 토큰 발급

사용 예제

기본 사용법

import asyncio
from poc.instagram.client import InstagramClient

async def main():
    async with InstagramClient(access_token="YOUR_TOKEN") as client:
        # 미디어 목록 조회
        media_list = await client.get_media_list(limit=10)
        for media in media_list.data:
            print(f"{media.media_type}: {media.like_count} likes")

asyncio.run(main())

이미지 게시

async with InstagramClient(access_token="YOUR_TOKEN") as client:
    media = await client.publish_image(
        image_url="https://example.com/photo.jpg",
        caption="My photo! #photography"
    )
    print(f"게시 완료: {media.permalink}")

비디오/릴스 게시

async with InstagramClient(access_token="YOUR_TOKEN") as client:
    media = await client.publish_video(
        video_url="https://example.com/video.mp4",
        caption="Check this out! #video",
        share_to_feed=True
    )
    print(f"게시 완료: {media.permalink}")

캐러셀 게시

async with InstagramClient(access_token="YOUR_TOKEN") as client:
    media = await client.publish_carousel(
        media_urls=[
            "https://example.com/img1.jpg",
            "https://example.com/img2.jpg",
            "https://example.com/img3.jpg",
        ],
        caption="My carousel! #photos"
    )
    print(f"게시 완료: {media.permalink}")

에러 처리

import httpx
from poc.instagram.client import InstagramClient

async with InstagramClient(access_token="YOUR_TOKEN") as client:
    try:
        media = await client.publish_image(...)
    except httpx.HTTPStatusError as e:
        print(f"API 오류: {e}")
        print(f"상태 코드: {e.response.status_code}")
    except TimeoutError as e:
        print(f"타임아웃: {e}")
    except RuntimeError as e:
        print(f"컨테이너 처리 실패: {e}")
    except Exception as e:
        print(f"예상치 못한 오류: {e}")

멀티테넌트 사용

여러 사용자가 각자의 토큰으로 독립적인 인스턴스를 사용합니다:

async def post_for_user(user_token: str, image_url: str, caption: str):
    async with InstagramClient(access_token=user_token) as client:
        return await client.publish_image(image_url=image_url, caption=caption)

# 여러 사용자에 대해 병렬 실행
results = await asyncio.gather(
    post_for_user("USER1_TOKEN", "https://...", "User 1 post"),
    post_for_user("USER2_TOKEN", "https://...", "User 2 post"),
    post_for_user("USER3_TOKEN", "https://...", "User 3 post"),
)

API 제한사항

Rate Limits

제한 설명
시간당 요청 200회 사용자 토큰당
일일 게시 25개 계정당 (공식 문서 확인 필요)

Rate limit 초과 시 RateLimitError가 발생하며, retry_after 속성으로 대기 시간을 확인할 수 있습니다.

미디어 요구사항

이미지:

  • 형식: JPEG 권장
  • 최소 크기: 320x320 픽셀
  • 비율: 4:5 ~ 1.91:1

비디오:

  • 형식: MP4 (H.264)
  • 길이: 3초 ~ 60분 (릴스)
  • 해상도: 최소 720p
  • 비율: 9:16 (세로), 16:9 (가로), 1:1 (정사각형)

캐러셀:

  • 이미지 수: 2-10개
  • 각 이미지는 위 이미지 요구사항 충족 필요

미디어 URL 요구사항

게시할 미디어는 공개적으로 접근 가능한 URL이어야 합니다:

  • HTTPS 프로토콜 권장
  • 인증 없이 접근 가능해야 함
  • CDN 또는 S3 등의 공개 URL 사용

예외 처리

표준 Python 및 httpx 예외를 사용합니다:

예외 설명 원인
httpx.HTTPStatusError HTTP 상태 에러 API 에러 응답 (4xx, 5xx)
httpx.HTTPError HTTP 통신 에러 네트워크 오류, 재시도 초과
TimeoutError 타임아웃 컨테이너 처리 시간 초과
RuntimeError 런타임 에러 컨테이너 처리 실패, 컨텍스트 매니저 미사용
ValueError 값 에러 잘못된 파라미터 (토큰 누락, 캐러셀 이미지 수 등)

테스트 실행

# 환경변수 설정
export INSTAGRAM_ACCESS_TOKEN="your_access_token"

# 테스트 실행
python -m poc.instagram.main

파일 구조

poc/instagram/
├── __init__.py  # 패키지 초기화 및 export
├── client.py    # InstagramClient 클래스
├── models.py    # Pydantic 모델 (Media, MediaList 등)
├── main.py      # 테스트 실행 파일
└── poc.md       # 사용 매뉴얼 (본 문서)

참고 문서