빠른 답변
Python에서 SERP API를 어떻게 호출하나요?
https://serpcrypto.com/api/v1/search에 requests 또는 httpx로 GET 요청을 보내고, Authorization: Bearer 헤더에 키를, params에 검색 쿼리를 넣은 뒤 response.json()을 읽으세요. SerpCrypto은 성공한 검색 1건당 크레딧 1개를 청구하며, US$0.30/1K 검색부터 시작하고, 실패한 호출의 재시도는 무료입니다. 암호화폐로 결제하고 KYC가 없습니다. 아래 코드는 requests 또는 httpx만 있으면 됩니다.
Python 설정 한눈에 보기
| 설치 | pip install requests 또는 pip install httpx |
|---|---|
| 키 | 환경 변수 SERPCRYPTO_API_KEY |
| 헤더 | Authorization: Bearer <key> |
| 타임아웃 | 60~90초: 검색이 실시간으로 실행됩니다 |
| 재시도 | 429, 502, 504만 백오프로 재시도하며, 오류는 무료입니다 |
| 병렬 검색 | GET /credits부터 최대 concurrency_limit |
재사용 가능한 Python 클라이언트는 어떻게 설정하나요?
헤더에 키를 넣고 세 가지 일시적 오류에 대한 재시도 정책을 가진 requests.Session을 하나 만드세요. 세션은 연결을 재사용하므로, 검색 루프에서 TLS 핸드셰이크에 드는 시간이 줄어듭니다. 파일을 serp_client.py로 저장하세요. 다음 예제들이 이를 불러옵니다.
urllib3의 Retry는 새 시도 전마다 더 오래 기다리며, Retry-After 헤더가 오면 이를 따릅니다. 400, 401, 402은 재시도하지 않으며, 이들은 두 번째 시도가 아니라 수정이 필요합니다.
"""serp_client.py: a small, reusable client for the SerpCrypto SERP API (requests)."""
import os
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
API_URL = "https://serpcrypto.com/api/v1/search"
CREDITS_URL = "https://serpcrypto.com/api/v1/credits"
def make_session():
session = requests.Session()
session.headers["Authorization"] = "Bearer " + os.environ["SERPCRYPTO_API_KEY"]
retry = Retry(
total=4,
backoff_factor=1.0, # waits about 1 s, 2 s, 4 s between attempts
status_forcelist=(429, 502, 504),
allowed_methods=("GET",),
respect_retry_after_header=True,
)
session.mount("https://", HTTPAdapter(max_retries=retry))
return session
SESSION = make_session()
def search(q, **params):
"""Run one search (1 credit if it succeeds) and return the parsed JSON."""
r = SESSION.get(API_URL, params={"q": q, **params}, timeout=90)
r.raise_for_status()
return r.json()
def credits():
"""Free: credits left, used today and the concurrency limit."""
r = SESSION.get(CREDITS_URL, timeout=30)
r.raise_for_status()
return r.json()
if __name__ == "__main__":
data = search("project management software", gl="us", hl="en")
for item in data.get("organic_results", []):
print(item["position"], item["link"])
print(credits())10개 넘는 결과를 어떻게 수집하나요?
다음 페이지를 하나씩 요청하세요. 페이지당 약 10개의 유기적 결과로, Google이 2025년 9월 num=100을 더 이상 지원하지 않게 된 이후 제공되는 방식입니다. 추가 페이지마다 크레딧이 1개 더 차감됩니다. pagination.next_page이 없으면 바로 멈추세요. 더 가져올 것이 없고, 크레딧도 지킬 수 있습니다.
대부분의 순위 추적 작업에는 첫 페이지나 처음 세 페이지면 충분합니다. 클릭이 그쪽에 집중되기 때문입니다. 키워드 하나에 30개 결과는 크레딧 3개가 듭니다.
from serp_client import search
def top_results(q, pages=3, **params):
"""Collect organic results over several pages: each page is 1 credit."""
rows = []
for page in range(1, pages + 1):
data = search(q, page=page, **params)
for item in data.get("organic_results", []):
rows.append({"page": page, "position": item["position"], "title": item["title"], "link": item["link"]})
if not data.get("pagination", {}).get("next_page"):
break # no further page: stop early and save credits
return rows
rows = top_results("crm for small business", pages=3, gl="gb", hl="en")
print(len(rows), "results")많은 검색을 병렬로 어떻게 실행하나요?
계정 한도에 맞춘 asyncio.Semaphore과 함께 httpx.AsyncClient을 사용하세요. 스크립트는 무료 크레딧 엔드포인트에서 concurrency_limit을 읽으므로, 지원팀이 한도를 올리면 자동으로 적응합니다. 한도를 넘는 검색은 어차피 429을 받으므로, 세마포어가 그 시도를 낭비하지 않게 합니다.
각 작업은 일시적 오류를 점점 늘어나는 대기로 재시도하며, 네 번 실패하면 None를 반환하므로, 고집스러운 쿼리 하나가 배치 전체를 막지 않습니다.
"""Run many searches in parallel without exceeding the account's concurrency limit."""
import asyncio
import os
import httpx
API_URL = "https://serpcrypto.com/api/v1/search"
CREDITS_URL = "https://serpcrypto.com/api/v1/credits"
HEADERS = {"Authorization": "Bearer " + os.environ["SERPCRYPTO_API_KEY"]}
async def search_one(client, gate, q):
async with gate: # at most N searches at the same time
for attempt in range(4):
r = await client.get(API_URL, params={"q": q, "gl": "us", "hl": "en"})
if r.status_code in (429, 502, 504):
await asyncio.sleep(2 ** attempt)
continue
r.raise_for_status()
return q, r.json()
return q, None
async def main(queries):
async with httpx.AsyncClient(headers=HEADERS, timeout=90) as client:
limits = (await client.get(CREDITS_URL)).json()
gate = asyncio.Semaphore(limits["concurrency_limit"])
results = await asyncio.gather(*(search_one(client, gate, q) for q in queries))
for q, data in results:
first = (data or {}).get("organic_results", [{}])[0].get("link")
print(f"{q!r}: {first}")
asyncio.run(main(["best vpn router", "home espresso machine", "4k monitor for coding"]))일별 순위를 CSV 파일로 어떻게 저장하나요?
결과마다 한 행을 추가하세요. 날짜, 키워드, 순위, 링크, 그리고 API가 적용한 설정을 담습니다. gl과 device을 직접 만든 변수가 아니라 search_parameters에서 읽으면, 파일에 실제로 사용된 값이 기록됩니다.
cron이나 Windows 작업 스케줄러로 하루에 한 번 스크립트를 실행하세요. 모바일에서 키워드 세 개는 하루 크레딧 3개, 한 달에 약 90개입니다.
import csv
from datetime import date
from serp_client import search
KEYWORDS = ["standing desk", "ergonomic chair", "monitor arm"]
FIELDS = ["day", "keyword", "position", "title", "link", "gl", "device"]
with open("rankings.csv", "a", newline="", encoding="utf-8") as fh:
writer = csv.DictWriter(fh, fieldnames=FIELDS)
if fh.tell() == 0:
writer.writeheader()
for kw in KEYWORDS:
data = search(kw, gl="gb", hl="en", device="mobile")
applied = data["search_parameters"]
for item in data.get("organic_results", []):
writer.writerow({
"day": date.today().isoformat(),
"keyword": kw,
"position": item["position"],
"title": item["title"],
"link": item["link"],
"gl": applied["gl"],
"device": applied["device"],
})어떤 Python HTTP 클라이언트를 써야 하나요?
스크립트와 cron 작업에는 requests을 사용하세요. 간단하고 재시도 어댑터가 성숙해 있습니다. 웹 앱, 에이전트, 수백 개의 키워드 배치처럼 비동기 코드가 필요할 때는 httpx을 사용하세요. 둘 다 같은 요청을 보내고 같은 JSON을 받습니다. API는 어느 쪽을 선택하든 상관하지 않습니다.
어느 라이브러리든 타임아웃을 너무 짧게 잡지 마세요. 5초 후에 포기하는 클라이언트는 아직 실행 중이던 검색을 다시 보내 두 번 결제할 수 있습니다.
내 스크립트는 비용이 얼마나 들까요?
결과 수가 아니라 검색 횟수를 세세요. 호출 한 번이 성공하면 크레딧 1입니다. 키워드 500개, 각 1페이지, 매일 30일이면 15,000회 검색입니다. 검색 25,000회 팩(US$18.75)에서도 여유가 남고, 선불 검색 크레딧은 만료되지 않습니다: 사용하지 않은 검색은 사용할 때까지 계정에 남아 있습니다.
잔액은 위의 credits() 헬퍼로 코드에서 확인하세요. 비용은 들지 않습니다.
Python 관련 질문
PyPI에 SerpCrypto 패키지가 있나요?
없습니다. 예제는 널리 쓰이는 두 라이브러리인 requests 또는 httpx로 HTTPS endpoint를 호출하므로, 설치하거나 업데이트할 저희 패키지는 없습니다. 위의 클라이언트는 40줄 정도이고 직접 소유하게 됩니다.
이 코드는 어떤 Python 버전을 지원하나요?
Python 3.9 이상입니다. 비동기 예제는 Python 3.7부터 제공되는 asyncio.run을 사용하고, 나머지는 표준 라이브러리와 requests 또는 httpx만 사용합니다.
Jupyter notebook에서 API를 사용할 수 있나요?
네. Jupyter를 시작하기 전에 SERPCRYPTO_API_KEY을 설정하거나, notebook 안에서 getpass로 키를 읽어 저장된 셀에 남지 않게 하세요. notebook에서는 asyncio.run(main(...)) 대신 await main(...)을 사용하세요.
결과를 pandas DataFrame으로 바꾸려면 어떻게 하나요?
결과 딕셔너리 목록을 pandas.DataFrame(data["organic_results"])에 넘기세요. 각 field가 column이 되고, date 같은 누락된 optional field는 빈 셀이 됩니다.