├── .gitignore ├── README.md ├── cmd └── crawlerl.go ├── conf └── conf.go ├── main.go ├── models ├── parse_config.go └── parse_page.go └── testData ├── gui-config.json └── statistics-config.json /.gitignore: -------------------------------------------------------------------------------- 1 | run.sh 2 | 3 | crawlershadowsocks-64.zip 4 | crawlershadowsocks-32.zip 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CrawlerIShadowsocks 2 | 用来及时获取Ishadowsocks的免费SS信息。 3 | 4 | # 使用方法 5 | 1. 可将执行程序 放到 Shadowsocks.exe 同目录下。 也可以使用 -p 参数指定 Shadowsocks.exe 的目录路径. 6 | 7 | 2. 关闭正在运行的 Shadowsocks.exe 8 | 9 | 2. 双击运行即可。 10 | ![](http://7xsspq.com2.z0.glb.clouddn.com/2016-04-30%2016-30-44%E5%B1%8F%E5%B9%95%E6%88%AA%E5%9B%BE.png) 11 | -------------------------------------------------------------------------------- /cmd/crawlerl.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | "os/exec" 6 | 7 | "github.com/codegangsta/cli" 8 | "github.com/iyannik0215/CrawlerIShadowsocks/conf" 9 | "github.com/iyannik0215/CrawlerIShadowsocks/models" 10 | ) 11 | 12 | func RunCrawlerl(ctx *cli.Context) { 13 | models.WriteProfile( 14 | models.ModifyProfile( 15 | models.AnalysisProfile(models.ReadProfile()), 16 | models.ConvertMap(models.ParsePage(models.GetPage())))) 17 | 18 | fmt.Println("执行完成, 关闭Dos退出.") 19 | exec.Command(conf.ExecPath + "Shadowsocks.exe").Run() 20 | } 21 | -------------------------------------------------------------------------------- /conf/conf.go: -------------------------------------------------------------------------------- 1 | package conf 2 | 3 | var ( 4 | URL = "http://www.ishadowsocks.net/" 5 | 6 | ExecPath = "./" 7 | FileName = "gui-config.json" 8 | 9 | DefaultConfig = []byte(`{ 10 | "configs": [], 11 | "strategy": "com.shadowsocks.strategy.balancing", 12 | "index": -1, 13 | "global": false, 14 | "enabled": true, 15 | "shareOverLan": false, 16 | "isDefault": false, 17 | "localPort": 1080, 18 | "pacUrl": null, 19 | "useOnlinePac": false, 20 | "availabilityStatistics": false, 21 | "autoCheckUpdate": true, 22 | "logViewer": null 23 | }`) 24 | ) 25 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/codegangsta/cli" 7 | "github.com/iyannik0215/CrawlerIShadowsocks/cmd" 8 | "github.com/iyannik0215/CrawlerIShadowsocks/conf" 9 | ) 10 | 11 | func main() { 12 | app := cli.NewApp() 13 | app.Name = "Crawlerl shadowoskcs" 14 | app.Usage = "Crawlerl http://www.ishadowsocks.net free ss." 15 | app.Version = "2.0" 16 | 17 | app.Flags = []cli.Flag{ 18 | cli.StringFlag{ 19 | Name: "path, p", 20 | Value: "./", 21 | Usage: "Shadowsocks.exe 的路径, 默认路径为 当前路径, 推荐.", 22 | Destination: &conf.ExecPath, 23 | }, 24 | } 25 | 26 | app.Action = cmd.RunCrawlerl 27 | 28 | app.Run(os.Args) 29 | } 30 | -------------------------------------------------------------------------------- /models/parse_config.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "io/ioutil" 5 | "log" 6 | "os" 7 | 8 | "github.com/bitly/go-simplejson" 9 | "github.com/iyannik0215/CrawlerIShadowsocks/conf" 10 | ) 11 | 12 | func Exist(filename string) bool { 13 | _, err := os.Stat(filename) 14 | return err == nil || os.IsExist(err) 15 | } 16 | 17 | func ReadProfile() []byte { 18 | if !Exist(conf.ExecPath + conf.FileName) { 19 | if err := ioutil.WriteFile(conf.ExecPath+conf.FileName, conf.DefaultConfig, 0664); err != nil { 20 | log.Fatal("写入文件失败.") 21 | } 22 | } 23 | src, err := ioutil.ReadFile(conf.ExecPath + conf.FileName) 24 | if err != nil { 25 | log.Fatal("[ERROR]:", err) 26 | } 27 | return src 28 | } 29 | 30 | func AnalysisProfile(src []byte) *simplejson.Json { 31 | json, err := simplejson.NewJson(src) 32 | if err != nil { 33 | log.Fatal("[ERROR]:", err) 34 | } 35 | 36 | return json 37 | } 38 | 39 | func ModifyProfile(configs *simplejson.Json, param []interface{}) []byte { 40 | configs.Del("configs") 41 | configs.Set("configs", param) 42 | src, err := configs.EncodePretty() 43 | if err != nil { 44 | log.Fatal("[ERROR:]", err) 45 | } 46 | // log.Println(string(src)) 47 | return src 48 | } 49 | 50 | func WriteProfile(src []byte) { 51 | err := ioutil.WriteFile(conf.ExecPath+conf.FileName, src, 0644) 52 | if err != nil { 53 | log.Fatal("[ERROR]:", err) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /models/parse_page.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "log" 5 | "reflect" 6 | "strings" 7 | 8 | "github.com/PuerkitoBio/goquery" 9 | ) 10 | 11 | type Config struct { 12 | Remarks string 13 | Server string 14 | Server_port string 15 | Password string 16 | Method string 17 | } 18 | 19 | func GetPage() *goquery.Document { 20 | for { 21 | doc, err := goquery.NewDocument("http://www.ishadowsocks.net") 22 | if err != nil { 23 | log.Println("[ERROR]:", err) 24 | } 25 | return doc 26 | } 27 | } 28 | 29 | func ParsePage(doc *goquery.Document) [3]Config { 30 | var configArr = [3]Config{} 31 | count := 0 32 | 33 | doc.Find(".col-lg-4.text-center").EachWithBreak(func(i int, contentSelection *goquery.Selection) bool { 34 | contentSelection.Find("h4").EachWithBreak(func(i int, configSelection *goquery.Selection) bool { 35 | text := configSelection.Text() 36 | result := strings.Split(text, ":") 37 | 38 | switch i { 39 | case 0: 40 | configArr[count].Remarks = result[0] 41 | configArr[count].Server = result[1] 42 | break 43 | case 1: 44 | configArr[count].Server_port = result[1] 45 | break 46 | case 2: 47 | configArr[count].Password = result[1] 48 | break 49 | case 3: 50 | configArr[count].Method = result[1] 51 | break 52 | } 53 | 54 | if i == 3 { 55 | count++ 56 | return false 57 | } 58 | return true 59 | }) 60 | 61 | if i == 2 { 62 | return false 63 | } 64 | return true 65 | }) 66 | 67 | return configArr 68 | } 69 | 70 | func ConvertMap(conf [3]Config) []interface{} { 71 | mapSlice := make([]map[string]interface{}, 3) 72 | o := make([]interface{}, 3) 73 | 74 | for i, cf := range conf { 75 | tmpMap := make(map[string]interface{}) 76 | elem := reflect.ValueOf(&cf).Elem() 77 | type_ := elem.Type() 78 | 79 | for j := 0; j < type_.NumField(); j++ { 80 | tmpMap[strings.ToLower(type_.Field(j).Name)] = elem.Field(j).Interface() 81 | } 82 | 83 | mapSlice[i] = tmpMap 84 | o[i] = mapSlice[i] 85 | } 86 | return o 87 | } 88 | -------------------------------------------------------------------------------- /testData/gui-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "configs": [ 3 | { 4 | "server": "", 5 | "server_port": 8388, 6 | "password": "", 7 | "method": "aes-256-cfb", 8 | "remarks": "", 9 | "auth": false 10 | } 11 | ], 12 | "strategy": "com.shadowsocks.strategy.balancing", 13 | "index": -1, 14 | "global": false, 15 | "enabled": true, 16 | "shareOverLan": false, 17 | "isDefault": false, 18 | "localPort": 1080, 19 | "pacUrl": null, 20 | "useOnlinePac": false, 21 | "availabilityStatistics": false, 22 | "autoCheckUpdate": true, 23 | "logViewer": null 24 | } -------------------------------------------------------------------------------- /testData/statistics-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "Calculations": { 3 | "AverageLatency": 0.0, 4 | "MinLatency": 0.0, 5 | "MaxLatency": 0.0, 6 | "AverageInboundSpeed": 0.0, 7 | "MinInboundSpeed": 0.0, 8 | "MaxInboundSpeed": 0.0, 9 | "AverageOutboundSpeed": 0.0, 10 | "MinOutboundSpeed": 0.0, 11 | "MaxOutboundSpeed": 0.0, 12 | "AverageResponse": 0.0, 13 | "MinResponse": 0.0, 14 | "MaxResponse": 0.0, 15 | "PackageLoss": 0.0 16 | }, 17 | "StatisticsEnabled": true, 18 | "ByHourOfDay": true, 19 | "Ping": false, 20 | "ChoiceKeptMinutes": 10, 21 | "DataCollectionMinutes": 10, 22 | "RepeatTimesNum": 4 23 | } --------------------------------------------------------------------------------