chromedp와 함께 Go SDK 사용하기

작성: solvethree읽는 데 3분

먼저 해결한 다음 동일한 프록시와 반환된 브라우저 식별 정보로 Chrome을 실행하세요. 애플리케이션 양식에 토큰을 삽입하고 제출한 뒤 애플리케이션의 결과를 기다리세요. 준비 완료 상태의 작업은 해결 결과가 있다는 뜻이지, 웹사이트가 이를 수락했다는 뜻은 아닙니다.

이 페이지의 내용

모듈, 프로필, 프록시 설정하기

go get으로 solvethree.com/[email protected]과 github.com/chromedp/[email protected]을 설치하세요. SDK는 Go 1.22+가 필요하지만 이 chromedp 버전은 Go 1.25+가 필요하므로, 두 가지를 함께 사용하는 예제에서는 이 버전을 사용하세요. 이 버전의 타입 기반 API는 이전 chromedp 예제와 다릅니다.

프로그램을 실행하기 전에 워크스페이스에서 대상 호스트 이름에 대한 활성 사이트 프로필을 생성하세요. 호스트 이름과 액션을 전송하는 것만으로는 프로필이 생성되지 않습니다.

  • TARGET_URL: 양식이 포함된 페이지의 전체 HTTPS URL입니다. 작업은 이 URL의 호스트 이름을 Site로 사용하고, Chrome은 전체 URL로 이동합니다.
  • SOLVETHREE_PROXY: 단일 HTTP 또는 HTTPS 프록시 URL입니다. 이 예제에는 URL에 인증 정보가 없고 IP 허용 목록을 사용하는 프록시가 필요합니다.
  • SOLVETHREE_API_KEY: 워크스페이스 API 키입니다. 페이지 JavaScript가 아닌 Go 프로세스에 보관하세요.

이 예제는 login 액션을 요청하고 기본 Enterprise v3 reCAPTCHA 모드를 사용합니다. 액션을 애플리케이션에서 기대하는 값으로 변경하세요.

해결 후 Chrome을 실행하고 제출하기

프로그램은 SDK의 해결 작업이 끝날 때까지 기다린 후 Chrome의 할당자를 생성합니다. 동일한 단일 프록시와 result.Solution.UserAgent로 Chrome을 구성한 다음, 페이지 이동 전에 반환된 SecChUA를 sec-ch-ua 헤더로 설정합니다. 관련 없는 브라우저 식별 정보로 대체하거나 해결과 제출 사이에 프록시를 변경하지 마세요.

chromedp · IP 허용 목록 기반 프록시를 통해 제출
// go get github.com/chromedp/[email protected] (requires Go 1.25+)
package main

import (
    "context"
    "encoding/json"
    "fmt"
    "log"
    "net/url"
    "os"
    "time"
    "github.com/chromedp/cdproto/network"
    "github.com/chromedp/chromedp"
    solvethree "solvethree.com/sdk"
)

func main() { if err := run(); err != nil { log.Fatal(err) } }

func run() error {
    target,err:=url.Parse(os.Getenv("TARGET_URL"));if err!=nil||target.Scheme!="https"||target.Hostname()=="" { return fmt.Errorf("set an HTTPS TARGET_URL") }
    proxy,err:=url.Parse(os.Getenv("SOLVETHREE_PROXY"));if err!=nil||proxy.User!=nil { return fmt.Errorf("use an IP-allowlisted proxy without URL credentials") }
    client,err:=solvethree.NewClient(os.Getenv("SOLVETHREE_API_KEY"),nil);if err!=nil { return err }
    ctx,cancel:=context.WithTimeout(context.Background(),180*time.Second);defer cancel()
    result,err:=client.Solve(ctx,solvethree.TaskRequest{Site:target.Hostname(),Action:"login",Proxy:proxy.String()},solvethree.SolveOptions{})
    if err!=nil { return err }
    options:=append(chromedp.DefaultExecAllocatorOptions[:],chromedp.ProxyServer(proxy.String()),chromedp.UserAgent(result.Solution.UserAgent))
    allocator,closeAllocator:=chromedp.NewExecAllocator(context.Background(),options...);defer closeAllocator()
    browser,closeBrowser:=chromedp.NewContext(allocator);defer closeBrowser()
    browser,stop:=context.WithTimeout(browser,60*time.Second);defer stop()
    tokenJSON,err:=json.Marshal(result.Solution.Token);if err!=nil { return err }
    script:=`(token => {const field=document.querySelector('[name="g-recaptcha-response"]'); field.value=token; field.dispatchEvent(new Event('input',{bubbles:true}));})(`+string(tokenJSON)+`)`
    _,err=chromedp.Call(browser,network.SetExtraHTTPHeaders,network.SetExtraHTTPHeadersParams{Headers:network.Headers{"sec-ch-ua":result.Solution.SecChUA}})
    if err!=nil { return err }
    err=chromedp.Do(browser,
        chromedp.Navigate(target.String()),chromedp.WaitReady(chromedp.CSS(`[name="g-recaptcha-response"]`)),
        chromedp.Evaluate[chromedp.Void](script),chromedp.Click(chromedp.CSS(`button[type="submit"]`)),
        chromedp.WaitVisible(chromedp.ID("success")))
    if err!=nil { return err }
    // #success is this owned demo form's outcome. Adapt its selectors, token
    // parameter and success check to your application, including CSRF/session fields.
    return nil
}

