Install
Nothing to install beyond Go itself; everything here is in the standard library.
go mod init monkeycrawlRotating residential
With DisableKeepAlives, every request opens a new tunnel through the residential gateway and so gets a new address. Leave keep-alives on and requests to the same host share one tunnel and one IP.
package main
import (
"fmt"
"io"
"net/http"
"net/url"
"time"
)
func main() {
proxy, _ := url.Parse("http://USER:[email protected]:8000")
client := &http.Client{
Timeout: 30 * time.Second,
Transport: &http.Transport{
Proxy: http.ProxyURL(proxy),
DisableKeepAlives: true,
},
}
for i := 0; i < 3; i++ {
resp, err := client.Get("https://httpbin.org/ip")
if err != nil {
fmt.Println(err)
continue
}
body, _ := io.ReadAll(resp.Body)
resp.Body.Close()
fmt.Print(string(body))
}
}A static datacenter or ISP IP
On a static datacenter IP keep-alives are what you want. This version fetches a list of URLs with at most eight in flight, using a buffered channel as the limit; it is the body of main, with log and sync added to the imports. For an ISP order, use the host and port from your dashboard.
proxy, _ := url.Parse("http://USER:PASS@IP:PORT")
client := &http.Client{
Timeout: 30 * time.Second,
Transport: &http.Transport{
Proxy: http.ProxyURL(proxy),
MaxIdleConnsPerHost: 8,
},
}
sem := make(chan struct{}, 8)
var wg sync.WaitGroup
for _, u := range urls {
wg.Add(1)
sem <- struct{}{}
go func(u string) {
defer wg.Done()
defer func() { <-sem }()
resp, err := client.Get(u)
if err != nil {
log.Println(u, err)
return
}
io.Copy(io.Discard, resp.Body)
resp.Body.Close()
log.Println(u, resp.StatusCode)
}(u)
}
wg.Wait()Keeping one identity
With keep-alives on, requests to one host reuse a tunnel and keep its exit address until the connection idles out. That is not a guarantee, so for a residential IP that must hold across a login, use a sticky session; the session setting for your account is in the dashboard.