[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"blog-post-ko-colly-rotating-proxy-guide":3},{"success":4,"payload":5,"related":67,"errors":161},true,{"id":6,"slug":7,"title":8,"excerpt":9,"body_html":10,"meta_title":11,"meta_description":12,"canonical_url":13,"canonical_override":14,"og_title":15,"og_description":16,"og_image_url":17,"faq_json":18,"key_takeaways":14,"allow_index":34,"noindex_google_only":34,"allow_follow":4,"published_at":35,"updated_at":35,"content_updated_at":36,"featured_image_url":37,"featured_image_alt":38,"card_image_url":39,"reading_time_minutes":40,"author":41,"categories":45,"tags":52,"alternates":53,"locale_paths":65,"views":66},175,"colly-rotating-proxy-guide","Colly에서 로테이션 프록시 사용하기: Go 웹 스크래핑 완전 가이드","Go의 Colly 프레임워크에서 RoundRobinProxySwitcher와 SetProxyFunc를 활용해 ProxyHat 주거 프록시를 로테이션하는 방법을 코드 예제와 함께 다룹니다. 프로덕션 패턴, 재시도, 분산 스크래핑까지.","\u003Cp>Go로 웹 스크래핑을 하다 보면 단일 IP로는 수백 페이지를 수집하기 전에 차단당합니다. Colly 로테이션 프록시를 설정하면 매 요청마다 IP를 바꿔 429 Too Many Requests와 403 Forbidden을 회피할 수 있습니다. 이 글에서는 Colly의 콜렉터 모델, \u003Ccode>proxy.RoundRobinProxySwitcher\u003C\u002Fcode>와 \u003Ccode>c.SetProxyFunc\u003C\u002Fcode>를 활용한 프록시 교체, ProxyHat 주거 프록시 연동, 그리고 프로덕션 환경에서의 재시도·동시성 제어·분산 큐 패턴까지 단계별로 설명합니다.\u003C\u002Fp>\n\n\u003Ch2>Colly 로테이션 프록시: 기본 개념과 필요성\u003C\u002Fh2>\n\n\u003Cp>Colly는 Go 생태계에서 가장 널리 쓰이는 웹 스크래핑 프레임워크입니다. \u003Ca href=\"https:\u002F\u002Fpkg.go.dev\u002Fgithub.com\u002Fgocolly\u002Fcolly\u002Fv2\" rel=\"noopener noreferrer\">Colly 공식 문서\u003C\u002Fa>에 따르면, Colly는 콜백 기반의 콜렉터(Collector) 모델을 사용하며 \u003Ccode>goquery\u003C\u002Fcode>로 DOM을 순회합니다. 핵심 콜백은 다음과 같습니다:\u003C\u002Fp>\n\n\u003Cul>\n\u003Cli>\u003Ccode>c.OnRequest(func(r *colly.Request))\u003C\u002Fcode> — 요청 전 헤더·쿠키·프록시 설정\u003C\u002Fli>\n\u003Cli>\u003Ccode>c.OnHTML(selector, func(e *colly.HTMLElement))\u003C\u002Fcode> — DOM 노드 추출\u003C\u002Fli>\n\u003Cli>\u003Ccode>c.OnError(func(r *colly.Response, err error))\u003C\u002Fcode> — 에러 처리 및 재시도\u003C\u002Fli>\n\u003Cli>\u003Ccode>c.OnScraped(func(r *colly.Response))\u003C\u002Fcode> — 페이지 완료 후 후처리\u003C\u002Fli>\n\u003C\u002Ful>\n\n\u003Cp>Colly는 기본적으로 동기 모드로 동작하지만, \u003Ccode>c.Async = true\u003C\u002Fcode>로 설정하면 고루틴 기반 비동기 모드로 전환됩니다. 이때 \u003Ccode>c.Parallelism\u003C\u002Fcode>으로 동시 요청 수를 제어할 수 있으며, 프록시 로테이션과 함께 사용하면 대량 수집 시 차단을 크게 줄일 수 있습니다.\u003C\u002Fp>\n\n\u003Ch3>왜 주거 프록시인가?\u003C\u002Fh3>\n\n\u003Cp>데이터센터 IP는 AS(Autonomous System) 정보만 봐도 프록시로 식별되기 쉽습니다. 반면 주거(residential) IP는 실제 ISP가 할당한 가정용 주소이므로, Cloudflare·Akamai·PerimeterX 같은 봇 방지 시스템도 합법 사용자와 구분하기 어렵습니다. SERP 스크래핑, 이커머스 가격 모니터링, 소셜 미디어 데이터 수집 등 \u003Cstrong>하드 타겟\u003C\u002Fstrong>에서는 주거 프록시가 사실상 필수입니다.\u003C\u002Fp>\n\n\u003Cblockquote>\n\u003Cp>\u003Cstrong>주의:\u003C\u002Fstrong> 공개 데이터만 수집하세요. robots.txt와 웹사이트 이용약관을 준수해야 하며, 미국에서는 \u003Ca href=\"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FComputer_Fraud_and_Abuse_Act\" rel=\"noopener noreferrer\">CFAA(Computer Fraud and Abuse Act)\u003C\u002Fa> 위반, EU에서는 GDPR 위반의 법적 리스크가 있습니다. 인증이 필요한 페이지를 무단으로 스크래핑하지 마세요.\u003C\u002Fp>\n\u003C\u002Fblockquote>\n\n\u003Ch2>Colly 프록시 교체 방식: RoundRobinProxySwitcher vs SetProxyFunc\u003C\u002Fh2>\n\n\u003Cp>Colly는 프록시 설정을 위한 두 가지 방법을 제공합니다. 하나는 빌트인 라운드로빈 스위처이고, 다른 하나는 커스텀 함수 기반 방식입니다.\u003C\u002Fp>\n\n\u003Ch3>1. proxy.RoundRobinProxySwitcher (빌트인)\u003C\u002Fh3>\n\n\u003Cp>\u003Ccode>colly\u002Fproxy\u003C\u002Fcode> 패키지의 \u003Ccode>RoundRobinProxySwitcher\u003C\u002Fcode>는 문자열 URL 목록을 받아 매 요청마다 순차적으로 프록시를 교체합니다. 가장 간단한 \u003Cstrong>colly proxy switcher\u003C\u002Fstrong> 패턴입니다:\u003C\u002Fp>\n\n\u003Cpre>\u003Ccode>package main\n\nimport (\n    &quot;fmt&quot;\n    &quot;log&quot;\n    &quot;github.com\u002Fgocolly\u002Fcolly\u002Fv2&quot;\n    &quot;github.com\u002Fgocolly\u002Fcolly\u002Fv2\u002Fproxy&quot;\n)\n\nfunc main() {\n    \u002F\u002F ProxyHat 주거 프록시 — http\u002Fhttps\u002Fsocks5 모두 지원\n    proxies := []string{\n        &quot;http:\u002F\u002Fuser-country-DE-sid-abc1:pass@gate.proxyhat.com:8080&quot;,\n        &quot;http:\u002F\u002Fuser-country-DE-sid-abc2:pass@gate.proxyhat.com:8080&quot;,\n        &quot;http:\u002F\u002Fuser-country-DE-sid-abc3:pass@gate.proxyhat.com:8080&quot;,\n    }\n\n    rp, err := proxy.RoundRobinProxySwitcher(proxies...)\n    if err != nil {\n        log.Fatal(err)\n    }\n\n    c := colly.NewCollector()\n    c.SetProxyFunc(rp)\n\n    c.OnHTML(&quot;title&quot;, func(e *colly.HTMLElement) {\n        fmt.Println(&quot;Title:&quot;, e.Text)\n    })\n\n    c.OnError(func(r *colly.Response, err error) {\n        log.Printf(&quot;Error on %s: %v&quot;, r.Request.URL, err)\n    })\n\n    c.Visit(&quot;https:\u002F\u002Fhttpbin.org\u002Fip&quot;)\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Cp>이 방식은 소규모 프록시 풀(3~10개)에는 적합하지만, 수백 개의 세션을 관리해야 하는 프로덕션 환경에서는 유연성이 부족합니다. 세션 스티키니스, 국가별 라우팅, 실패한 프록시 제외 등의 로직이 필요하면 커스텀 함수를 작성해야 합니다.\u003C\u002Fp>\n\n\u003Ch3>2. 커스텀 SetProxyFunc (유연한 제어)\u003C\u002Fh3>\n\n\u003Cp>\u003Ccode>c.SetProxyFunc(func(*http.Request) (*url.URL, error))\u003C\u002Fcode>를 사용하면 요청 컨텍스트, URL 패턴, 재시도 카운트 등에 따라 프록시를 동적으로 선택할 수 있습니다. 이것이 진정한 \u003Cstrong>golang colly proxy\u003C\u002Fstrong> 패턴입니다:\u003C\u002Fp>\n\n\u003Cpre>\u003Ccode>package main\n\nimport (\n    &quot;math\u002Frand&quot;\n    &quot;net\u002Fhttp&quot;\n    &quot;net\u002Furl&quot;\n    &quot;sync\u002Fatomic&quot;\n    &quot;time&quot;\n    &quot;github.com\u002Fgocolly\u002Fcolly\u002Fv2&quot;\n)\n\nvar counter uint64\n\nfunc proxyHatSwitcher(req *http.Request) (*url.URL, error) {\n    countries := []string{&quot;US&quot;, &quot;DE&quot;, &quot;GB&quot;, &quot;FR&quot;, &quot;JP&quot;}\n    n := atomic.AddUint64(&amp;counter, 1)\n    country := countries[n % uint64(len(countries))]\n    sessionID := fmt.Sprintf(&quot;sess-%d&quot;, n)\n\n    proxyURL := fmt.Sprintf(\n        &quot;http:\u002F\u002Fuser-country-%s-sid-%s:YOUR_PASSWORD@gate.proxyhat.com:8080&quot;,\n        country, sessionID,\n    )\n    return url.Parse(proxyURL)\n}\n\nfunc main() {\n    c := colly.NewCollector(\n        colly.Async(true),\n    )\n    c.SetProxyFunc(proxyHatSwitcher)\n    c.Limit(&amp;colly.LimitRule{\n        DomainGlob:  &quot;*&quot;,\n        Parallelism: 20,\n        Delay:       2 * time.Second,\n        RandomDelay: 1 * time.Second,\n    })\n\n    c.OnHTML(&quot;title&quot;, func(e *colly.HTMLElement) {\n        fmt.Printf(&quot;[%s] %s\\n&quot;, e.Request.AbsoluteURL(e.Request.URL.String()), e.Text)\n    })\n\n    urls := []string{\n        &quot;https:\u002F\u002Fhttpbin.org\u002Fip&quot;,\n        &quot;https:\u002F\u002Fhttpbin.org\u002Fheaders&quot;,\n        &quot;https:\u002F\u002Fhttpbin.org\u002Fuser-agent&quot;,\n    }\n    for _, u := range urls {\n        c.Visit(u)\n    }\n    c.Wait()\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Cp>위 예제에서는 \u003Ccode>atomic\u003C\u002Fcode> 카운터로 매 요청마다 새 세션 ID를 생성합니다. ProxyHat의 사용자명 포맷에서 \u003Ccode>-sid-abc123\u003C\u002Fcode> 접미사를 바꾸면 매 요청마다 다른 IP가 할당됩니다. \u003Ccode>-country-DE\u003C\u002Fcode>로 국가를 지정하고 \u003Ccode>-region-state_of_berlin-city-berlin\u003C\u002Fcode>으로 도시까지 타겟팅할 수 있습니다.\u003C\u002Fp>\n\n\u003Ch2>ProxyHat 주거 프록시와 Colly 통합하기\u003C\u002Fh2>\n\n\u003Cp>ProxyHat은 게이트웨이 호스트 \u003Ccode>gate.proxyhat.com\u003C\u002Fcode>을 통해 HTTP(포트 8080)와 SOCKS5(포트 1080)를 모두 지원합니다. 사용자명에 지오타겟팅과 세션 플래그를 포함하는 방식이 핵심입니다:\u003C\u002Fp>\n\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>사용자명 포맷\u003C\u002Fth>\n\u003Cth>효과\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>user-country-US:pass\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>미국 IP로 라우팅, 매 요청마다 새 IP\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>user-country-DE-region-state_of_berlin-city-berlin:pass\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>베를린 도시 단위 타겟팅\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>user-country-DE-sid-abc123:pass\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>동일 세션 ID = 동일 IP 유지 (스티키 세션)\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>user-sid-xyz789:pass\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>국가 무관, 세션만 고정\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\n\u003Ch3>SOCKS5 사용 예제\u003C\u002Fh3>\n\n\u003Cp>일부 타겟 사이트는 HTTP CONNECT 프록시를 감지하지만 SOCKS5는 통과시키는 경우가 있습니다. SOCKS5를 사용하려면 포트를 1080으로 변경하세요:\u003C\u002Fp>\n\n\u003Cpre>\u003Ccode>func socks5Switcher(req *http.Request) (*url.URL, error) {\n    n := atomic.AddUint64(&amp;counter, 1)\n    proxyURL := fmt.Sprintf(\n        &quot;socks5:\u002F\u002Fuser-country-JP-sid-s%d:YOUR_PASSWORD@gate.proxyhat.com:1080&quot;,\n        n,\n    )\n    return url.Parse(proxyURL)\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Cp>ProxyHat의 전체 연결 옵션은 \u003Ca href=\"https:\u002F\u002Fdocs.proxyhat.com\u002F\" rel=\"noopener noreferrer\">공식 문서\u003C\u002Fa>를 참조하세요. 가격 정보는 \u003Ca href=\"\u002Fko\u002Fpricing\">ProxyHat 가격 페이지\u003C\u002Fa>에서 확인할 수 있으며, 지원 국가 목록은 \u003Ca href=\"\u002Fko\u002Flocations\">위치 페이지\u003C\u002Fa>에 있습니다.\u003C\u002Fp>\n\n\u003Ch2>프로덕션 패턴: 재시도, 동시성, 분산 큐\u003C\u002Fh2>\n\n\u003Ch3>재시도 with c.Clone()\u003C\u002Fh3>\n\n\u003Cp>Colly에서 재시도를 구현하는 관용적 방법은 \u003Ccode>OnError\u003C\u002Fcode> 콜백에서 \u003Ccode>c.Clone()\u003C\u002Fcode>으로 새 콜렉터를 만들어 재방문하는 것입니다. 이때 프록시 함수도 복제되므로, 새 IP로 재시도됩니다:\u003C\u002Fp>\n\n\u003Cpre>\u003Ccode>func setupCollector() *colly.Collector {\n    c := colly.NewCollector(\n        colly.Async(true),\n        colly.MaxDepth(2),\n    )\n    c.SetProxyFunc(proxyHatSwitcher)\n\n    c.OnError(func(r *colly.Response, err error) {\n        if r.StatusCode == 429 || r.StatusCode == 503 {\n            fmt.Printf(&quot;Retrying %s (status %d)\\n&quot;, r.Request.URL, r.StatusCode)\n            \u002F\u002F 짧은 대기 후 재시도\n            time.Sleep(5 * time.Second)\n            clone := r.Request.C.Clone()\n            clone.SetProxyFunc(proxyHatSwitcher)\n            clone.OnHTML(&quot;title&quot;, func(e *colly.HTMLElement) {\n                fmt.Println(&quot;Retry title:&quot;, e.Text)\n            })\n            clone.Visit(r.Request.URL.String())\n        }\n    })\n\n    return c\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Ch3>RandomDelay와 Parallelism 제어\u003C\u002Fh3>\n\n\u003Cp>대량 스크래핑에서 가장 흔한 실수는 \u003Ccode>Limit()\u003C\u002Fcode> 규칙 없이 비동기 모드를 사용하는 것입니다. \u003Ccode>Parallelism\u003C\u002Fcode>을 20~50으로 설정하고 \u003Ccode>RandomDelay\u003C\u002Fcode>를 1~3초로 주면, 타겟 서버에 부담을 주지 않으면서도 시간당 수천 페이지를 수집할 수 있습니다. ProxyHat 주거 프록시를 사용하면 동시 세션 100개까지도 안정적으로 유지할 수 있습니다.\u003C\u002Fp>\n\n\u003Ch3>분산 스크래핑: Redis 큐 백엔드\u003C\u002Fh3>\n\n\u003Cp>여러 머신에서 동시에 스크래핑하려면 Colly의 큐(Queue) 시스템에 Redis 백엔드를 사용하세요. \u003Ca href=\"https:\u002F\u002Fpkg.go.dev\u002Fgithub.com\u002Fgocolly\u002Fcolly\u002Fv2\" rel=\"noopener noreferrer\">Colly v2\u003C\u002Fa>는 \u003Ccode>storage.RedisStorage\u003C\u002Fcode>를 제공합니다:\u003C\u002Fp>\n\n\u003Cpre>\u003Ccode>import (\n    &quot;github.com\u002Fgocolly\u002Fcolly\u002Fv2\u002Fstorage&quot;\n    &quot;github.com\u002Fgocolly\u002Fredisstorage&quot;\n)\n\nfunc setupDistributedQueue() *colly.Collector {\n    c := colly.NewCollector()\n    c.SetProxyFunc(proxyHatSwitcher)\n\n    \u002F\u002F Redis 백엔드로 방문한 URL 추적\n    redisStorage := &amp;redisstorage.Storage{\n        Address:  &quot;redis:6379&quot;,\n        Password: &quot;&quot;,\n        DB:       0,\n        Prefix:   &quot;proxyhat_scraper&quot;,\n    }\n    c.SetStorage(redisStorage)\n\n    q, _ := colly.NewQueue(\n        20, \u002F\u002F threads\n        colly.NewCookieJarStorage(redisStorage),\n    )\n\n    \u002F\u002F URL 추가\n    q.AddURL(&quot;https:\u002F\u002Fexample.com\u002Fpage1&quot;)\n    q.AddURL(&quot;https:\u002F\u002Fexample.com\u002Fpage2&quot;)\n    q.Run(c)\n\n    return c\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Cp>이 패턴을 사용하면 여러 컨테이너가 동일한 Redis 큐에서 URL을 가져와 처리합니다. 각 컨테이너는 독립적으로 ProxyHat 프록시를 로테이션하므로 IP 풀이 고갈되지 않습니다.\u003C\u002Fp>\n\n\u003Ch3>커스텀 Transport TLS 설정\u003C\u002Fh3>\n\n\u003Cp>일부 사이트는 TLS 지문(fingerprint)으로 봇을 탐지합니다. Colly의 \u003Ccode>http.Transport\u003C\u002Fcode>를 커스터마이징하면 User-Agent와 TLS 설정을 미세 조정할 수 있습니다:\u003C\u002Fp>\n\n\u003Cpre>\u003Ccode>import (\n    &quot;crypto\u002Ftls&quot;\n    &quot;net\u002Fhttp&quot;\n    &quot;github.com\u002Fgocolly\u002Fcolly\u002Fv2&quot;\n)\n\nfunc setupTLS() *colly.Collector {\n    c := colly.NewCollector()\n    c.SetProxyFunc(proxyHatSwitcher)\n\n    c.WithTransport(&amp;http.Transport{\n        TLSClientConfig: &amp;tls.Config{\n            InsecureSkipVerify: false,\n            MinVersion:         tls.VersionTLS12,\n        },\n        MaxIdleConns:        100,\n        IdleConnTimeout:     90 * time.Second,\n        TLSHandshakeTimeout: 10 * time.Second,\n    })\n\n    return c\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Ch2>Colly를 사용하면 안 되는 경우\u003C\u002Fh2>\n\n\u003Cp>Colly는 HTTP 요청과 HTML 파싱에 최적화되어 있습니다. React·Vue·Angular로 구축된 SPA(Single Page Application)는 JavaScript 실행이 필요하므로 Colly만으로는 렌더링된 콘텐츠를 얻을 수 없습니다. 이런 경우 \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fchromedp\u002Fchromedp\" rel=\"noopener noreferrer\">chromedp\u003C\u002Fa>나 Playwright for Go를 사용해 헤드리스 브라우저를 구동하고, 그 앞에 ProxyHat 프록시를 설정해야 합니다.\u003C\u002Fp>\n\n\u003Cp>또한 Colly는 파일 다운로드, 바이너리 처리, WebSocket 통신에는 적합하지 않습니다. 이런 작업이 필요하면 표준 \u003Ccode>net\u002Fhttp\u003C\u002Fcode> 클라이언트에 프록시를 직접 설정하는 것이 더 적합합니다.\u003C\u002Fp>\n\n\u003Ch2>윤리와 법적 고려사항\u003C\u002Fh2>\n\n\u003Cp>웹 스크래핑은 강력한 도구이지만 책임감 있게 사용해야 합니다. \u003Ca href=\"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FComputer_Fraud_and_Abuse_Act\" rel=\"noopener noreferrer\">CFAA\u003C\u002Fa>는 미국에서 인증 없이 접근해서는 안 되는 시스템에 대한 접근을 금지하며, EU의 GDPR은 개인 데이터 수집에 엄격한 제한을 둡니다. 다음 원칙을 지키세요:\u003C\u002Fp>\n\n\u003Cul>\n\u003Cli>\u003Cstrong>robots.txt 준수:\u003C\u002Fstrong> Colly는 \u003Ccode>c.IgnoreRobotsTxt = false\u003C\u002Fcode>가 기본값이지만, 명시적으로 확인하세요.\u003C\u002Fli>\n\u003Cli>Rate limit 존중: \u003Ccode>Limit()\u003C\u002Fcode> 규칙으로 초당 요청 수를 제한하세요.\u003C\u002Fli>\n\u003Cli>공개 데이터만 수집: 로그인이 필요한 페이지는 이용약관 위반일 수 있습니다.\u003C\u002Fli>\n\u003Cli>개인정보 최소화: 이메일·전화번호 등 PII를 수집하지 않거나 즉시 익명화하세요.\u003C\u002Fli>\n\u003C\u002Ful>\n\n\u003Cp>SERP 추적과 웹 스크래핑 유스케이스에 대한 자세한 가이드는 \u003Ca href=\"\u002Fko\u002Fuse-cases\u002Fserp-tracking\">SERP 추적 페이지\u003C\u002Fa>와 \u003Ca href=\"\u002Fko\u002Fuse-cases\u002Fweb-scraping\">웹 스크래핑 페이지\u003C\u002Fa>를 참조하세요.\u003C\u002Fp>\n\n\u003Ch2>핵심 요약: Key Takeaways\u003C\u002Fh2>\n\n\u003Cul>\n\u003Cli>RoundRobinProxySwitcher는 소규모 프록시 풀에 적합하고, SetProxyFunc 커스텀 함수는 동적 지오타겟팅·세션 관리에 적합합니다.\u003C\u002Fli>\n\u003Cli>ProxyHat 사용자명에 \u003Ccode>-country-DE-region-state_of_berlin-city-berlin-sid-abc123\u003C\u002Fcode> 형식으로 플래그를 추가하면 매 요청마다 IP·지역·세션을 제어할 수 있습니다.\u003C\u002Fli>\n\u003Cli>\u003Ccode>Limit()\u003C\u002Fcode>으로 Parallelism과 RandomDelay를 설정하지 않으면 타겟 서버가 봇으로 간주합니다. 동시성 20~50, 지연 1~3초가 권장값입니다.\u003C\u002Fli>\n\u003Cli>재시도는 \u003Ccode>c.Clone()\u003C\u002Fcode>으로 새 콜렉터를 만들어 새 IP로 재방문하는 것이 Colly의 관용적 패턴입니다.\u003C\u002Fli>\n\u003Cli>분산 환경에서는 Redis 큐 백엔드를 사용해 여러 컨테이너가 동일한 작업 큐를 공유하세요.\u003C\u002Fli>\n\u003Cli>JS 렌더링이 필요한 SPA는 Colly 대신 chromedp나 Playwright를 사용하고, 그 앞에 ProxyHat 프록시를 설정하세요.\u003C\u002Fli>\n\u003C\u002Ful>","Colly 로테이션 프록시 완전 가이드: Go 웹 스크래핑 | ProxyHat","Colly에서 로테이션 프록시를 설정하는 방법을 RoundRobinProxySwitcher와 SetProxyFunc 예제로 설명합니다. ProxyHat 주거 프록시 연동, 재시도, 분산 큐 패턴까지.","\u002Fko\u002Fblog\u002Fcolly-rotating-proxy-guide",null,"Colly 로테이션 프록시 완전 가이드 | ProxyHat","Go Colly에서 프록시 로테이션을 구현하는 방법: RoundRobinProxySwitcher, SetProxyFunc, ProxyHat 주거 프록시 연동, 프로덕션 패턴.","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fko\u002Fcolly-rotating-proxy-guide-og.webp",[19,22,25,28,31],{"question":20,"answer":21},"Colly에서 로테이션 프록시를 설정하는 방법은?","proxy.RoundRobinProxySwitcher에 프록시 URL 목록을 전달하고 c.SetProxyFunc(rp)로 등록하면 됩니다. 더 유연한 제어가 필요하면 c.SetProxyFunc(func(*http.Request) (*url.URL, error))로 커스텀 함수를 작성해 요청마다 ProxyHat 게이트웨이 주소와 세션 ID를 동적으로 생성하세요.",{"question":23,"answer":24},"Colly에서 어떤 프록시 유형이 가장 적합한가요?","봇 방지 시스템이 있는 하드 타겟(SERP, 이커머스, 소셜 미디어)에서는 주거(residential) 프록시가 가장 적합합니다. 데이터센터 IP는 AS 정보로 쉽게 식별됩니다. ProxyHat 주거 프록시를 사용하면 실제 ISP IP로 요청이 전달되어 차단률이 크게 낮아집니다. SOCKS5(포트 1080)는 HTTP 프록시가 감지되는 사이트에서 대안이 됩니다.",{"question":26,"answer":27},"Colly에서 차단을 피하려면 어떻게 해야 하나요?","세 가지를 결합하세요: (1) ProxyHat 주거 프록시로 매 요청마다 IP 로테이션, (2) Limit()으로 Parallelism을 20~50, RandomDelay를 1~3초로 설정, (3) OnError에서 429\u002F503 응답 시 c.Clone()으로 재시도. User-Agent 회전과 robots.txt 준수도 필수입니다.",{"question":29,"answer":30},"Colly의 비동기 모드에서 프록시 로테이션이 안전한가요?","네, c.Async = true와 SetProxyFunc는 함께 작동합니다. 단, atomic.AddUint64 같은 스레드 안전 카운터를 사용해 세션 ID를 생성해야 합니다. 일반 변수를 사용하면 고루틴 경쟁 조건으로 인해 동일 IP가 중복 할당될 수 있습니다.",{"question":32,"answer":33},"분산 환경에서 Colly 프록시 로테이션을 어떻게 관리하나요?","Colly의 redisstorage 백엔드를 사용해 방문한 URL을 추적하고, 각 컨테이너가 독립적으로 ProxyHat 프록시를 로테이션하게 하세요. 중앙에서 프록시 풀을 관리할 필요 없이, 각 노드가 자체적으로 세션 ID를 생성하면 됩니다. 큐 스레드 수는 노드당 10~20이 적당합니다.",false,"2026-08-04T10:05:34+00:00","2026-10-03T23:53:00+00:00","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fko\u002Fcolly-rotating-proxy-guide-master.webp","Rotating Proxies in Colly: A Framework-Idiomatic Guide for Go Developers","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fko\u002Fcolly-rotating-proxy-guide-card.webp",12,{"name":42,"slug":43,"bio":44,"avatar_url":14,"website_url":14,"social_links":14},"ProxyHat Team","proxyhat-team","The ProxyHat editorial team covers proxies, web scraping, and data extraction.",[46],{"id":47,"slug":48,"name":49,"description":14,"meta_title":50,"meta_description":51,"parent_id":14},4,"gaebaljja-gaideu","개발자 가이드","개발자 가이드 | ProxyHat 블로그","프록시를 애플리케이션에 통합하기 위한 코드 튜토리얼 및 SDK 가이드.",[],{"es":54,"ru":55,"ja":56,"pt":57,"pl":58,"ko":13,"tr":59,"zh":60,"it":61,"de":62,"en":63,"fr":64,"x-default":63},"\u002Fes\u002Fblog\u002Frotacion-proxies-colly-golang-1","\u002Fru\u002Fblog\u002Frotaciya-proksi-v-colly-1","\u002Fja\u002Fblog\u002Fcolly-purokushi-roteshon-gaido","\u002Fpt\u002Fblog\u002Fproxies-rotativos-em-colly","\u002Fpl\u002Fblog\u002Frotacja-proxy-w-colly-1","\u002Ftr\u002Fblog\u002Fcolly-doner-proxy-rehberi","\u002Fcn\u002Fblog\u002Fcolly-lunhuan-daili-shixian-zhinan","\u002Fit\u002Fblog\u002Fproxy-rotanti-in-colly-guida","\u002Fde\u002Fblog\u002Frotierende-proxies-in-colly","\u002Fblog\u002Frotating-proxies-in-colly-golang","\u002Ffr\u002Fblog\u002Frotation-proxies-colly-golang-1",{"es":54,"ru":55,"ja":56,"pt":57,"pl":58,"ko":13,"tr":59,"zh":60,"it":61,"de":62,"en":63,"fr":64},71,[68,102,129,145],{"id":69,"slug":70,"title":71,"excerpt":72,"featured_image_url":73,"featured_image_alt":74,"card_image_url":75,"og_image_url":76,"published_at":77,"updated_at":78,"content_updated_at":79,"reading_time_minutes":80,"is_featured":34,"indexable":4,"views":81,"author":82,"categories":83,"tags":85},210,"ai-agent-proxy-seoljeong","AI 에이전트 프록시 설정: browser-use·Crawl4AI·MCP","클라우드 VM의 에이전트는 데이터센터 IP로 접속합니다. browser-use, Crawl4AI, MCP 서버에서 지금 작동하는 프록시 설정을 sticky와 로테이션 선택 표, 피해야 할 비용 함정과 함께 정리했습니다.","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fko\u002Fai-agent-proxy-seoljeong-master.webp","Proxy Setup for AI Agents: browser-use, Crawl4AI and an MCP Server","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fko\u002Fai-agent-proxy-seoljeong-card.webp","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fko\u002Fai-agent-proxy-seoljeong-og.webp","2026-10-24T09:00:00+00:00","2026-10-24T09:00:20+00:00","2026-10-03T09:41:40+00:00",14,15,{"name":42,"slug":43,"bio":44,"avatar_url":14,"website_url":14,"social_links":14},[84],{"id":47,"slug":48,"name":49,"description":14,"meta_title":50,"meta_description":51,"parent_id":14},[86,90,94,98],{"id":87,"slug":88,"name":89},1,"web-scraping","웹 스크래핑",{"id":91,"slug":92,"name":93},2,"residential-proxies","주거용 프록시",{"id":95,"slug":96,"name":97},9,"python","Python",{"id":99,"slug":100,"name":101},22,"playwright","Playwright",{"id":103,"slug":104,"title":105,"excerpt":106,"featured_image_url":107,"featured_image_alt":108,"card_image_url":109,"og_image_url":110,"published_at":111,"updated_at":112,"content_updated_at":79,"reading_time_minutes":80,"is_featured":34,"indexable":4,"views":113,"author":114,"categories":115,"tags":117},206,"camoufox-residential-proxy-python-gaideu","Camoufox와 레지덴셜 프록시: 코드로 보는 Python 가이드","C++ 레벨에서 패치한 Firefox인 Camoufox를 레지덴셜 프록시 뒤에서 돌리는 방법. 최신 Python API, geoip에 스티키 세션이 필요한 이유, 핑거프린트 일관성 체크리스트, 그리고 Patchright나 nodriver가 더 맞는 경우를 정리했습니다.","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fko\u002Fcamoufox-residential-proxy-python-gaideu-master.webp","Camoufox with Residential Proxies: A Code-First Python Guide","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fko\u002Fcamoufox-residential-proxy-python-gaideu-card.webp","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fko\u002Fcamoufox-residential-proxy-python-gaideu-og.webp","2026-10-13T09:00:00+00:00","2026-10-13T09:00:22+00:00",31,{"name":42,"slug":43,"bio":44,"avatar_url":14,"website_url":14,"social_links":14},[116],{"id":47,"slug":48,"name":49,"description":14,"meta_title":50,"meta_description":51,"parent_id":14},[118,119,120,124,125],{"id":87,"slug":88,"name":89},{"id":91,"slug":92,"name":93},{"id":121,"slug":122,"name":123},6,"anti-detection","안티 탐지",{"id":95,"slug":96,"name":97},{"id":126,"slug":127,"name":128},21,"headless-browser","헤드리스 브라우저",{"id":130,"slug":131,"title":132,"excerpt":133,"featured_image_url":134,"featured_image_alt":135,"card_image_url":136,"og_image_url":137,"published_at":138,"updated_at":138,"content_updated_at":139,"reading_time_minutes":40,"is_featured":34,"indexable":4,"views":140,"author":141,"categories":142,"tags":144},176,"got-scraping-nodejs-proxy-guide-1","Node.js에서 got-scraping과 주거 프록시로 웹 스크래핑하기","got-scraping의 헤더 생성기와 HTTP\u002F2 지원을 활용해 차단을 우회하는 방법, ProxyHat 주거 프록시 라우팅, 그리고 Crawlee 통합까지 다루는 실전 가이드입니다.","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fko\u002Fgot-scraping-nodejs-proxy-guide-1-master.webp","got-scraping in Node.js: A Developer's Guide with Residential Proxies","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fko\u002Fgot-scraping-nodejs-proxy-guide-1-card.webp","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fko\u002Fgot-scraping-nodejs-proxy-guide-1-og.webp","2026-08-04T16:05:06+00:00","2026-10-03T08:29:58+00:00",121,{"name":42,"slug":43,"bio":44,"avatar_url":14,"website_url":14,"social_links":14},[143],{"id":47,"slug":48,"name":49,"description":14,"meta_title":50,"meta_description":51,"parent_id":14},[],{"id":146,"slug":147,"title":148,"excerpt":149,"featured_image_url":150,"featured_image_alt":151,"card_image_url":152,"og_image_url":153,"published_at":154,"updated_at":154,"content_updated_at":155,"reading_time_minutes":40,"is_featured":34,"indexable":4,"views":156,"author":157,"categories":158,"tags":160},195,"bybit-v5-market-api-proxy-scraping","회전 프록시로 암호화폐 시장 데이터 수집하기 (Bybit V5 Market API 사례)","Bybit V5 Market API의 orderbook, tickers, kline, recent-trade 엔드포인트를 회전 프록시로 안정적으로 수집하는 개발자 가이드입니다. IP 레이트 리밋, 지역 제한, ProxyHat SDK 예제를 포함합니다.","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fko\u002Fbybit-v5-market-api-proxy-scraping-master.webp","How to Scrape the Bybit V5 Market API with Rotating Proxies","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fko\u002Fbybit-v5-market-api-proxy-scraping-card.webp","https:\u002F\u002Fstatic.proxyhat.com\u002Fstorage\u002Fblog-covers\u002Fko\u002Fbybit-v5-market-api-proxy-scraping-og.webp","2026-08-03T16:09:16+00:00","2026-10-04T01:29:51+00:00",87,{"name":42,"slug":43,"bio":44,"avatar_url":14,"website_url":14,"social_links":14},[159],{"id":47,"slug":48,"name":49,"description":14,"meta_title":50,"meta_description":51,"parent_id":14},[],[]]