8.6 KiB
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 기반입니다:
- Meta for Developers에서 앱 생성
- Instagram Graph API 제품 추가
- 사용자 인증 후 Access Token 발급
- 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 반환 │
│ │
└─────────────────────────────────────────────────────────────┘
캐러셀의 경우:
- 각 이미지마다 개별 Container 생성 (병렬 처리)
- 캐러셀 Container 생성 (children ID 목록 전달)
- 캐러셀 Container 상태 대기
- 게시
3. HTTP 클라이언트 재사용
InstagramClient는 async 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 발급 방법
- Meta for Developers에서 앱 생성
- Instagram Graph API 제품 추가
- 권한 설정:
instagram_basic- 기본 프로필 정보instagram_content_publish- 콘텐츠 게시
- 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 # 사용 매뉴얼 (본 문서)