在golang中使用clash作为http客户端的代理
摘要:如何在Go语言中使用Clash作为HTTP客户端的代理。它通过引入Clash的代码并在本地启动一个端口进行代理。代码中使用了github.com/Dreamacro/clash包来实现代理功能。它包括了启动代理、测速、随机选择代理和切换代理等功能。使用示例代码演示了如何在爬虫程序中使用Clash作为代理来发送HTTP请求。
在golang中使用clash作为http客户端的代理
在爬取网站时,经常会遇到一些反爬虫的网站,这些网站会检测你的ip地址,如果你的ip地址被检测到是爬虫的话,就会拒绝你的访问,这时候就需要使用代理来解决这个问题。代理的原理就是你的请求先发送给代理服务器,代理服务器再发送给目标服务器,目标服务器返回数据给代理服务器,代理服务器再返回给你。这样的话,目标服务器就无法知道你的真实ip地址,从而达到隐藏你的真实ip地址的目的。网上有一些免费的获取http代理的网站或者可以采用付费购买的方式获取http代理。
我这里我想采用机场来做我的http代理但是机场一般提供的是v2或者ssr协议的代理,恰好clash是用golang写的所以我能在我的golang程序中直接引入clash的代码开启一个本地端口进行代理。
下面是我的代码:
代理实现
package proxy
import (
"bytes"
"encoding/json"
"fmt"
"github.com/Dreamacro/clash/config"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/hub"
logs "github.com/danbai225/go-logs"
"go.uber.org/automaxprocs/maxprocs"
"io"
"math/rand"
"net/http"
"net/url"
"os"
"path/filepath"
"sync"
"time"
)
func init() {
rand.NewSource(time.Now().UnixNano())
}
type Clash struct {
configPath string
}
func New(configPath string) *Clash {
return &Clash{configPath: configPath}
}
func (c *Clash) Start() {
maxprocs.Set(maxprocs.Logger(func(string, ...any) {}))
C.SetHomeDir(".")
if c.configPath != "" {
if !filepath.IsAbs(c.configPath) {
currentDir, _ := os.Getwd()
c.configPath = filepath.Join(currentDir, c.configPath)
}
C.SetConfig(c.configPath)
} else {
configFile := filepath.Join(C.Path.HomeDir(), C.Path.Config())
C.SetConfig(configFile)
}
if err := config.Init(C.Path.HomeDir()); err != nil {
logs.Err("Initial configuration directory error: %s", err.Error())
return
}
if err := hub.Parse(hub.WithExternalController(":9091")); err != nil {
logs.Err("Parse config error: %s", err.Error())
return
}
time.Sleep(time.Second * 1)
c.Speed()
c.RandomSelect()
}
func (c *Clash) Speed() {
proxies := c.Proxies()
group := sync.WaitGroup{}
for _, s := range proxies {
group.Add(1)
go func() {
http.Get(fmt.Sprintf(`http://127.0.0.1:9091/proxies/%s/delay?timeout=5000&url=%s`, url.PathEscape(s.Name), url.QueryEscape(`https://baidu.com`)))
group.Done()
}()
}
group.Wait()
}
func (c *Clash) Proxies() []P {
resp, _ := http.Get(`http://127.0.0.1:9091/proxies`)
all, _ := io.ReadAll(resp.Body)
m := make(map[string]interface{})
m2 := make(map[string]P)
json.Unmarshal(all, &m)
marshal, _ := json.Marshal(m["proxies"])
json.Unmarshal(marshal, &m2)
ps := make([]P, 0)
for k := range m2 {
ps = append(ps, m2[k])
}
return ps
}
func (c *Clash) Switchover(name string) {
json := fmt.Sprintf(`{"name":"%s"}`, name)
req, err := http.NewRequest(http.MethodPut, "http://127.0.0.1:9091/proxies/GLOBAL", bytes.NewBufferString(json))
if err != nil {
logs.Err(err)
return
}
req.Header.Set("Content-Type", "application/json")
_, err = http.DefaultClient.Do(req)
if err != nil {
logs.Err(err)
return
}
}
func (c *Clash) EffectiveProxy() []P {
ps := make([]P, 0)
for _, p := range c.Proxies() {
if len(p.History) > 0 && p.History[len(p.History)-1].Delay > 0 {
ps = append(ps, p)
}
}
return ps
}
func (c *Clash) RandomSelect() string {
ps := c.EffectiveProxy()
name := ps[rand.Int63n(int64(len(ps)))].Name
c.Switchover(name)
logs.Info("切换为", name)
return name
}
type P struct {
Alive bool `json:"alive"`
History []struct {
Time time.Time `json:"time"`
Delay int `json:"delay"`
MeanDelay int `json:"meanDelay"`
} `json:"history"`
Name string `json:"name"`
Type string `json:"type"`
Udp bool `json:"udp"`
}
使用demo
package main
import (
logs "github.com/danbai225/go-logs"
"io"
"net/http"
"net/url"
"test/proxy"
)
func main() {
clash := proxy.New("clash.yml")
clash.Start()
// 创建代理URL
proxyURL, err := url.Parse("http://127.0.0.1:7799")
if err != nil {
return
}
transport := &http.Transport{
Proxy: http.ProxyURL(proxyURL),
}
c := &http.Client{
Transport: transport,
}
resp, err := c.Get("https://ip.useragentinfo.com/json")
all, err := io.ReadAll(resp.Body)
logs.Info(string(all))
}