KYC 없이 — 신분증, 셀피, 서류 없음. 암호화폐로 결제: BTC, USDT, USDC, ETH, SOL, LTC
언어: 한국어
API 키 발급

문서 · Python 3.9+ · requests · httpx

Python에서 SERP API 사용하기: requests, httpx, asyncio

재시도가 있는 재사용 클라이언트, 결과가 끝나면 멈추는 페이지네이션 루프, 동시성 제한 내로 제한된 async 검색, 순위용 일별 CSV. 복사해 붙여넣는 코드로, 문법 검사를 마쳤고 저희 패키지는 설치할 필요가 없습니다.

마지막 업데이트: · 5 분 소요

빠른 답변

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
"""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를 반환하므로, 고집스러운 쿼리 하나가 배치 전체를 막지 않습니다.

asyncio + httpx: 한도 내 병렬 검색
"""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개입니다.

오늘의 순위를 rankings.csv에 추가
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는 빈 셀이 됩니다.

US$0.30/1K 검색부터 · KYC 없이

API 키 발급