이 예제는 의도적으로 프록시 하나만 사용하므로 어떤 후보가 선택되었는지 확인할 필요가 없습니다. 나중에 ProxyCandidates를 사용한다면 SuccessfulProxy(originalTask, readyResult)로 성공한 프록시를 가져와 Chrome에 사용하세요.

데모 양식의 가정에 맞춘 부분 교체하기

토큰 삽입 시 JavaScript 표현식을 구성하기 전에 json.Marshal을 사용합니다. 이 이스케이프 단계를 유지하세요. 이 단계는 이스케이프되지 않은 텍스트를 실행 가능한 코드에 삽입하는 대신, 토큰을 JavaScript 문자열 값으로 전달합니다.

  • [name="g-recaptcha-response"]를 애플리케이션이 실제로 제출하는 필드로 교체하세요. 예제는 필드 값을 설정하고 input 이벤트를 발생시킵니다. 애플리케이션에 다른 제출 경로가 필요하다면 이에 맞게 조정하세요.
  • button[type="submit"]을 원하는 제출 컨트롤로 교체하세요. 클릭하기 전에 필요한 양식 값, CSRF 필드, 세션 상태를 모두 포함하세요.
  • #success를 애플리케이션에서 실제로 수락되었음을 나타내는 결과로 교체하세요. 클릭 완료나 토큰 필드에 값이 채워진 상태는 그러한 결과가 아닙니다.

SDK는 대상에 토큰을 제출하지 않습니다. 대상이 요청을 거부하면 먼저 전송되는 양식을 확인하세요. 작업 ID나 이전 필드 값이 아닌 result.Solution.Token이 포함되어 있는지 확인하고, 프록시와 브라우저 식별 정보가 여전히 일치하는지도 확인하세요.

중복 해결 요청을 생성하지 않고 기한 처리하기

해결 작업에는 180초의 컨텍스트 기한이 적용됩니다. 해결 후 Chrome에는 별도의 60초 기한이 적용됩니다. run 함수는 오류를 반환하므로 main이 오류를 기록하기 전에 지연된 컨텍스트 취소와 브라우저 정리가 실행됩니다.

해결 컨텍스트를 취소하면 대기만 중단되고 원격 작업은 중단되지 않습니다. SDK는 작업을 한 번만 생성하며 일시적인 폴링 실패만 재시도합니다. 생성 POST 요청은 재시도하지 않습니다. 따라서 시간 초과가 발생했다고 즉시 새 작업을 제출해서는 안 됩니다.

  • 취소 또는 기한 초과 시 errors.Is로 컨텍스트 오류를 식별하세요. errors.As로 *solvethree.Error를 추출하고 해당 TaskID와 RequestID를 보관하세요.
  • 작업 ID가 있으면 GetTask로 조회하세요. 그렇지 않으면 동일한 요청 ID로 원래 작업 입력을 정확히 그대로 다시 전송해 복구하세요. 해당 ID 없이 다시 호출하면 새 논리적 요청이 생성됩니다. 같은 ID를 재사용하면서 입력을 변경하면 충돌이 발생합니다.
  • *TaskFailedError의 경우 ErrorCode를 확인하고 실패한 작업을 조회해 오류 내용을 확인하세요. 해당 작업은 최종 상태입니다. 폴링을 중단하고, 변경하지 않은 입력으로 재시도하는 대신 원인을 해결하세요.
  • HTTP API 오류의 경우 중첩된 *APIError를 추출해 StatusCode와 RetryAfter를 확인하세요. HTTP 실패를 최종 상태인 작업 실패와 혼동하지 마세요.

첫 작업을 실행하세요.

워크스페이스 크레딧 $5로 시작하세요.

워크스페이스 만들기
chromedp와 함께 Go SDK 사용하기 · solvethree