867 lines
27 KiB
Go
867 lines
27 KiB
Go
package main
|
||
|
||
//import (
|
||
// "crypto/md5"
|
||
// "encoding/json"
|
||
// "fmt"
|
||
// "log"
|
||
// "math/rand"
|
||
// "net/http"
|
||
// "net/url"
|
||
// "regexp"
|
||
// "strconv"
|
||
// "strings"
|
||
// "sync"
|
||
// "time"
|
||
//
|
||
// "github.com/parnurzeal/gorequest"
|
||
//)
|
||
//
|
||
//// 获取商品模版
|
||
//func outGetGoodsTplMsgLinux(token, itemId, proxy string) (map[string]interface{}, error) {
|
||
// if token == "" {
|
||
// return nil, fmt.Errorf("请先登录获取Token")
|
||
// }
|
||
//
|
||
// url := fmt.Sprintf("https://seller.kongfz.com/pc/itemInfo/getTplFields?itemId=%s&isClone=1&v=%d",
|
||
// itemId, time.Now().Unix())
|
||
//
|
||
// log.Printf("请求URL: %s", url)
|
||
//
|
||
// // 创建HTTP客户端
|
||
// request := gorequest.New()
|
||
//
|
||
// // 设置代理(如果有提供代理URL)
|
||
// if proxy != "" {
|
||
// request.Proxy(proxy)
|
||
// log.Printf("使用代理: %s", proxy)
|
||
// }
|
||
//
|
||
// resp, body, errs := request.Get(url).
|
||
// Set("Cookie", fmt.Sprintf("PHPSESSID=%s", token)).
|
||
// Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36").
|
||
// Set("Accept", "application/json, text/plain, */*").
|
||
// Set("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8").
|
||
// Set("Referer", "https://seller.kongfz.com/").
|
||
// Set("Origin", "https://seller.kongfz.com").
|
||
// Timeout(30 * time.Second).
|
||
// End()
|
||
//
|
||
// if len(errs) > 0 {
|
||
// return nil, fmt.Errorf("请求失败: %v", errs)
|
||
// }
|
||
//
|
||
// // 检查HTTP状态码
|
||
// if resp.StatusCode != http.StatusOK {
|
||
// return nil, fmt.Errorf("HTTP错误: %d - %s", resp.StatusCode, resp.Status)
|
||
// }
|
||
//
|
||
// var data map[string]interface{}
|
||
// if err := json.Unmarshal([]byte(body), &data); err != nil {
|
||
// return nil, fmt.Errorf("解析JSON失败: %w", err)
|
||
// }
|
||
//
|
||
// // 检查API响应状态
|
||
// if val, ok := data["status"].(float64); ok && val == 1 {
|
||
// return data, nil
|
||
// }
|
||
//
|
||
// return nil, fmt.Errorf("API返回错误: %+v", data)
|
||
//}
|
||
//
|
||
//func main() {
|
||
// fmt.Println("=== 孔夫子商品模板API服务 ===")
|
||
//
|
||
// http.HandleFunc("/api/goodsTemplate", getGoodsTemplateHandler)
|
||
// http.HandleFunc("/api/outGetImageByIsbn", getOutGetImageByIsbnHandler)
|
||
//
|
||
// port := "8989"
|
||
// server := &http.Server{
|
||
// Addr: ":" + port,
|
||
// Handler: nil,
|
||
// }
|
||
// // 启动服务器
|
||
// if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
||
// fmt.Printf("服务器启动失败: %v\n", err)
|
||
// }
|
||
//}
|
||
//
|
||
//// 获取商品模板接口
|
||
//func getGoodsTemplateHandler(w http.ResponseWriter, r *http.Request) {
|
||
// // 设置响应头
|
||
// w.Header().Set("Content-Type", "application/json")
|
||
//
|
||
// // 只处理GET请求
|
||
// if r.Method != http.MethodGet {
|
||
// w.WriteHeader(http.StatusMethodNotAllowed)
|
||
// json.NewEncoder(w).Encode(map[string]interface{}{
|
||
// "success": false,
|
||
// "error": "只支持GET请求",
|
||
// })
|
||
// return
|
||
// }
|
||
//
|
||
// // 获取查询参数
|
||
// token := r.URL.Query().Get("token")
|
||
// itemId := r.URL.Query().Get("itemId")
|
||
// proxy := r.URL.Query().Get("proxy")
|
||
//
|
||
// // 验证必需参数
|
||
// if token == "" || itemId == "" {
|
||
// w.WriteHeader(http.StatusBadRequest)
|
||
// json.NewEncoder(w).Encode(map[string]interface{}{
|
||
// "success": false,
|
||
// "error": "缺少必需参数: token 和 itemid",
|
||
// "usage": map[string]string{
|
||
// "token": "登录Token (PHPSESSID)",
|
||
// "itemid": "商品ID",
|
||
// "proxy": "代理地址 (可选)",
|
||
// },
|
||
// "example": "GET /api/goods-template?token=abc123&itemid=123456&proxy=http://proxy:8080",
|
||
// })
|
||
// return
|
||
// }
|
||
//
|
||
// log.Printf("收到请求 - 商品ID: %s", itemId)
|
||
//
|
||
// // 调用函数获取商品模板
|
||
// result, err := outGetGoodsTplMsgLinux(token, itemId, proxy)
|
||
// if err != nil {
|
||
// log.Printf("获取商品模板失败: %v", err)
|
||
// w.WriteHeader(http.StatusInternalServerError)
|
||
// json.NewEncoder(w).Encode(map[string]interface{}{
|
||
// "success": false,
|
||
// "error": err.Error(),
|
||
// })
|
||
// return
|
||
// }
|
||
//
|
||
// // 返回成功响应
|
||
// json.NewEncoder(w).Encode(map[string]interface{}{
|
||
// "success": true,
|
||
// "data": result,
|
||
// })
|
||
//}
|
||
//
|
||
//func getOutGetImageByIsbnHandler(w http.ResponseWriter, r *http.Request) {
|
||
// // 设置响应头
|
||
// w.Header().Set("Content-Type", "application/json")
|
||
//
|
||
// // 只处理GET请求
|
||
// if r.Method != http.MethodGet {
|
||
// w.WriteHeader(http.StatusMethodNotAllowed)
|
||
// json.NewEncoder(w).Encode(map[string]interface{}{
|
||
// "success": false,
|
||
// "error": "只支持GET请求",
|
||
// })
|
||
// return
|
||
// }
|
||
//
|
||
// // 获取查询参数
|
||
// token := r.URL.Query().Get("token")
|
||
// isbn := r.URL.Query().Get("isbn")
|
||
// proxyType := r.URL.Query().Get("proxyType")
|
||
// username := r.URL.Query().Get("username")
|
||
// password := r.URL.Query().Get("password")
|
||
// machineCode := r.URL.Query().Get("machineCode")
|
||
// //proxy := r.URL.Query().Get("proxy")
|
||
//
|
||
// // 验证必需参数
|
||
// if token == "" || isbn == "" {
|
||
// w.WriteHeader(http.StatusBadRequest)
|
||
// json.NewEncoder(w).Encode(map[string]interface{}{
|
||
// "success": false,
|
||
// "error": "缺少必需参数: token 和 isbn",
|
||
// "usage": map[string]string{
|
||
// "token": "登录Token (PHPSESSID)",
|
||
// "isbn": "isbn",
|
||
// "proxy": "代理地址 (可选)",
|
||
// },
|
||
// "example": "GET /api/goods-template?token=abc123&itemid=123456&proxy=http://proxy:8080",
|
||
// })
|
||
// return
|
||
// }
|
||
//
|
||
// manager, err2 := proxyTypeManager(proxyType, username, password, machineCode)
|
||
// if err2 != nil {
|
||
// return
|
||
// }
|
||
// log.Printf("收到请求 - 商品ID: %s", isbn)
|
||
//
|
||
// // 调用函数获取商品模板
|
||
// result, err := OutGetImageByIsbns(token, isbn, manager, 0, 0)
|
||
// if err != nil {
|
||
// log.Printf("获取商品模板失败: %v", err)
|
||
// w.WriteHeader(http.StatusInternalServerError)
|
||
// json.NewEncoder(w).Encode(map[string]interface{}{
|
||
// "success": false,
|
||
// "error": err.Error(),
|
||
// })
|
||
// return
|
||
// }
|
||
// // 返回成功响应
|
||
// json.NewEncoder(w).Encode(map[string]interface{}{
|
||
// "success": true,
|
||
// "data": result,
|
||
// })
|
||
//}
|
||
//
|
||
//// 条目详情结构体
|
||
//type BookInfo struct {
|
||
// BookName string `json:"book_name"` // 书名
|
||
// Author string `json:"author"` // 作者
|
||
// Publisher string `json:"publisher"` // 出版社
|
||
// ISBN string `json:"isbn"` // ISBN
|
||
// PublicationTime int64 `json:"publication_time"` // 出版时间
|
||
// Edition string `json:"edition"` // 版次
|
||
// PrintTime string `json:"print_time"` // 印刷时间
|
||
// FixPrice string `json:"fix_price"` // 定价
|
||
// BindingLayout string `json:"binding_layout"` // 装帧
|
||
// Format string `json:"format"` // 开本
|
||
// Paper string `json:"paper"` // 纸张
|
||
// Pages string `json:"pages"` // 页数
|
||
// Wordage string `json:"wordage"` // 字数
|
||
// Languages string `json:"languages"` // 语种
|
||
// Era string `json:"era"` // 年代
|
||
// EngravingMethod string `json:"engraving_method"` // 刻印方式
|
||
// Dimensions string `json:"dimensions"` // 尺寸
|
||
// VolumeNumber string `json:"volume_number"` // 册数
|
||
// BookPic string `json:"book_pic"` // 图书封面图(官图)
|
||
// BookPicS string `json:"book_pic_s"` // 图书封面图(实拍图)
|
||
// SellingPrice string `json:"selling_price"` // 售价
|
||
// Condition string `json:"condition"` // 品相
|
||
// ExpressDeliveryFee string `json:"express_delivery_fee"` // 快递费
|
||
// Editor string `json:"editor"` // 编辑
|
||
// Category string `json:"category"` // 分类
|
||
// BuyCount string `json:"buy_count"` // 买过
|
||
// SellCount string `json:"sell_count"` // 在卖
|
||
// Content string `json:"content"` // 内容
|
||
// Mid int64 `json:"mid"` // 商家id
|
||
// ItemId int64 `json:"item_id"` // 商品id
|
||
// ShopId int64 `json:"shop_id"` // 店铺id
|
||
// DetailUrl string `json:"detail_url"` // 商品详情url
|
||
//}
|
||
//
|
||
//// 获取图片URL(官图和拍图)
|
||
//func OutGetImageByIsbns(token string, isbn string, proxy string, isLiveImage int, isReturnMsg int) (*BookInfo, error) {
|
||
// fmt.Println("[DEBUG] 使用的ISBN: ", isbn)
|
||
// // isLiveImage 1实拍图 0官图 ,isReturnMsg 0商品信息
|
||
// bookInfo := &BookInfo{}
|
||
// //if isLiveImage == 0 {
|
||
// // 孔网官图请求
|
||
// gtUrl := fmt.Sprintf("%s?keyword=%s", "https://search.kongfz.com/pc-gw/search-web/client/pc/bookLib/keyword/list", isbn)
|
||
// // 创建HTTP客户端
|
||
// requestGt := gorequest.New()
|
||
// // 设置代理(如果有提供代理URL)
|
||
// if proxy != "" {
|
||
// requestGt.Proxy(proxy)
|
||
// }
|
||
// // 发送请求
|
||
// respGt, bodyGt, errsGt := requestGt.Get(gtUrl).
|
||
// Set("Cookie", fmt.Sprintf("PHPSESSID=%s", token)).
|
||
// Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36").
|
||
// Set("Accept", "application/json, text/plain, */*").
|
||
// Set("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8").
|
||
// Set("Referer", "https://item.kongfz.com/").
|
||
// Timeout(30 * time.Second).
|
||
// End()
|
||
// if len(errsGt) > 0 {
|
||
// // 检查是否是代理相关错误
|
||
// var isProxyError bool
|
||
// var errorDetails []string
|
||
// for _, e := range errsGt {
|
||
// errorStr := e.Error()
|
||
// errorDetails = append(errorDetails, errorStr)
|
||
// if strings.Contains(errorStr, "Proxy Authentication Required") ||
|
||
// strings.Contains(errorStr, "connectex: A connection attempt failed") ||
|
||
// strings.Contains(errorStr, "connectex: No connection could be made") ||
|
||
// strings.Contains(errorStr, "proxyconnect tcp") ||
|
||
// strings.Contains(errorStr, "timeout") ||
|
||
// strings.Contains(errorStr, "connection refused") {
|
||
// isProxyError = true
|
||
// }
|
||
// }
|
||
// log.Printf("[ERROR] 请求错误详情: %v", errorDetails)
|
||
// if isProxyError {
|
||
// // 处理代理失败
|
||
// return nil, fmt.Errorf("代理连接失败")
|
||
// }
|
||
// return nil, fmt.Errorf("查询请求失败: %v", errsGt)
|
||
// }
|
||
// //检查HTTP状态码
|
||
// if respGt.StatusCode != http.StatusOK {
|
||
// return nil, fmt.Errorf("HTTP错误: %s", respGt.Status)
|
||
// }
|
||
// // 解析响应
|
||
// var apiGtResp struct {
|
||
// Status int `json:"status"`
|
||
// ErrType string `json:"errType"`
|
||
// Message string `json:"message"`
|
||
// SystemTime int64 `json:"systemTime"`
|
||
// Data struct {
|
||
// ItemResponse struct {
|
||
// Total int `json:"total"`
|
||
// List []struct {
|
||
// BookName string `json:"bookName"`
|
||
// Mid int64 `json:"mid"`
|
||
// ImgUrlEntity struct {
|
||
// BigImgUrl string `json:"bigImgUrl"`
|
||
// } `json:"imgUrlEntity"`
|
||
// Isbn string `json:"isbn"`
|
||
// BookShowInfo []string `json:"bookShowInfo"`
|
||
// } `json:"list"`
|
||
// } `json:"itemResponse"`
|
||
// } `json:"data"`
|
||
// }
|
||
// if err := json.Unmarshal([]byte(bodyGt), &apiGtResp); err != nil {
|
||
// return nil, fmt.Errorf("解析JSON失败: %w", err)
|
||
// }
|
||
// if apiGtResp.ErrType == "102" {
|
||
// return nil, fmt.Errorf("错误信息: %w,状态码: %s", apiGtResp.Message, apiGtResp.ErrType)
|
||
// }
|
||
// // 如果找到条目,返回图片URL
|
||
// if apiGtResp.Data.ItemResponse.Total > 0 && len(apiGtResp.Data.ItemResponse.List) > 0 {
|
||
// list := apiGtResp.Data.ItemResponse.List[0]
|
||
// bookShowInfo := list.BookShowInfo
|
||
// bookInfo.BookName = list.BookName
|
||
// bookInfo.BookPic = list.ImgUrlEntity.BigImgUrl
|
||
// bookInfo.ISBN = list.Isbn
|
||
// // 根据长度安全填充字段
|
||
// if isReturnMsg == 0 {
|
||
// if len(bookShowInfo) > 0 {
|
||
// bookInfo.Author = bookShowInfo[0]
|
||
// }
|
||
// if len(bookShowInfo) > 1 {
|
||
// bookInfo.Publisher = bookShowInfo[1]
|
||
// }
|
||
// if len(bookShowInfo) > 2 {
|
||
// bookInfo.PublicationTime = validateDateFormat(bookShowInfo[2])
|
||
// }
|
||
// if len(bookShowInfo) > 3 {
|
||
// bookInfo.BindingLayout = bookShowInfo[3]
|
||
// }
|
||
// if len(bookShowInfo) > 4 {
|
||
// bookInfo.FixPrice = bookShowInfo[4]
|
||
// } else {
|
||
// log.Printf("[WARN] BookShowInfo 长度不足 (仅 %d 项): %v", len(bookShowInfo), bookShowInfo)
|
||
// }
|
||
// }
|
||
// }
|
||
// //return bookInfo, nil
|
||
//
|
||
// //}
|
||
// //if isLiveImage == 1 {
|
||
//
|
||
// size := 10
|
||
// // 实拍图
|
||
// sptUrl := fmt.Sprintf("%s?dataType=0&keyword=%s&page=1&size=%d&sortType=7&actionPath=quality,sortType&quality=85~&quaSelect=2&userArea=13003000000",
|
||
// "https://search.kongfz.com/pc-gw/search-web/client/pc/product/keyword/list", isbn, size)
|
||
// //创建HTTP客户端
|
||
// requestSpt := gorequest.New()
|
||
// //设置代理(如果有提供代理URL)
|
||
// if proxy != "" {
|
||
// requestSpt.Proxy(proxy)
|
||
// }
|
||
// // 发送请求
|
||
// respSpt, bodySpt, errsSpt := requestSpt.Get(sptUrl).
|
||
// Proxy(proxy).
|
||
// Set("Cookie", token).
|
||
// Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36").
|
||
// Set("Accept", "application/json, text/plain, */*").
|
||
// Set("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8").
|
||
// Set("Referer", "https://item.kongfz.com/").
|
||
// Timeout(30 * time.Second).
|
||
// End()
|
||
// // 错误处理
|
||
// if len(errsSpt) > 0 {
|
||
// return nil, fmt.Errorf("请求失败: %v", errsSpt)
|
||
// }
|
||
// // 检查HTTP状态码
|
||
// if respSpt.StatusCode != http.StatusOK {
|
||
// return nil, fmt.Errorf("HTTP错误: %s", respSpt.Status)
|
||
// }
|
||
// // 解析响应
|
||
// var apiSptResp struct {
|
||
// Status int `json:"status"`
|
||
// ErrType string `json:"errType"`
|
||
// Message string `json:"message"`
|
||
// SystemTime int64 `json:"systemTime"`
|
||
// Data struct {
|
||
// ItemResponse struct {
|
||
// Total int `json:"total"`
|
||
// List []struct {
|
||
// ItemId int64 `json:"itemId"`
|
||
// Title string `json:"title"`
|
||
// ImgUrl string `json:"imgUrl"`
|
||
// ImgBigUrl string `json:"imgBigUrl"`
|
||
// Author string `json:"author"`
|
||
// PubDateText string `json:"pubDateText"`
|
||
// Isbn string `json:"isbn"`
|
||
// Press string `json:"press"`
|
||
// ShopId int64 `json:"shopId"`
|
||
// TplRecords []struct {
|
||
// Key string `json:"key"`
|
||
// Value string `json:"value"`
|
||
// } `json:"tplRecords"`
|
||
// } `json:"list"`
|
||
// } `json:"itemResponse"`
|
||
// } `json:"data"`
|
||
// }
|
||
// // 解析JSON
|
||
// if err := json.Unmarshal([]byte(bodySpt), &apiSptResp); err != nil {
|
||
// return nil, fmt.Errorf("解析JSON失败: %w", err)
|
||
// }
|
||
// if apiSptResp.ErrType == "102" {
|
||
// return nil, fmt.Errorf("错误信息: %w,状态码: %s", apiSptResp.Message, apiSptResp.ErrType)
|
||
// }
|
||
// if apiSptResp.Data.ItemResponse.Total > 0 && len(apiSptResp.Data.ItemResponse.List) > 0 {
|
||
// // 确定其实索引
|
||
// var startIndex int
|
||
// if size >= apiSptResp.Data.ItemResponse.Total {
|
||
// startIndex = apiSptResp.Data.ItemResponse.Total - 1
|
||
// } else {
|
||
// startIndex = size - 1
|
||
// }
|
||
// for attempt := 0; attempt < 3; attempt++ {
|
||
// currentIndex := startIndex - attempt
|
||
// // 检查索引是否有效
|
||
// if currentIndex < 0 || currentIndex >= len(apiSptResp.Data.ItemResponse.List) {
|
||
// log.Printf("[DEBUG] 索引 %d 超出范围,跳过", currentIndex)
|
||
// continue
|
||
// }
|
||
// randomNum := rand.Intn(currentIndex + 1)
|
||
// item := apiSptResp.Data.ItemResponse.List[randomNum]
|
||
// // 检查图片URL是否存在
|
||
// if item.ImgBigUrl == "" {
|
||
// log.Printf("[DEBUG] 索引 %d 的图片URL为空,跳过", randomNum)
|
||
// continue
|
||
// }
|
||
// // 响应信息
|
||
// bookInfo.BookPicS = item.ImgUrl
|
||
// bookInfo.ISBN = item.Isbn
|
||
// if bookInfo.BookName == "" {
|
||
// bookInfo.BookName = item.Title
|
||
// if isReturnMsg == 0 {
|
||
// // 安全地获取TplRecords中的值
|
||
// if len(item.TplRecords) > 0 {
|
||
// bookInfo.Author = item.TplRecords[0].Value
|
||
// }
|
||
// if len(item.TplRecords) > 1 {
|
||
// bookInfo.Publisher = item.TplRecords[1].Value
|
||
// }
|
||
// if len(item.TplRecords) > 2 {
|
||
// bookInfo.PublicationTime = validateDateFormat(item.TplRecords[2].Value)
|
||
// }
|
||
// if len(item.TplRecords) > 3 {
|
||
// bookInfo.BindingLayout = item.TplRecords[3].Value
|
||
// }
|
||
// }
|
||
// }
|
||
// return bookInfo, nil
|
||
// }
|
||
// //}
|
||
// }
|
||
// return nil, fmt.Errorf("查询失败,没有数据!")
|
||
//}
|
||
//
|
||
//// 验证日期格式
|
||
//func validateDateFormat(dateStr string) int64 {
|
||
// // 去除前后空格
|
||
// dateStr = strings.TrimSpace(dateStr)
|
||
//
|
||
// // 替换各种分隔符为统一的分隔符"-"
|
||
// dateStr = regexp.MustCompile(`[/_\\.,\s]+`).ReplaceAllString(dateStr, "-")
|
||
//
|
||
// // 处理纯年份格式 (4位数字)
|
||
// if regexp.MustCompile(`^\d{4}$`).MatchString(dateStr) {
|
||
// dateStr += "-01-01"
|
||
// }
|
||
//
|
||
// // 处理年月格式 (4位数字-1或2位数字)
|
||
// if matches := regexp.MustCompile(`^(\d{4})-(\d{1,2})$`).FindStringSubmatch(dateStr); len(matches) == 3 {
|
||
// year := matches[1]
|
||
// month := matches[2]
|
||
// if len(month) == 1 {
|
||
// month = "0" + month
|
||
// }
|
||
// if monthNum, _ := strconv.Atoi(month); monthNum >= 1 && monthNum <= 12 {
|
||
// dateStr = year + "-" + month + "-01"
|
||
// } else {
|
||
// return 0
|
||
// }
|
||
// }
|
||
//
|
||
// // 处理年月日格式 (4位数字-1或2位数字-1或2位数字)
|
||
// if matches := regexp.MustCompile(`^(\d{4})-(\d{1,2})-(\d{1,2})`).FindStringSubmatch(dateStr); len(matches) >= 4 {
|
||
// year := matches[1]
|
||
// month := matches[2]
|
||
// day := matches[3]
|
||
//
|
||
// // 标准化月份和日期为两位数
|
||
// if len(month) == 1 {
|
||
// month = "0" + month
|
||
// }
|
||
// if len(day) == 1 {
|
||
// day = "0" + day
|
||
// }
|
||
//
|
||
// dateStr = year + "-" + month + "-" + day
|
||
// }
|
||
//
|
||
// // 加载上海时区
|
||
// loc, err := time.LoadLocation("Asia/Shanghai")
|
||
// if err != nil {
|
||
// // 如果加载时区失败,使用UTC+8作为后备方案
|
||
// loc = time.FixedZone("CST", 8*60*60)
|
||
// }
|
||
//
|
||
// // 尝试解析为标准日期格式,并指定上海时区
|
||
// parsedTime, err := time.ParseInLocation("2006-01-02", dateStr, loc)
|
||
// if err != nil {
|
||
// return 0
|
||
// }
|
||
//
|
||
// // 返回秒级时间戳(UTC时间,但解析时已经考虑了时区偏移)
|
||
// return parsedTime.Unix()
|
||
//}
|
||
//
|
||
//// 代理类型常量
|
||
//const (
|
||
// CalfElephantProxyType = "CALF_ELEPHANT_PROXY"
|
||
// TailProxyType = "TAIL_PROXY"
|
||
//)
|
||
//
|
||
//// 代理服务器列表
|
||
//var (
|
||
// servers = []string{
|
||
// "http-dynamic.xiaoxiangdaili.com",
|
||
// "http-dynamic-S02.xiaoxiangdaili.com",
|
||
// "http-dynamic-S03.xiaoxiangdaili.com",
|
||
// "http-dynamic-S04.xiaoxiangdaili.com",
|
||
// }
|
||
// randMutex sync.Mutex
|
||
// globalRand *rand.Rand
|
||
//
|
||
// // 代理健康状态管理
|
||
// proxyHealthMaps = make(map[string]*ProxyHealth)
|
||
// proxyHealthMutex sync.RWMutex
|
||
//)
|
||
//
|
||
//// ProxyManager 代理管理器结构体
|
||
//type ProxyManager struct {
|
||
// servers []string `json:"servers"` // 代理服务器列表
|
||
// username string `json:"username"` // 代理账号
|
||
// password string `json:"password"` // 代理密码
|
||
// tailCardSecret string `json:"tail_card_secret"` // 尾巴代理卡密
|
||
// proxyType string `json:"proxy_type"` // 代理类型 CALF_ELEPHANT_PROXY/TAIL_PROXY
|
||
//}
|
||
//
|
||
//// 代理健康状态
|
||
//type ProxyHealth struct {
|
||
// SuccessCount int // 成功次数
|
||
// FailCount int // 失败次数
|
||
// LastCheck time.Time // 最后检查时间
|
||
// ResponseTime time.Duration // 响应时间
|
||
// IsHealthy bool // 是否健康
|
||
//}
|
||
//
|
||
//func init() {
|
||
// // 创建全局的随机数生成器
|
||
// globalRand = rand.New(rand.NewSource(time.Now().UnixNano()))
|
||
//}
|
||
//
|
||
//// 获取代理URL
|
||
//func proxyTypeManager(proxyType, username, password, machineCode string) (string, error) {
|
||
// switch proxyType {
|
||
// case CalfElephantProxyType:
|
||
// return buildCalfElephantProxyURL(username, password)
|
||
// case TailProxyType:
|
||
// return buildTailProxyURL(machineCode)
|
||
// default:
|
||
// return "", fmt.Errorf("不支持的代理类型: %s", proxyType)
|
||
// }
|
||
//}
|
||
//
|
||
//// 构建小象代理URL
|
||
//func buildCalfElephantProxyURL(username, password string) (string, error) {
|
||
// server := randomServer()
|
||
// proxyURL := fmt.Sprintf("http://%s:%s@%s:%d",
|
||
// url.QueryEscape(username),
|
||
// url.QueryEscape(password),
|
||
// server,
|
||
// 10030)
|
||
//
|
||
// // 检测代理可用性
|
||
// if err := checkProxyHealth(proxyURL); err != nil {
|
||
// log.Printf("[WARN] 代理 %s 检测失败: %v", server, err)
|
||
// // 尝试下一个代理服务器
|
||
// return tryNextCalfElephantProxy(username, password, server)
|
||
// }
|
||
//
|
||
// log.Printf("[INFO] 使用小象代理: %s", server)
|
||
// return proxyURL, nil
|
||
//}
|
||
//
|
||
//// 尝试下一个小象代理服务器
|
||
//func tryNextCalfElephantProxy(username, password, failedServer string) (string, error) {
|
||
// // 创建服务器副本并排除失败的服务器
|
||
// availableServers := make([]string, 0)
|
||
// for _, server := range servers {
|
||
// if server != failedServer {
|
||
// availableServers = append(availableServers, server)
|
||
// }
|
||
// }
|
||
//
|
||
// if len(availableServers) == 0 {
|
||
// return "", fmt.Errorf("所有小象代理服务器都不可用")
|
||
// }
|
||
//
|
||
// // 随机尝试可用服务器
|
||
// for _, server := range shuffleServers(availableServers) {
|
||
// proxyURL := fmt.Sprintf("http://%s:%s@%s:%d",
|
||
// url.QueryEscape(username),
|
||
// url.QueryEscape(password),
|
||
// server,
|
||
// 10030)
|
||
//
|
||
// if err := checkProxyHealth(proxyURL); err == nil {
|
||
// log.Printf("[INFO] 切换到可用代理: %s", server)
|
||
// return proxyURL, nil
|
||
// }
|
||
// log.Printf("[WARN] 代理 %s 检测失败", server)
|
||
// }
|
||
//
|
||
// return "", fmt.Errorf("所有可用的小象代理服务器都检测失败")
|
||
//}
|
||
//
|
||
//// 构建内置代理URL
|
||
//func buildTailProxyURL(machineCode string) (string, error) {
|
||
// proxies, err := getProxies(machineCode)
|
||
// if err != nil {
|
||
// return "", err
|
||
// }
|
||
// if len(proxies) == 0 {
|
||
// return "", fmt.Errorf("未获取到有效代理")
|
||
// }
|
||
//
|
||
// // 过滤并选择健康的代理
|
||
// healthyProxies := filterHealthyProxies(proxies)
|
||
// if len(healthyProxies) > 0 {
|
||
// proxyURL := "http://" + randomElement(healthyProxies)
|
||
// log.Printf("[INFO] 使用健康尾巴代理: %s", proxyURL)
|
||
// return proxyURL, nil
|
||
// }
|
||
//
|
||
// // 如果没有健康代理,检测所有代理
|
||
// log.Printf("[INFO] 未找到健康代理,开始检测代理可用性...")
|
||
// return findWorkingTailProxy(proxies)
|
||
//}
|
||
//
|
||
//// 获取代理服务器列表
|
||
//func getProxies(machineCode string) ([]string, error) {
|
||
// log.Printf("[INFO] 开始获取代理列表: %s", machineCode)
|
||
// // 生成签名
|
||
// sign := fmt.Sprintf("%x", md5.Sum([]byte(fmt.Sprintf("9999%s9999", machineCode))))
|
||
//
|
||
// GetProxiesUrl := fmt.Sprintf("http://114.66.2.223:7842/api/proxies/get_proxy?machine_code=%s&sign=%s&agent_id=9999",
|
||
// machineCode, sign)
|
||
//
|
||
// req := gorequest.New().Get(GetProxiesUrl).Timeout(20 * time.Second)
|
||
// _, body, errs := req.End()
|
||
// if len(errs) > 0 {
|
||
// return nil, fmt.Errorf("获取代理失败: %v", errs)
|
||
// }
|
||
//
|
||
// // 检查是否为JSON错误响应
|
||
// if strings.HasPrefix(strings.TrimSpace(body), "{") && strings.HasSuffix(strings.TrimSpace(body), "}") {
|
||
// // 尝试解析为JSON错误响应
|
||
// var errorResp struct {
|
||
// Code int `json:"code"`
|
||
// Message string `json:"message"`
|
||
// }
|
||
// if err := json.Unmarshal([]byte(body), &errorResp); err == nil {
|
||
// return nil, fmt.Errorf("获取代理失败: %s (错误码: %d)", errorResp.Message, errorResp.Code)
|
||
// }
|
||
// }
|
||
//
|
||
// // 解析响应
|
||
// lines := strings.Split(strings.TrimSpace(body), "\n")
|
||
// var proxies []string
|
||
// for _, line := range lines {
|
||
// line = strings.TrimSpace(line)
|
||
// if line != "" && !strings.HasPrefix(line, "{") {
|
||
// proxies = append(proxies, line)
|
||
// }
|
||
// }
|
||
// if len(proxies) == 0 {
|
||
// return nil, fmt.Errorf("未获取到有效代理")
|
||
// }
|
||
//
|
||
// log.Printf("[INFO] 获取到 %d 个代理", len(proxies))
|
||
// return proxies, nil
|
||
//}
|
||
//
|
||
//// 过滤健康代理
|
||
//func filterHealthyProxies(proxies []string) []string {
|
||
// proxyHealthMutex.RLock()
|
||
// defer proxyHealthMutex.RUnlock()
|
||
//
|
||
// var healthy []string
|
||
// for _, proxy := range proxies {
|
||
// if health, exists := proxyHealthMaps[proxy]; exists && health.IsHealthy {
|
||
// // 检查是否在最近检查过(5分钟内)
|
||
// if time.Since(health.LastCheck) < 5*time.Minute {
|
||
// healthy = append(healthy, proxy)
|
||
// }
|
||
// }
|
||
// }
|
||
// return healthy
|
||
//}
|
||
//
|
||
//// 查找可用的尾巴代理
|
||
//func findWorkingTailProxy(proxies []string) (string, error) {
|
||
// // 打乱代理顺序
|
||
// shuffledProxies := shuffleServers(proxies)
|
||
//
|
||
// // 并发检测代理
|
||
// type proxyResult struct {
|
||
// proxy string
|
||
// err error
|
||
// }
|
||
//
|
||
// ch := make(chan proxyResult, len(shuffledProxies))
|
||
// var wg sync.WaitGroup
|
||
//
|
||
// // 限制并发数
|
||
// sem := make(chan struct{}, 5)
|
||
//
|
||
// for _, proxy := range shuffledProxies {
|
||
// wg.Add(1)
|
||
// go func(p string) {
|
||
// defer wg.Done()
|
||
// sem <- struct{}{}
|
||
// defer func() { <-sem }()
|
||
//
|
||
// proxyURL := "http://" + p
|
||
// err := checkProxyHealth(proxyURL)
|
||
// ch <- proxyResult{proxy: p, err: err}
|
||
// }(proxy)
|
||
// }
|
||
//
|
||
// wg.Wait()
|
||
// close(ch)
|
||
//
|
||
// // 收集结果
|
||
// var workingProxies []string
|
||
// for result := range ch {
|
||
// if result.err == nil {
|
||
// workingProxies = append(workingProxies, result.proxy)
|
||
// // 更新健康状态
|
||
// updateProxyHealth(result.proxy, true, 0)
|
||
// } else {
|
||
// updateProxyHealth(result.proxy, false, 0)
|
||
// }
|
||
// }
|
||
//
|
||
// if len(workingProxies) > 0 {
|
||
// selected := randomElement(workingProxies)
|
||
// log.Printf("[INFO] 找到可用代理: %s (共 %d 个可用)", selected, len(workingProxies))
|
||
// return "http://" + selected, nil
|
||
// }
|
||
//
|
||
// return "", fmt.Errorf("所有尾巴代理都不可用")
|
||
//}
|
||
//
|
||
//// 检测代理健康状态
|
||
//func checkProxyHealth(proxyURL string) error {
|
||
// start := time.Now()
|
||
//
|
||
// req := gorequest.New().Proxy(proxyURL).Timeout(10 * time.Second)
|
||
// resp, _, errs := req.Get("https://shop.kongfz.com/").End()
|
||
//
|
||
// responseTime := time.Since(start)
|
||
//
|
||
// if len(errs) > 0 {
|
||
// updateProxyHealth(proxyURL, false, responseTime)
|
||
// return fmt.Errorf("代理连接失败: %v", errs)
|
||
// }
|
||
//
|
||
// if resp.StatusCode != 200 {
|
||
// updateProxyHealth(proxyURL, false, responseTime)
|
||
// return fmt.Errorf("代理响应状态码错误: %d", resp.StatusCode)
|
||
// }
|
||
//
|
||
// updateProxyHealth(proxyURL, true, responseTime)
|
||
// log.Printf("[DEBUG] 代理 %s 检测成功, 响应时间: %v", getProxyHost(proxyURL), responseTime)
|
||
// return nil
|
||
//}
|
||
//
|
||
//// 更新代理健康状态
|
||
//func updateProxyHealth(proxyURL string, success bool, responseTime time.Duration) {
|
||
// proxyHealthMutex.Lock()
|
||
// defer proxyHealthMutex.Unlock()
|
||
//
|
||
// host := getProxyHost(proxyURL)
|
||
// if _, exists := proxyHealthMaps[host]; !exists {
|
||
// proxyHealthMaps[host] = &ProxyHealth{}
|
||
// }
|
||
//
|
||
// health := proxyHealthMaps[host]
|
||
// health.LastCheck = time.Now()
|
||
//
|
||
// if success {
|
||
// health.SuccessCount++
|
||
// health.FailCount = 0
|
||
// health.ResponseTime = responseTime
|
||
// health.IsHealthy = true
|
||
// } else {
|
||
// health.FailCount++
|
||
// health.SuccessCount = 0
|
||
// // 连续失败3次标记为不健康
|
||
// if health.FailCount >= 3 {
|
||
// health.IsHealthy = false
|
||
// }
|
||
// }
|
||
//}
|
||
//
|
||
//// 获取代理主机名
|
||
//func getProxyHost(proxyURL string) string {
|
||
// if strings.HasPrefix(proxyURL, "http://") {
|
||
// proxyURL = proxyURL[7:]
|
||
// }
|
||
// // 去除认证信息
|
||
// if atIndex := strings.Index(proxyURL, "@"); atIndex != -1 {
|
||
// proxyURL = proxyURL[atIndex+1:]
|
||
// }
|
||
// // 去除端口
|
||
// if colonIndex := strings.Index(proxyURL, ":"); colonIndex != -1 {
|
||
// proxyURL = proxyURL[:colonIndex]
|
||
// }
|
||
// return proxyURL
|
||
//}
|
||
//
|
||
//// 随机代理服务器
|
||
//func randomServer() string {
|
||
// return randomElement(servers)
|
||
//}
|
||
//
|
||
//// 线程安全的随机元素选择
|
||
//func randomElement(slice []string) string {
|
||
// randMutex.Lock()
|
||
// defer randMutex.Unlock()
|
||
// return slice[globalRand.Intn(len(slice))]
|
||
//}
|
||
//
|
||
//// 打乱服务器顺序
|
||
//func shuffleServers(servers []string) []string {
|
||
// randMutex.Lock()
|
||
// defer randMutex.Unlock()
|
||
//
|
||
// shuffled := make([]string, len(servers))
|
||
// copy(shuffled, servers)
|
||
// globalRand.Shuffle(len(shuffled), func(i, j int) {
|
||
// shuffled[i], shuffled[j] = shuffled[j], shuffled[i]
|
||
// })
|
||
// return shuffled
|
||
//}
|