package main /* #include */ import "C" import ( "bytes" "crypto/md5" "encoding/json" "fmt" "io" "log" "math/rand" "mime/multipart" "net/http" "net/url" "os" "path" "path/filepath" "regexp" "sort" "strconv" "strings" "time" "unsafe" "github.com/PuerkitoBio/goquery" _ "github.com/go-sql-driver/mysql" "github.com/parnurzeal/gorequest" ) // Config 结构体定义应用程序配置 type Config struct { App struct { MaxRetryTimes int `ini:"app.max_retry_times" json:"max_retry_times" default:"3"` // 最大重试次数 RateLimitDelay time.Duration `ini:"app.rate_limit_delay" json:"rate_limit_delay" default:"500ms"` // 请求延迟 Size int `ini:"app.size" json:"size" default:"5"` // 默认大小 DefaultUserAgent string `ini:"app.default_user_agent" json:"default_user_agent" default:"Mozilla/5.0"` // 默认 User-Agent } `ini:"app" json:"app"` API struct { LoginURL string `ini:"api.login_url" json:"login_url" default:"https://login.kongfz.com/Pc/Login/account"` // 登录 URL BookSearchURL string `ini:"api.book_search_url" json:"book_search_url" default:"https://search.kongfz.com/pc-gw/search-web/client/pc/bookLib/keyword/list"` // 图书搜索 URL ProductSearchURL string `ini:"api.product_search_url" json:"product_search_url" default:"https://search.kongfz.com/pc-gw/search-web/client/pc/product/keyword/list"` // 商品搜索 URL } `ini:"api" json:"api"` Proxy struct { Servers string `ini:"proxy.servers" json:"servers" default:"http-dynamic.xiaoxiangdaili.com,http-dynamic-S02.xiaoxiangdaili.com,http-dynamic-S03.xiaoxiangdaili.com,http-dynamic-S04.xiaoxiangdaili.com"` // 代理服务器列表 Username string `ini:"proxy.username" json:"username" default:"1297757178467602432"` // 代理用户名 Password string `ini:"proxy.password" json:"password" default:"QgQBvP7f"` // 代理密码 TailMachineCode string `ini:"proxy.tail_machine_code" json:"tail_machine_code" default:"b7bf22a237ec692f13fcc2c43ee63252"` // 尾机编码 TailCardKey string `ini:"proxy.tail_card_key" json:"tail_card_key" default:"DL_20_YK_1920acb2129844c2aabade3896560a9b"` // 尾卡密钥 ProxyFilePath string `ini:"proxy.proxy_file_path" json:"proxy_file_path" default:"dll/proxyConfig.dll"` // 代理配置文件路径 } `ini:"proxy" json:"proxy"` } // BookInfo 图书详情结构体 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"` // 出版时间(时间戳) PubDate string `json:"pub_date"` // 出版时间 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"` // 内容简介 AuthorIntroduction string `json:"author_introduction"` // 作者简介 Catalogue string `json:"catalogue"` // 目录 Mid int64 `json:"mid"` // 商家id ItemId int64 `json:"item_id"` // 商品id ShopId int64 `json:"shop_id"` // 店铺id DetailUrl string `json:"detail_url"` // 商品详情url } // APIResponse 通用API响应结构体 type APIResponse struct { Success bool `json:"success"` // 请求是否成功 Message string `json:"message,omitempty"` // 错误信息(成功时可选) Data interface{} `json:"data,omitempty"` // 响应数据(失败时可选) } // UserInfo 孔网用户信息结构体 type UserInfo struct { UserID int64 `json:"userId"` // 用户ID Nickname string `json:"nickname"` // 用户昵称 Mobile string `json:"mobile"` // 手机号 } // 全局配置变量 var ( cf Config // 存储应用程序配置 ) // ProductInfo 商品信息结构体 type ProductInfo struct { ItemID string `json:"itemId"` // 商品ID BookName string `json:"bookName"` // 书名 Price string `json:"price"` // 价格 ShippingFee string `json:"shippingFee"` // 运费 } // BookDetailResponse 图书详情响应结构体 type BookDetailResponse struct { Status bool `json:"status"` // 状态 Result BookList `json:"result"` // 结果数据 ErrMessage string `json:"errMessage"` // 错误信息 ErrCode int `json:"errCode"` // 错误码 } // BookList 图书列表结构体 type BookList struct { Current int `json:"current"` // 当前页码 Data []BookInformation `json:"data"` // 图书数据列表 Total int `json:"total"` // 总数 } // BookInformation 图书信息结构体 type BookInformation struct { Author string `json:"author"` // 作者 BookName string `json:"bookName"` // 书名 ContentIntroduction string `json:"contentIntroduction"` // 内容简介 ImgUrl string `json:"imgUrl"` // 图片URL Isbn string `json:"isbn"` // ISBN ItemUrls ItemUrls `json:"itemUrls"` // 商品URL Mid int `json:"mid"` // 商家ID NewMinPrice string `json:"newMinPrice"` // 新书最低价 OldMinPrice string `json:"oldMinPrice"` // 旧书最低价 Press string `json:"press"` // 出版社 Price string `json:"price"` // 价格 PubDate string `json:"pubDate"` // 出版日期 RiseTag string `json:"riseTag"` // 上涨标签 AuthorArr []AuthorInfo `json:"authorArr"` // 作者数组 PressUrl string `json:"pressUrl"` // 出版社URL } // AuthorInfo 作者信息结构体 type AuthorInfo struct { Name string `json:"name"` // 作者姓名 OriName string `json:"oriName"` // 原始姓名 Nationality string `json:"nationality"` // 国籍 Role string `json:"role"` // 角色 Url string `json:"url"` // 作者页面URL } // ItemUrls 商品链接结构体 type ItemUrls struct { AppUrl string `json:"appUrl"` // App链接 MUrl string `json:"mUrl"` // 移动端链接 MiniUrl string `json:"miniUrl"` // 小程序链接 PcUrl string `json:"pcUrl"` // PC端链接 } // ParamsInfo 店铺快递费参数结构体 type ParamsInfo struct { Params []Param `json:"params"` // 参数列表 Area string `json:"area"` // 地区编码 } // Param 单个参数结构体 type Param struct { UserId string `json:"userId"` // 用户ID ItemId string `json:"itemId"` // 商品ID } // DataItem 快递费用响应数据项 type DataItem struct { Fee []FeeInfo `json:"fee"` // 费用列表 IsSeller bool `json:"isSeller"` // 是否是卖家 ItemID string `json:"itemId"` // 商品ID UserID string `json:"userId"` // 用户ID } // FeeInfo 费用信息结构体 type FeeInfo struct { ShippingID string `json:"shippingId"` // 配送方式ID ShippingName string `json:"shippingName"` // 配送方式名称 TotalFee string `json:"totalFee"` // 总费用 ShippingText string `json:"shippingText"` // 配送说明 FilterTotalFee string `json:"filterTotalFee"` // 过滤后的总费用 } // ResponseStruct 快递费响应结构体 type ResponseStruct struct { Status bool `json:"status"` // 状态 Data []DataItem `json:"data"` // 数据 Message string `json:"message"` // 消息 ErrType string `json:"errType"` // 错误类型 } // ShippingTemplateResponse 运费模板响应结构体 type ShippingTemplateResponse struct { Status bool `json:"status"` // 状态 Data []ShippingTemplateInfo `json:"data"` // 运费模板信息 Message string `json:"message"` // 消息 ErrType string `json:"errType"` // 错误类型 } // ShippingTemplateInfo 运费模板信息 type ShippingTemplateInfo struct { MouldId string `json:"mouldId"` MouldName string `json:"mouldName"` } /* * 获取店铺里商品的快递费(定位到河南) * param params[ParamsInfo] 店铺快递费参数结构体 * param proxy[string] 代理服务器IP * return 快递费用响应数据项数组,错误信息 * Error 没有商品信息 * Error 参数序列化失败 * Error 请求失败 * Error HTTP错误 * Error 解析JSON失败 */ func getGoodsListShippingFee(params ParamsInfo, proxy string) ([]DataItem, error) { // 检查参数是否为空 if params.Params == nil { return nil, fmt.Errorf("没有商品信息!") } // 序列化参数为JSON paramsJSON, err := json.Marshal(params) if err != nil { return nil, fmt.Errorf("参数序列化失败: %v", err) } // URL 编码参数 encodedParams := url.QueryEscape(string(paramsJSON)) // 构建请求URL url := fmt.Sprintf("https://shop.kongfz.com/book/shopsearch/getShippingFee?params=%s", encodedParams) // 创建请求对象 request := gorequest.New() // 设置代理 if proxy != "" { request.Proxy(proxy) } // 发送GET请求 resp, body, errs := request.Get(url). 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"). End() // 错误处理 if len(errs) > 0 { return nil, fmt.Errorf("请求失败: %v", errs) } // 检查HTTP状态码 if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("HTTP错误: %s", resp.Status) } // 解析JSON响应 responseStruct := ResponseStruct{} err = json.Unmarshal([]byte(body), &responseStruct) if err != nil { return nil, fmt.Errorf("解析JSON失败: %v", err) } // 提取数据项 var dataItem []DataItem for i := range responseStruct.Data { dataItem = append(dataItem, responseStruct.Data[i]) } return dataItem, nil } /* * 孔网登录 * param username[string] 孔网用户名 * param password[string] 孔网密码 * return token,错误信息 * Error 登录请求失败 * Error 登录失败(HTTP状态码: %d) * Error 登录成功但未获取到Cookie * Error 登录失败: 未找到 PHPSESSID * Error 账号或密码错误 * Error 登录失败 * Error 登录失败,未知错误! */ func outKfzLogin(username, password string) (string, error) { // 检查用户名和密码是否为空 if username == "" || password == "" { return "", fmt.Errorf("请输入用户名和密码!") } // 准备POST请求的表单数据 formData := map[string]string{ "loginName": username, "loginPass": password, "returnUrl": "http://user.kongfz.com/", } // 孔网登录URL loginUrl := "https://login.kongfz.com/Pc/Login/account" // 发送登录请求 resp, body, errs := gorequest.New(). Post(loginUrl). Set("Content-Type", "application/x-www-form-urlencoded"). Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"). Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"). Send(formData). Timeout(15 * time.Second). End() // 请求错误处理 if len(errs) > 0 { return "", fmt.Errorf("登录请求失败: %v", errs) } // 检查HTTP状态码 if resp.StatusCode != http.StatusOK { return "", fmt.Errorf("登录失败(HTTP状态码: %d)", resp.StatusCode) } // 提取Cookie cookie := resp.Header.Get("Set-Cookie") // 检查是否登录成功(通过响应内容判断) if strings.Contains(body, "window.location.href='https://login.kongfz.cn/Pc/Session/rsync") { if cookie == "" { return "", fmt.Errorf("登录成功但未获取到Cookie") } // 登录成功 if strings.Contains(cookie, "PHPSESSID=") { token := strings.Split(strings.Split(cookie, "PHPSESSID=")[1], ";")[0] return token, nil } return "", fmt.Errorf("登录失败: 未找到PHPSESSID") } // 错误信息 var res struct { Status bool `json:"status"` ErrCode int `json:"errCode"` ErrInfo string `json:"errInfo"` } // 解析json if err := json.Unmarshal([]byte(body), &res); err == nil { if res.ErrCode == 1001 || res.ErrCode == 1005 { return "", fmt.Errorf("账号或密码错误!") } if res.ErrInfo != "" { return "", fmt.Errorf("登录失败: %s", res.ErrInfo) } } return "", fmt.Errorf("登录失败,未知错误!") } /* * 获取孔网用户信息 * param token[string] 孔网token * return 孔网用户信息结构体,错误信息 * Error 查询请求失败 * Error HTTP错误 * Error 解析JSON失败 * Error 获取用户失败 */ func outKfzGetUserInfo(token string) (*UserInfo, error) { // 用户信息URL url := "https://user.kongfz.com/User/Index/getUserInfo/" // 发送请求 resp, body, errs := gorequest.New(). 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"). Timeout(15 * time.Second). End() if len(errs) > 0 { return nil, fmt.Errorf("查询用户信息请求失败: %v", errs) } //检查HTTP状态码 if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("HTTP错误: %s", resp.Status) } // 响应数据 var userInfo struct { Status bool `json:"status"` Data struct { UserID int64 `json:"userId"` Nickname string `json:"nickname"` Mobile string `json:"mobile"` } } // 解析json if err := json.Unmarshal([]byte(body), &userInfo); err != nil { return nil, fmt.Errorf("解析JSON失败: %w", err) } // 创建用户信息对象 user := &UserInfo{} if !userInfo.Status { return nil, fmt.Errorf("获取用户失败!") } user.UserID = userInfo.Data.UserID user.Nickname = userInfo.Data.Nickname user.Mobile = userInfo.Data.Mobile return user, nil } // 获取运费模板信息 func outGetKfzShippingTemplate(token string) ([]ShippingTemplateInfo, error) { if token == "" { return nil, fmt.Errorf("请先登录获取Token") } kfzUrl := "https://shop.kongfz.com/seller/delivery/index" // 发送请求 resp, body, errs := gorequest.New(). Get(kfzUrl). 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"). Timeout(15 * time.Second). End() if len(errs) > 0 { return nil, fmt.Errorf("查询请求失败: %v", errs) } //检查HTTP状态码 if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("HTTP错误: %s", resp.Status) } var shippingTemplateResponse ShippingTemplateResponse // 解析json if err := json.Unmarshal([]byte(body), &shippingTemplateResponse); err != nil { return nil, fmt.Errorf("解析运费模板响应结构体失败: %w", err) } if !shippingTemplateResponse.Status { return nil, fmt.Errorf(shippingTemplateResponse.Message) } return shippingTemplateResponse.Data, nil } /* * 获取商品模版-已登的店铺 * param token[string] 孔网token * param proxy[string] 代理服务器IP * param itemId[string] 商品ID * return 商品模板信息结构体,错误信息 * Error 请先登录获取Token * Error 代理连接失败 * Error 查询请求失败 * Error HTTP错误 * Error 解析JSON失败 * Error API返回错误 */ func outGetGoodsTplMsg(token, proxy, itemId string) (map[string]interface{}, error) { // 判断登录token if token == "" { return nil, fmt.Errorf("请先登录获取Token") } // 商品模板URL url := fmt.Sprintf("https://seller.kongfz.com/pc/itemInfo/getTplFields?itemId=%s&isClone=1&v=%d", itemId, time.Now().Unix()) // 创建请求 request := gorequest.New() // 设置代理(如果有提供代理URL) if proxy != "" { request.Proxy(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(15 * time.Second). End() // 错误处理 if errs != nil { // 检查是否是代理相关错误 var isProxyError bool var errorDetails []string for _, e := range errs { 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", errs) } // 检查HTTP状态码 if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("HTTP错误: %s", resp.Status) } // 解析json var data map[string]interface{} if err := json.Unmarshal([]byte(body), &data); err != nil { return nil, fmt.Errorf("解析JSON失败: %w", err) } // 检查status状态 if val, ok := data["status"].(float64); ok && val == 1 { return data, nil } return nil, fmt.Errorf("API返回错误: %+v", data) } type Kfz struct { Token string `json:"token"` // 认证token Proxy string `json:"proxy"` // 代理配置 ItemSn string `json:"itemSn"` // 商品货号 MouldId string `json:"mouldId"` // 运费模板ID(可选) PriceMin string `json:"priceMin"` // 最低价格 PriceMax string `json:"priceMax"` // 最高价格 StartCreateTime string `json:"startCreateTime"` // 开始创建时间 EndCreateTime string `json:"endCreateTime"` // 结束创建时间 RequestType string `json:"requestType"` // 请求类型 IsItemSnEqual int `json:"isItemSnEqual"` // 货号是否相等(0/1) Page int `json:"page"` // 页码 Size int `json:"size"` // 每页大小 } /* * 获取商品列表-已登的店铺--核价软件用 * param token[string] 孔网token * param proxy[string] 代理服务器IP * param itemSn[string] 货号 * param priceMin[string] 价格区间-低 * param priceMax[string] 价格区间-高 * param startCreateTime[string] 开始时间 * param endCreateTime[string] 结束时间 * param requestType[string] 请求类型 * param isItemSnEqual[int] 商品ID * param page[int] 页数 * param size[int] 大小 * return 商品列表响应信息结构体,错误信息 * Error 请先登录获取Token * Error 代理连接失败 * Error 查询请求失败 * Error HTTP错误 * Error 解析JSON失败 * Error API返回错误 */ func outGetGoodsListMsgFromSelfShop(token string, proxy string, itemSn string, mouldId, priceMin string, priceMax string, startCreateTime string, endCreateTime string, requestType string, isItemSnEqual int, page int, size int) (map[string]interface{}, error) { // 判断登录token if token == "" { return nil, fmt.Errorf("请先登录获取Token") } // 已登店铺的商品信息URL outUrl := "https://seller.kongfz.com/pc-gw/book-manage-service/client/pc/goods/unSold/list" // 请求参数 formData := struct { ItemSn string `json:"itemSn"` ShippingMould string `json:"shippingMould"` PriceMin string `json:"priceMin"` PriceMax string `json:"priceMax"` StartCreateTime string `json:"startCreateTime"` EndCreateTime string `json:"endCreateTime"` RequestType string `json:"requestType,omitempty"` IsItemSnEqual int `json:"isItemSnEqual,omitempty"` Page int `json:"page,omitempty"` Size int `json:"size,omitempty"` }{ ItemSn: itemSn, ShippingMould: mouldId, PriceMin: priceMin, PriceMax: priceMax, StartCreateTime: startCreateTime, EndCreateTime: endCreateTime, RequestType: requestType, IsItemSnEqual: isItemSnEqual, Page: page, Size: size, } // 创建请求 request := gorequest.New() // 设置代理(如果有提供代理URL) if proxy != "" { request.Proxy(proxy) } // 发送POST请求 resp, body, errs := request.Post(outUrl). 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, */*"). Send(formData). Timeout(15 * time.Second). End() if errs != nil { // 检查是否是代理相关错误 var isProxyError bool var errorDetails []string for _, e := range errs { 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 } } if isProxyError { // 处理代理失败 return nil, fmt.Errorf("代理连接失败") } return nil, fmt.Errorf("查询请求失败: %v", errs) } //检查HTTP状态码 if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("HTTP错误: %s", resp.Status) } // 解析json var data map[string]interface{} if err := json.Unmarshal([]byte(body), &data); err != nil { return nil, fmt.Errorf("解析JSON失败: %w", err) } // 检查API返回状态 if status, ok := data["status"].(bool); ok && status { // 获取result字段 if result, ok := data["result"].(map[string]interface{}); ok { return result, nil } // 如果result字段不存在或类型不对,返回错误 return nil, fmt.Errorf("孔网商品获取失败: 缺少商品信息") } // 处理API错误情况 errMsg, _ := data["errMessage"].(string) return nil, fmt.Errorf("孔网商品获取错误: %s", errMsg) } // 获取模板字段 func outGetTplFields(token, proxy, itemId string) (map[string]interface{}, error) { // 判断登录token if token == "" { return nil, fmt.Errorf("请先登录获取Token") } outUrl := fmt.Sprintf("https://seller.kongfz.com/pc/itemInfo/getTplFields?itemId=%s&isClone=1&v=%d", itemId, time.Now().Unix()) // 创建请求 request := gorequest.New() // 设置代理(如果有提供代理URL) if proxy != "" { request.Proxy(proxy) } // 发送POST请求 resp, body, errs := request.Get(outUrl). 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, */*"). Timeout(15 * time.Second). End() if errs != nil { // 检查是否是代理相关错误 var isProxyError bool var errorDetails []string for _, e := range errs { 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 } } if isProxyError { // 处理代理失败 return nil, fmt.Errorf("代理连接失败") } return nil, fmt.Errorf("查询请求失败: %v", errs) } //检查HTTP状态码 if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("HTTP错误: %s", resp.Status) } // 解析json var data map[string]interface{} if err := json.Unmarshal([]byte(body), &data); err != nil { return nil, fmt.Errorf("解析JSON失败: %w", err) } // 检查API返回状态 if status, ok := data["status"].(float64); ok && status == 1 { // 获取result字段 if result, ok := data["data"].(map[string]interface{}); ok { return result, nil } // 如果result字段不存在或类型不对,返回错误 return nil, fmt.Errorf("孔网获取模板字段失败: 缺少模板字段信息") } message := data["message"].(string) // 处理API错误情况 return nil, fmt.Errorf("孔网获取模板字段失败: %v ", message) } /* * 新增商品-已登的店铺--核价软件用 * param token[string] 孔网token * param proxy[string] 代理服务器IP * param formData[string] 商品信息结构体字符串 * return 新增商品响应信息结构体,错误信息 * Error 请先登录获取Token * Error 代理连接失败 * Error 查询请求失败 * Error HTTP错误 * Error 解析JSON失败 * Error API返回错误 */ func outAddGoods(token, proxy, formData string) (map[string]interface{}, error) { // 判断登录token if token == "" { return nil, fmt.Errorf("请先登录获取Token") } // 新增商品的URL outUrl := "https://seller.kongfz.com/pc/itemInfo/add" var repData map[string]interface{} err := json.Unmarshal([]byte(formData), &repData) if err != nil { return nil, fmt.Errorf("JSON解析失败: %v", err) } // 创建请求 request := gorequest.New() // 设置代理(如果有提供代理URL) if proxy != "" { request.Proxy(proxy) } resp, respBody, errs := request.Post(outUrl). 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("Content-Type", writer.FormDataContentType()). Type("multipart"). Send(repData). Timeout(15 * time.Second). End() if errs != nil { // 检查是否是代理相关错误 var isProxyError bool var errorDetails []string for _, e := range errs { 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 } } if isProxyError { // 处理代理失败 return nil, fmt.Errorf("代理连接失败: %s", errs) } return nil, fmt.Errorf("查询请求失败: %v", errs) } //检查HTTP状态码 if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("HTTP错误: %s", resp.Status) } // 解析JSON响应 var data map[string]interface{} if err := json.Unmarshal([]byte(respBody), &data); err != nil { return nil, fmt.Errorf("解析JSON失败: %w", err) } fmt.Println("data:", data) // 检查响应状态 if val, ok := data["status"]; ok && fmt.Sprint(val) == "1" { return data, nil } // 安全获取message var message string if msgVal, ok := data["message"]; ok { switch v := msgVal.(type) { case string: message = v case map[string]interface{}: // 如果是map,可以序列化成JSON字符串 msgBytes, _ := json.Marshal(v) message = string(msgBytes) default: message = fmt.Sprintf("%v", v) } } return nil, fmt.Errorf("新增孔网商品失败: %v", message) } /* * 修改商品-已登的店铺--核价软件用 * param token[string] 孔网token * param proxy[string] 代理服务器IP * param formData[string] 商品信息结构体字符串 * return 新增商品响应信息结构体,错误信息 * Error 请先登录获取Token * Error 代理连接失败 * Error 查询请求失败 * Error HTTP错误 * Error 解析JSON失败 * Error API返回错误 */ func outUpdateGoods(token, proxy, formData string) (map[string]interface{}, error) { // 判断登录token if token == "" { return nil, fmt.Errorf("请先登录获取Token") } // 新增商品的URL outUrl := "https://seller.kongfz.com/pc/itemInfo/update" var repData map[string]interface{} err := json.Unmarshal([]byte(formData), &repData) if err != nil { return nil, fmt.Errorf("JSON解析失败: %v", err) } // 创建请求 request := gorequest.New() // 设置代理(如果有提供代理URL) if proxy != "" { request.Proxy(proxy) } resp, respBody, errs := request.Post(outUrl). 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, */*"). Type("multipart"). Send(repData). Timeout(15 * time.Second). End() if errs != nil { // 检查是否是代理相关错误 var isProxyError bool var errorDetails []string for _, e := range errs { 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 } } if isProxyError { // 处理代理失败 return nil, fmt.Errorf("代理连接失败: %s", errs) } return nil, fmt.Errorf("查询请求失败: %v", errs) } //检查HTTP状态码 if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("HTTP错误: %s", resp.Status) } // 解析JSON响应 var data map[string]interface{} if err := json.Unmarshal([]byte(respBody), &data); err != nil { return nil, fmt.Errorf("解析JSON失败: %w", err) } // 检查响应状态 if val, ok := data["status"]; ok && fmt.Sprint(val) == "1" { return data, nil } message := data["message"].(string) return nil, fmt.Errorf("修改孔网商品失败: %v", message) } // 修改商品价格-已登的店铺--店铺商品中价格下面的按钮修改--孔网核价软件用 func outUpdateGoodsPrice(token, proxy, itemId, updateType, value string) (map[string]interface{}, error) { // 判断登录token if token == "" { return nil, fmt.Errorf("请先登录获取Token") } // 新增商品的URL outUrl := "https://seller.kongfz.com/pc-gw/book-manage-service/client/pc/goods/quickUpdate" repData := map[string]interface{}{ "itemId": itemId, "updateType": updateType, "value": value, } // 创建请求 request := gorequest.New() // 设置代理(如果有提供代理URL) if proxy != "" { request.Proxy(proxy) } resp, respBody, errs := request.Post(outUrl). 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, */*"). Send(repData). Timeout(15 * time.Second). End() if errs != nil { // 检查是否是代理相关错误 var isProxyError bool var errorDetails []string for _, e := range errs { 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 } } if isProxyError { // 处理代理失败 return nil, fmt.Errorf("代理连接失败: %s", errs) } return nil, fmt.Errorf("查询请求失败: %v", errs) } //检查HTTP状态码 if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("HTTP错误: %s", resp.Status) } // 解析JSON响应 var data map[string]interface{} if err := json.Unmarshal([]byte(respBody), &data); err != nil { return nil, fmt.Errorf("解析JSON失败: %w", err) } // 检查响应状态 if val, ok := data["status"]; ok && val == true { return data, nil } message := data["errMessage"].(string) return nil, fmt.Errorf("修改孔网商品失败: %v", message) } // 获取孔网商品列表查询下拉选项--已登的店铺--店铺商品列表查询中下拉选项数据--孔网核价软件用 // @param token[string] 孔网token // @return 孔网商品列表查询下拉选项信息 // @return 错误信息 func outGetBaseSelectData(token string) (map[string]interface{}, error) { // 判断登录token if token == "" { return nil, fmt.Errorf("请先登录获取Token") } // 新增商品的URL outUrl := "https://seller.kongfz.com/pc-gw/book-manage-service/client/pc/goods/getBaseSelectData" // 创建请求 request := gorequest.New() resp, respBody, errs := request.Get(outUrl). 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, */*"). Timeout(15 * time.Second). End() if errs != nil { // 检查是否是代理相关错误 var isProxyError bool var errorDetails []string for _, e := range errs { 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 } } if isProxyError { // 处理代理失败 return nil, fmt.Errorf("代理连接失败: %s", errs) } return nil, fmt.Errorf("查询请求失败: %v", errs) } //检查HTTP状态码 if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("HTTP错误: %s", resp.Status) } // 解析JSON响应 var data map[string]interface{} if err := json.Unmarshal([]byte(respBody), &data); err != nil { return nil, fmt.Errorf("解析JSON失败: %w", err) } // 检查响应状态 if val, ok := data["status"]; ok && val == true { return data, nil } message := data["errMessage"].(string) return nil, fmt.Errorf("修改孔网商品失败: %v", message) } /* * 获取图片key * param token[string] 孔网token * param proxy[string] 代理服务器IP * return 获取图片key响应信息结构体,错误信息 */ func outKfzimgKey(token, proxy string) (map[string]interface{}, error) { // 判断登录token if token == "" { return nil, fmt.Errorf("请先登录获取Token") } // 新增商品的URL url := fmt.Sprintf("https://seller.kongfz.com/kfzimg-key?type=%s", "book") // 创建请求 request := gorequest.New() // 设置代理(如果有提供代理URL) if proxy != "" { request.Proxy(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, */*"). Timeout(15 * time.Second). End() if errs != nil { // 检查是否是代理相关错误 var isProxyError bool var errorDetails []string for _, e := range errs { 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("代理连接失败: %s", errs) } return nil, fmt.Errorf("查询请求失败: %v", errs) } //检查HTTP状态码 if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("HTTP错误: %s", resp.Status) } // 去除括号 jsonStr := strings.TrimPrefix(body, "(") jsonStr = strings.TrimSuffix(jsonStr, ")") // 解析JSON响应 var data map[string]interface{} if err := json.Unmarshal([]byte(jsonStr), &data); err != nil { return nil, fmt.Errorf("解析JSON失败: %w", err) } // 检查响应状态 if val, ok := data["status"]; ok && val == "success" { return data, nil } return nil, fmt.Errorf("API返回错误: %+v", data) } /* * 获取孔网图片 * param token[string] 孔网token * param proxy[string] 代理服务器IP * return 获取孔网图片响应信息结构体,错误信息 */ func outKfzimgUpload(token, proxy, filePath string) (string, error) { url := fmt.Sprint("https://seller.kongfz.com/kfzimg-upload") fileName := filepath.Base(filePath) // 创建multipart/form-data请求体 body := &bytes.Buffer{} writer := multipart.NewWriter(body) // 读取文件内容 fileData, err := os.ReadFile(filePath) if err != nil { return "", fmt.Errorf("读取文件失败: %v", err) } // 添加文件字段 part, err := writer.CreateFormFile("img", filepath.Base(filePath)) if err != nil { return "", fmt.Errorf("创建表单文件失败: %v", err) } _, err = part.Write(fileData) if err != nil { return "", fmt.Errorf("写入文件数据失败: %v", err) } _ = writer.WriteField("autorotated", "1") _ = writer.WriteField("name", fileName) _ = writer.Close() key, err := outKfzimgKey(token, proxy) if err != nil { return "", err } imageKey := key["imagekey"] // 在发送请求前添加 log.Printf("发送请求到: %s", url) log.Printf("Cookie: PHPSESSID=%s", token) log.Printf("文件: %s", fileName) log.Printf("Content-Type: %s", writer.FormDataContentType()) // 发送POST请求 request := gorequest.New() // 设置代理(如果有提供代理URL) if proxy != "" { request.Proxy(proxy) } resp, respBody, errs := request.Post(url). //Set("Cookie", fmt.Sprintf("PHPSESSID=%s", token)). Set("Cookie", fmt.Sprintf("PHPSESSID=%s; IMGKEY=%s", token, imageKey)). Set("Content-Type", writer.FormDataContentType()). // 设置Content-Type 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", "*/*"). Set("Host", "seller.kongfz.com"). Set("Connection", "keep-alive"). Send(body.String()). // 发送请求体 Timeout(30 * time.Second). End() if errs != nil { // 检查是否是代理相关错误 var isProxyError bool var errorDetails []string for _, e := range errs { 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 "", fmt.Errorf("代理连接失败: %s", errs) } return "", fmt.Errorf("查询请求失败: %v", errs) } // 在得到响应后添加 log.Printf("响应状态码: %d", resp.StatusCode) log.Printf("响应头: %v", resp.Header) //检查HTTP状态码 if resp.StatusCode != http.StatusOK { return "", fmt.Errorf("HTTP错误: %s", resp.Status) } // 正则表达式匹配路径 re := regexp.MustCompile(`(sw/.*?\.jpg)`) matches := re.FindStringSubmatch(respBody) if len(matches) > 0 { return matches[1], nil } else { return "", fmt.Errorf("未找到匹配的路径") } } /* * 整合添加商品和获取孔网图片 * param token[string] 孔网token * param proxy[string] 代理服务器IP * param filePath[string] 图片路径 * param formData[string] 商品JSON字符串 * return 添加商品响应信息结构体,错误信息 */ func outAddGoodsAndFile(token, proxy, filePath, formData string) (string, error) { upload, err := outKfzimgUpload(token, proxy, filePath) if err != nil { return "", err } var data map[string]interface{} err = json.Unmarshal([]byte(formData), &data) if err != nil { return "", fmt.Errorf("JSON解析失败: %v", err) } data["images[0][imgUrl]"] = upload dataStr, err := json.Marshal(data) if err != nil { return "", fmt.Errorf("JSON序列化失败: %v", err) } fmt.Println(string(dataStr)) goods, err := outAddGoods(token, proxy, string(dataStr)) if err != nil { return "", err } goodsStr, err := json.Marshal(goods) if err != nil { return "", fmt.Errorf("goodsStr JSON序列化失败: %v", err) } return string(goodsStr), nil } /* * 删除商品-已登的店铺 * param token[string] 孔网token * param proxy[string] 代理服务器IP * param itemId[string] 商品ID * return 删除商品响应信息结构体,错误信息 * Error 请先登录获取Token * Error 代理连接失败 * Error 查询请求失败 * Error HTTP错误 * Error 解析JSON失败 * Error API返回错误 */ func outDelGoodsFromSelfShop(token, proxy, itemId string) (map[string]interface{}, error) { // 判断登录token if token == "" { return nil, fmt.Errorf("请先登录获取Token") } // 删除商品的URL url := "https://seller.kongfz.com/pc-gw/book-manage-service/client/pc/goods/quickUpdate" formData := map[string]string{ "itemId": itemId, "updateType": "delete", "value": "1", } // 创建请求 request := gorequest.New() if proxy != "" { request.Proxy(proxy) } resp, body, errs := request.Post(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, */*"). Send(formData). Timeout(15 * time.Second). End() if errs != nil { // 检查是否是代理相关错误 var isProxyError bool var errorDetails []string for _, e := range errs { 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", errs) } // 检查HTTP状态码 if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("HTTP错误: %s", resp.Status) } // 解析json var data map[string]interface{} if err := json.Unmarshal([]byte(body), &data); err != nil { return nil, fmt.Errorf("解析JSON失败: %w", err) } // 判断是否响应成功 if status, ok := data["status"].(bool); ok && status { return data, nil } // 判断是否响应成功 if status, ok := data["status"].(float64); ok && status == 1 { return data, nil } return nil, fmt.Errorf("API返回错误: %+v", data) } /* * 获取孔网商品图片(官图和拍图)-带有店铺过滤 * param token[string] 孔网token * param proxy[string] 代理服务器IP * param itemId[string] 商品ID * return 删除商品响应信息结构体,错误信息 * Error 请先登录获取Token * Error 代理连接失败 * Error 查询请求失败 * Error HTTP错误 * Error 解析JSON失败 * Error API返回错误 */ func outGetImageFilterShopId(token string, proxy string, isbn string, shopId int, isLiveImage int, isReturnMsg int) (map[string]string, error) { // 判断是否为官图(isLiveImage=0) if isLiveImage == 0 { // 图书条目URL gtUrl := fmt.Sprintf("%s?keyword=%s", "https://search.kongfz.com/pc-gw/search-web/client/pc/bookLib/keyword/list", isbn) request := gorequest.New() if proxy != "" { request.Proxy(proxy) } resp, body, errs := request.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(errs) > 0 { // 检查是否是代理相关错误 var isProxyError bool var errorDetails []string for _, e := range errs { 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", errs) } //检查HTTP状态码 if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("HTTP错误: %s", resp.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(body), &apiGtResp); err != nil { return nil, fmt.Errorf("解析JSON失败: %w", err) } if apiGtResp.ErrType == "102" { return nil, fmt.Errorf("错误信息: %w,状态码: %s", apiGtResp.Message, apiGtResp.ErrType) } var info map[string]string // 如果找到条目,返回图片URL if apiGtResp.Data.ItemResponse.Total > 0 && len(apiGtResp.Data.ItemResponse.List) > 0 { list := apiGtResp.Data.ItemResponse.List[0] info = map[string]string{ "book_name": list.BookName, "book_pic": list.ImgUrlEntity.BigImgUrl, "isbn": list.Isbn, } } return info, nil } // 处理实拍图(isLiveImage=1) 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) } var info map[string]string 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 } // 尝试3次获取有效的图片 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 } // 过滤店铺 if item.ShopId == int64(shopId) { log.Printf("[DEBUG] 索引 %d 的店铺ID需要过滤,跳过", randomNum) continue } // 返回图片信息 info = map[string]string{ "book_name": item.Title, "book_pic_s": item.ImgUrl, "isbn": item.Isbn, } return info, nil } } } return nil, nil } /* * 获取孔网商品图片和信息(官图和拍图) * param token[string] 孔网token * param proxy[string] 代理服务器IP * param isbn[string] isbn * param isLiveImage[int] 是否官图 0官图 1实拍图 * param isReturnMsg[int] 是否有其他信息 * return 孔网商品图片和信息响应信息结构体,错误信息 * Error 请先登录获取Token * Error 代理连接失败 * Error 查询请求失败 * Error 解析JSON失败 * Error 错误信息: %w,状态码: %s * Error 查询失败,没有数据! */ func outGetImageByIsbn(token string, proxy string, isbn string, isLiveImage int, isReturnMsg int) (*BookInfo, error) { // isLiveImage 1实拍图 0官图 ,isReturnMsg 0商品信息 bookInfo := &BookInfo{} // 处理官图(isLiveImage=0) 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) } // 发送GET请求 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"` } // 解析JSON 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 bookInfo.Mid = list.Mid // 根据长度安全填充字段 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 } // 处理实拍图(isLiveImage=1) 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). 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(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 } // 尝试3次获取有效的图片 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("查询失败,没有数据!") } // 爬取孔网所有商品页面 https://search.kongfz.com/pc-gw/search-web/client/pc/product/keyword/list?dataType=0&keyword=9787802204461&page=1&quality=100~&quaSelect=2&actionPath=quality,sortType&sortType=7&userArea=13003000000 // --孔网核价系统用 func outGetAllGoods(token, proxy string, queryIndex int, isbn string, quality string, itemName, author, press string) (*BookInfo, error) { var actionPathList []string if token == "" { return nil, fmt.Errorf("token 不能为空") } kfzUrl := "https://search.kongfz.com/pc-gw/search-web/client/pc/product/keyword/list?dataType=0&page=1&sortType=7&userArea=13003000000&quaSelect=2" // 整理查询参数-加上排序 actionPathList = append(actionPathList, "sortType") // isbn if isbn != "" { kfzUrl = kfzUrl + "&keyword=" + isbn } // 品相 if quality != "" { kfzUrl = kfzUrl + "&quality=" + quality + "~" actionPathList = append(actionPathList, "quality") } // 书名 if itemName != "" { kfzUrl = kfzUrl + "&itemName=" + itemName actionPathList = append(actionPathList, "itemName") } // 作者 if author != "" { kfzUrl = kfzUrl + "&author=" + author actionPathList = append(actionPathList, "author") } // 出版社 if press != "" { kfzUrl = kfzUrl + "&press=" + press actionPathList = append(actionPathList, "press") } // 参数进行分割 actionPath := strings.Join(actionPathList, ",") // 加入查询参数 kfzUrl = kfzUrl + "&actionPath=" + actionPath //创建HTTP客户端 requestSpt := gorequest.New() //设置代理(如果有提供代理URL) if proxy != "" { requestSpt.Proxy(proxy) } // 发送请求 respSpt, bodySpt, errsSpt := requestSpt.Get(kfzUrl). 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(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 { Title string `json:"title"` Author string `json:"author"` Press string `json:"press"` PubDateText string `json:"pubDateText"` Isbn string `json:"isbn"` Price float64 `json:"price"` Postage struct { ShippingList []struct { ShippingFee float64 `json:"shippingFee"` } } `json:"postage"` } `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.Status != 1 { return nil, fmt.Errorf("错误信息: %v,状态码: %s", apiSptResp.Message, apiSptResp.ErrType) } bookInfo := &BookInfo{} if apiSptResp.Data.ItemResponse.Total > 0 && len(apiSptResp.Data.ItemResponse.List) > 0 { if queryIndex > 0 && queryIndex <= len(apiSptResp.Data.ItemResponse.List) { goodsInfo := apiSptResp.Data.ItemResponse.List[queryIndex-1] bookInfo.BookName = goodsInfo.Title bookInfo.ISBN = goodsInfo.Isbn bookInfo.Author = goodsInfo.Author bookInfo.Publisher = goodsInfo.Press bookInfo.PubDate = goodsInfo.PubDateText bookInfo.SellingPrice = fmt.Sprintf("%.2f", goodsInfo.Price) for _, shipping := range goodsInfo.Postage.ShippingList { bookInfo.ExpressDeliveryFee = fmt.Sprintf("%.2f", shipping.ShippingFee) } } else { goodsInfo := apiSptResp.Data.ItemResponse.List[len(apiSptResp.Data.ItemResponse.List)-1] bookInfo.BookName = goodsInfo.Title bookInfo.ISBN = goodsInfo.Isbn bookInfo.Author = goodsInfo.Author bookInfo.Publisher = goodsInfo.Press bookInfo.PubDate = goodsInfo.PubDateText bookInfo.SellingPrice = fmt.Sprintf("%.2f", goodsInfo.Price) for _, shipping := range goodsInfo.Postage.ShippingList { bookInfo.ExpressDeliveryFee = fmt.Sprintf("%.2f", shipping.ShippingFee) } } return bookInfo, nil } return nil, fmt.Errorf("查询失败,没有数据!") } // 爬取孔网 https://item.kongfz.com/pc-gw/item-library-service/client/pc/item/detail/48129308 网址商品信息 func outGetMidDetail(token string, mid string) (*BookInfo, error) { detailUrl := fmt.Sprintf("https://item.kongfz.com/pc-gw/item-library-service/client/pc/item/detail/%s", mid) // 创建HTTP客户端,设置超时时间 client := &http.Client{ Timeout: 120 * time.Second, } // 创建HTTP请求 req, err := http.NewRequest("GET", detailUrl, nil) if err != nil { return nil, fmt.Errorf("创建请求失败: %w", err) } // 设置请求头,模拟浏览器访问 req.Header.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") req.Header.Set("Accept", "application/json, text/plain, */*") req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8") req.Header.Set("Connection", "keep-alive") req.Header.Set("Cookie", fmt.Sprintf("PHPSESSID=%s", token)) // 发送请求 resp, err := client.Do(req) if err != nil { return nil, fmt.Errorf("请求失败: %w", err) } defer resp.Body.Close() // 读取响应体 body, err := io.ReadAll(resp.Body) if err != nil { return nil, fmt.Errorf("读取响应失败: %w", err) } // 解析API响应结构 var apiResp struct { Status bool `json:"status"` ErrCode int `json:"errCode"` ErrMessage string `json:"errMessage"` Result struct { ID int `json:"id"` Mid string `json:"mid"` Isbn string `json:"isbn"` OriIsbn string `json:"oriIsbn"` UnifiedIsbn string `json:"unifiedIsbn"` BookName string `json:"bookName"` ContentIntroduction string `json:"contentIntroduction"` AuthorIntroduction string `json:"authorIntroduction"` Directory string `json:"directory"` FilteredContentIntroduction string `json:"filteredContentIntroduction"` FilteredAuthorIntroduction string `json:"filteredAuthorIntroduction"` FilteredDirectory string `json:"filteredDirectory"` RightList []struct { Name string `json:"name"` Value string `json:"value"` } `json:"rightList"` LeftList []struct { Name string `json:"name"` Value string `json:"value"` } `json:"leftList"` BoughtNum int `json:"boughtNum"` ImageNum int `json:"imageNum"` ImageNumUrl string `json:"imageNumUrl"` CoverImageWater string `json:"coverImageWater"` CoverImageBig string `json:"coverImageBig"` CoverImageMid string `json:"coverImageMid"` CoverImageSmall string `json:"coverImageSmall"` RelatedCateList []string `json:"relatedCateList"` } `json:"result"` } // 解析JSON if err := json.Unmarshal(body, &apiResp); err != nil { return nil, fmt.Errorf("解析JSON失败: %w", err) } // 检查API响应状态 if !apiResp.Status { return nil, fmt.Errorf("API返回错误: %s (代码: %d)", apiResp.ErrMessage, apiResp.ErrCode) } bookInfo := &BookInfo{} result := apiResp.Result // 基本信息 bookInfo.BookName = result.BookName bookInfo.ISBN = result.Isbn bookInfo.Mid, _ = strconv.ParseInt(result.Mid, 10, 64) // 内容简介、作者简介、目录(优先使用过滤后的内容) bookInfo.Content = result.FilteredContentIntroduction if bookInfo.Content == "" { bookInfo.Content = result.ContentIntroduction } bookInfo.AuthorIntroduction = result.FilteredAuthorIntroduction if bookInfo.AuthorIntroduction == "" { bookInfo.AuthorIntroduction = result.AuthorIntroduction } bookInfo.Catalogue = result.FilteredDirectory if bookInfo.Catalogue == "" { bookInfo.Catalogue = result.Directory } // 买过人数 bookInfo.BuyCount = strconv.Itoa(result.BoughtNum) // 图书封面图 bookInfo.BookPic = result.CoverImageBig if bookInfo.BookPic == "" { bookInfo.BookPic = result.CoverImageMid } // 处理左侧信息(作者、出版社、出版时间、版次、ISBN、定价) for _, item := range result.LeftList { switch item.Name { case "作者": // 清理HTML标签,提取纯文本 bookInfo.Author = cleanHTMLText(item.Value) case "出版社": bookInfo.Publisher = cleanHTMLText(item.Value) case "出版时间": bookInfo.PublicationTime = validateDateFormat(item.Value) case "版次": bookInfo.Edition = item.Value case "ISBN": bookInfo.ISBN = item.Value case "定价": bookInfo.FixPrice = item.Value } } // 处理右侧信息(装帧、开本、页数、字数、分类等) for _, item := range result.RightList { switch item.Name { case "装帧": bookInfo.BindingLayout = item.Value case "开本": bookInfo.Format = item.Value case "页数": bookInfo.Pages = item.Value case "字数": bookInfo.Wordage = item.Value case "分类": bookInfo.Category = cleanHTMLText(item.Value) } } return bookInfo, nil } // 辅助函数:清理HTML标签,提取纯文本 func cleanHTMLText(html string) string { // 移除HTML标签 re := regexp.MustCompile(`<[^>]*>`) text := re.ReplaceAllString(html, "") // 替换HTML实体 text = strings.ReplaceAll(text, " ", " ") text = strings.ReplaceAll(text, "<", "<") text = strings.ReplaceAll(text, ">", ">") text = strings.ReplaceAll(text, "&", "&") text = strings.ReplaceAll(text, """, "\"") text = strings.ReplaceAll(text, "'", "'") // 清理空白字符 text = strings.TrimSpace(text) text = regexp.MustCompile(`\s+`).ReplaceAllString(text, " ") return text } /* * 获取商品列表通过店铺ID--他店的商品 * param shopId[int] 店铺ID * param proxy[string] 代理服务器IP * param retPrice[int] 是否需要价格 * param isImage[int] 是否有图片 0:有图 1:无图 * param sortType[string] 排序类型 默认值sort * param sort[string] 排序 默认值desc * param priceMin[float32] 价格区间-低 * param priceMax[float32] 价格区间-高 * param pageNum[int] 页数 * param returnNum[int] 返回数量 * return 商品列表响应信息结构体,商品总数,总页数,错误信息 * Error 无效的排序类型: %s,可选值: sort, putDate, newItem, price * Error 无效的排序类型: %s,可选值: desc, asc */ func outGetGoodsListMsgByShopId(token string, shopId int, proxy string, retPrice int, isImage int, sortType string, sort string, priceMin float32, priceMax float32, pageNum, returnNum int) (books []BookInfo, goodsNum string, pNum string, err error) { // 判断店铺ID if shopId == 0 { return nil, "", "", fmt.Errorf("店铺编码为空!") } // 判断是否有图片,设置默认值0 var isImageStr string if isImage == 0 { isImageStr = "0" } else { isImageStr = "1" } // 判断一页图书数量,设置默认值100 if returnNum == 0 { returnNum = 100 } // 判断页数,设置默认值1 if pageNum == 0 { pageNum = 1 } // 判断排序类型,设置默认值sort if sortType == "" { sortType = "sort" } else { validSortTypes := map[string]bool{ "sort": true, "putDate": true, "newItem": true, "price": true, } if !validSortTypes[sortType] { return nil, "", "", fmt.Errorf("无效的排序类型: %s,可选值: sort, putDate, newItem, price", sortType) } } // 判断排序,设置默认值desc if sort == "" { sort = "desc" } else { validSorts := map[string]bool{ "desc": true, "asc": true, } if !validSorts[sort] { return nil, "", "", fmt.Errorf("无效的排序类型: %s,可选值: desc, asc", sort) } } var kfzUrl string var pMin int pMin = 0 var pMax int pMax = 0 // 判断价格下限,设置默认值0 if priceMin == 0 && priceMax == 0 { // 调用的url kfzUrl = fmt.Sprintf("https://shop.kongfz.com/%d/all/%s_%d_0_0_%d_%s_%s_%d_%d", shopId, isImageStr, returnNum, pageNum, sortType, sort, pMin, pMax) } else if priceMin == 0 { kfzUrl = fmt.Sprintf("https://shop.kongfz.com/%d/all/%s_%d_0_0_%d_%s_%s_%d_%.2f", shopId, isImageStr, returnNum, pageNum, sortType, sort, pMin, priceMax) } else if priceMax == 0 { kfzUrl = fmt.Sprintf("https://shop.kongfz.com/%d/all/%s_%d_0_0_%d_%s_%s_%.2f_%d", shopId, isImageStr, returnNum, pageNum, sortType, sort, priceMin, pMax) } else { kfzUrl = fmt.Sprintf("https://shop.kongfz.com/%d/all/%s_%d_0_0_%d_%s_%s_%.2f_%.2f", shopId, isImageStr, returnNum, pageNum, sortType, sort, priceMin, priceMax) } // 发送请求(移除了重试机制) var response *http.Response var errors []error // 根据是否有代理发送请求 if proxy != "" { response, _, errors = gorequest.New(). Get(kfzUrl). Proxy(proxy). Set("Cookie", fmt.Sprintf("PHPSESSID=%s", token)). Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"). Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"). Set("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8"). Timeout(120 * time.Second). End() } else { fmt.Println("没使用代理") response, _, errors = gorequest.New(). Get(kfzUrl). Set("Cookie", fmt.Sprintf("PHPSESSID=%s", token)). Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"). Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"). Set("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8"). Timeout(120 * time.Second). End() } // 检测请求是否错误 if len(errors) > 0 { var proxyAuthFailed bool var timeoutError bool var connectionError bool // 分析错误类型 for _, e := range errors { errStr := e.Error() if strings.Contains(errStr, "Proxy Authentication Required") { proxyAuthFailed = true } if strings.Contains(errStr, "timeout") || strings.Contains(errStr, "i/o timeout") { timeoutError = true } if strings.Contains(errStr, "connection") || strings.Contains(errStr, "connect") { connectionError = true } } // 根据错误类型返回相应的错误信息 if proxyAuthFailed { fmt.Println("代理认证失败") return nil, "", "", fmt.Errorf("代理认证失败") } if timeoutError { fmt.Println("请求超时,超时网址") return nil, "", "", fmt.Errorf("请求超时,超时网址:%s", kfzUrl) } if connectionError { fmt.Println("网络连接错误,错误网址:") return nil, "", "", fmt.Errorf("网络连接错误,错误网址:%s", kfzUrl) } fmt.Println("查询请求失败:", errors) return nil, "", "", fmt.Errorf("查询请求失败: %v,失败网址:%s", errors, kfzUrl) } // 检查响应是否为空 if response == nil { fmt.Println("响应为空") return nil, "", "", fmt.Errorf("响应为空") } // 检查HTTP状态码 if response.StatusCode != http.StatusOK { fmt.Println("HTTP错误") return nil, "", "", fmt.Errorf("HTTP错误: %s", response.Status) } // 读取响应体 body, err := io.ReadAll(response.Body) if err != nil { return nil, "", "", err } // 解析HTML文档 doc, err := goquery.NewDocumentFromReader(strings.NewReader(string(body))) if err != nil { return nil, "", "", err } // 全部商品数量 num := doc.Find("div.crumbs-nav-main.clearfix").Find("span") if match := regexp.MustCompile(`\d+`).FindString(num.Text()); match != "" { goodsNum = match } // 商品页数 pg := doc.Find("li.pull-right.page_num").Find("span") _, split, found := strings.Cut(strings.TrimSpace(pg.Text()), "/") if found { pNum = split } else { log.Printf("未找到页数!") } // 提取商品信息 infoDiv := doc.Find("div.list-content") var params ParamsInfo if infoDiv.Length() > 0 { item := infoDiv.Find("div.item.clearfix") for i := 0; i < item.Length(); i++ { s := item.Eq(i) book := BookInfo{} // 书名 book.BookName = strings.TrimSpace(s.Find("div.title a.link").Text()) // 提取ISBN book.ISBN = strings.TrimSpace(s.AttrOr("isbn", "")) // 店铺ID shopid, _ := strconv.Atoi(strings.TrimSpace(s.AttrOr("shopid", ""))) book.ShopId = int64(shopid) // 商品ID itemid, _ := strconv.Atoi(strings.TrimSpace(s.AttrOr("itemid", ""))) book.ItemId = int64(itemid) // 详情URL book.DetailUrl = s.Find("div.item-img a.img-box").AttrOr("href", "") // 价格 if retPrice == 0 { book.SellingPrice = s.Find("div.f_right.red.price").Find("span.bold").Text() params.Params = append(params.Params, struct { UserId string `json:"userId"` ItemId string `json:"itemId"` }{UserId: strings.TrimSpace(s.AttrOr("userid", "")), ItemId: strings.TrimSpace(s.AttrOr("itemid", ""))}) } books = append(books, book) } // 如果需要查询快递费 if params.Params != nil { params.Area = "13003000000" dataItem, err := getGoodsListShippingFee(params, proxy) if err != nil { fmt.Println("查询快递费失败") return nil, "", "", err } // 将快递费信息填充到图书信息中 for i := 0; i < len(books); i++ { itemId := fmt.Sprintf("%d", books[i].ItemId) for _, data := range dataItem { if itemId == data.ItemID { books[i].ExpressDeliveryFee = data.Fee[0].TotalFee } } } } } return books, goodsNum, pNum, nil } // 获取孔网他店商品数据列表--他店的商品 // @param token 登录凭证 // @param shopId 他店店铺ID // @param proxy 代理 // @param retPrice 是否需要价格 // @param isImage 是否有图片 0:有 1:无 // @param sortType 排序类型 // @param sort 排序方式 // @param priceMin 价格最小值 // @param priceMax 价格最大值 // @param pageNum 页码 // @param returnNum 一页图书数量 // @return books 图书列表 // @return goodsNum 商品数量 // @return pNum 商品页数 // @return error 错误信息 func outGetHisGoodsList(token, shopId, proxy, retPrice, isImage, sortType, sort, priceMin, priceMax string, pageNum, returnNum int) (books []BookInfo, goodsNum string, pNum string, err error) { // 判断店铺ID if shopId == "" { return nil, "", "", fmt.Errorf("店铺编码为空!") } // 判断是否有图片,设置默认值0 if isImage == "" { isImage = "0" } // 判断一页图书数量,设置默认值100 if returnNum == 0 { returnNum = 100 } // 判断页数,设置默认值1 if pageNum == 0 { pageNum = 1 } // 判断排序类型,设置默认值sort if sortType == "" { sortType = "sort" } else { validSortTypes := map[string]bool{ "sort": true, "putDate": true, "newItem": true, "price": true, } if !validSortTypes[sortType] { return nil, "", "", fmt.Errorf("无效的排序类型: %s,可选值: sort, putDate, newItem, price", sortType) } } // 判断排序,设置默认值desc if sort == "" { sort = "desc" } else { validSorts := map[string]bool{ "desc": true, "asc": true, } if !validSorts[sort] { return nil, "", "", fmt.Errorf("无效的排序类型: %s,可选值: desc, asc", sort) } } if priceMin == "" { priceMin = "0" } if priceMax == "" { priceMax = "0" } kfzUrl := fmt.Sprintf("https://shop.kongfz.com/%s/all/%s_%d_0_0_%d_%s_%s_%s_%s", shopId, isImage, returnNum, pageNum, sortType, sort, priceMin, priceMax) log.Println("网址:", kfzUrl) // 发送请求(移除了重试机制) var response *http.Response var errors []error // 根据是否有代理发送请求 if proxy != "" { response, _, errors = gorequest.New(). Get(kfzUrl). Proxy(proxy). Set("Cookie", fmt.Sprintf("PHPSESSID=%s", token)). Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"). Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"). Set("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8"). Timeout(120 * time.Second). End() } else { response, _, errors = gorequest.New(). Get(kfzUrl). Set("Cookie", fmt.Sprintf("PHPSESSID=%s", token)). Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"). Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"). Set("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8"). Timeout(120 * time.Second). End() } // 检测请求是否错误 if len(errors) > 0 { var proxyAuthFailed bool var timeoutError bool var connectionError bool // 分析错误类型 for _, e := range errors { errStr := e.Error() if strings.Contains(errStr, "Proxy Authentication Required") { proxyAuthFailed = true } if strings.Contains(errStr, "timeout") || strings.Contains(errStr, "i/o timeout") { timeoutError = true } if strings.Contains(errStr, "connection") || strings.Contains(errStr, "connect") { connectionError = true } } // 根据错误类型返回相应的错误信息 if proxyAuthFailed { return nil, "", "", fmt.Errorf("代理认证失败") } if timeoutError { return nil, "", "", fmt.Errorf("请求超时,超时网址:%s", kfzUrl) } if connectionError { return nil, "", "", fmt.Errorf("网络连接错误,错误网址:%s", kfzUrl) } return nil, "", "", fmt.Errorf("查询请求失败: %v,失败网址:%s", errors, kfzUrl) } // 检查响应是否为空 if response == nil { return nil, "", "", fmt.Errorf("响应为空") } // 检查HTTP状态码 if response.StatusCode != http.StatusOK { return nil, "", "", fmt.Errorf("HTTP错误: %s", response.Status) } // 读取响应体 body, err := io.ReadAll(response.Body) if err != nil { return nil, "", "", err } // 解析HTML文档 doc, err := goquery.NewDocumentFromReader(strings.NewReader(string(body))) if err != nil { return nil, "", "", err } // 全部商品数量 num := doc.Find("div.crumbs-nav-main.clearfix").Find("span") if match := regexp.MustCompile(`\d+`).FindString(num.Text()); match != "" { goodsNum = match } // 商品页数 pg := doc.Find("li.pull-right.page_num").Find("span") _, split, found := strings.Cut(strings.TrimSpace(pg.Text()), "/") if found { pNum = split } else { return nil, "", "", fmt.Errorf("未找到店铺页数!") } // 提取商品信息 infoDiv := doc.Find("div.list-content") var params ParamsInfo if infoDiv.Length() > 0 { item := infoDiv.Find("div.item.clearfix") for i := 0; i < item.Length(); i++ { s := item.Eq(i) book := BookInfo{} // 书名 book.BookName = strings.TrimSpace(s.Find("div.title a.link").Text()) // 提取ISBN book.ISBN = strings.TrimSpace(s.AttrOr("isbn", "")) // 店铺ID shopid, _ := strconv.Atoi(strings.TrimSpace(s.AttrOr("shopid", ""))) book.ShopId = int64(shopid) // 商品ID itemid, _ := strconv.Atoi(strings.TrimSpace(s.AttrOr("itemid", ""))) book.ItemId = int64(itemid) // 详情URL book.DetailUrl = s.Find("div.item-img a.img-box").AttrOr("href", "") // 价格 if retPrice == "0" { book.SellingPrice = s.Find("div.f_right.red.price").Find("span.bold").Text() params.Params = append(params.Params, struct { UserId string `json:"userId"` ItemId string `json:"itemId"` }{UserId: strings.TrimSpace(s.AttrOr("userid", "")), ItemId: strings.TrimSpace(s.AttrOr("itemid", ""))}) } books = append(books, book) } // 如果需要查询快递费 if params.Params != nil { params.Area = "13003000000" dataItem, err := getGoodsListShippingFee(params, proxy) if err != nil { return nil, "", "", fmt.Errorf("查询快递费失败: %v", err) } // 将快递费信息填充到图书信息中 for i := 0; i < len(books); i++ { itemId := fmt.Sprintf("%d", books[i].ItemId) for _, data := range dataItem { if itemId == data.ItemID { books[i].ExpressDeliveryFee = data.Fee[0].TotalFee } } } } } return books, goodsNum, pNum, nil } /* * 获取商品信息通过商品详情链接--他店的商品 * param detailUrl[string] 详情页url * param proxy[string] 代理服务器IP * return 商品列表响应信息结构体,错误信息 * Error 未找到指定的contentSpan信息 * Error 无效的排序类型: %s,可选值: desc, asc */ func outGetGoodsMsgByDetailUrl(detailUrl, proxy string) (*BookInfo, error) { // 发送请求获取响应 response, err := fetchResponse(detailUrl, proxy) if err != nil { return nil, err } // 读取响应体 body, err := io.ReadAll(response.Body) if err != nil { return nil, err } // 解析HTML文档 document, err := goquery.NewDocumentFromReader(strings.NewReader(string(body))) if err != nil { return nil, err } // 获取商品信息的快递费 fee, err := getBookDetailShippingFee(detailUrl, proxy) if err != nil { return nil, err } book := BookInfo{} // 书名 book.BookName = strings.TrimSpace(document.Find("h1.title").Text()) // 提取作者、出版社等信息 topDiv := document.Find("div.keywords-define.keywords-define-1000.clear-fix") if topDiv.Length() > 0 { topDiv.Find("li").Each(func(i int, li *goquery.Selection) { titleSpan := li.Find("span.keywords-define-title") contentSpan := li.Find("span.keywords-define-txt") if contentSpan.Length() == 0 { fmt.Printf("未找到指定的contentSpan信息") } titleText := strings.TrimSpace(titleSpan.Text()) contentText := strings.TrimSpace(contentSpan.Text()) titleText = strings.TrimSpace(titleText) // 根据标题字段填充对应的图书信息字段 if strings.Contains(titleText, "作者") { book.Author = cleanString(contentText) } if strings.Contains(titleText, "出版社") { book.Publisher = contentText } if strings.Contains(titleText, "出版人") { book.Publisher = contentText } if strings.Contains(titleText, "ISBN") { book.ISBN = contentText } if strings.Contains(titleText, "出版时间") { book.PublicationTime = validateDateFormat(contentText) } if strings.Contains(titleText, "版次") { book.Edition = contentText } if strings.Contains(titleText, "装帧") { book.BindingLayout = contentText } if strings.Contains(titleText, "开本") { book.Format = contentText } if strings.Contains(titleText, "页数") { book.Pages = contentText } if strings.Contains(titleText, "字数") { book.Wordage = contentText } if strings.Contains(titleText, "纸张") { book.Paper = contentText } if strings.Contains(titleText, "年代") { book.Era = contentText } if strings.Contains(titleText, "刻印方式") { book.EngravingMethod = contentText } if strings.Contains(titleText, "尺寸") { book.Dimensions = contentText } if strings.Contains(titleText, "册数") { book.VolumeNumber = contentText } }) } else { // 备选提取方式 botDiv := document.Find("div.detail-lists.clear-fix") botDiv.Find("li").Each(func(i int, li *goquery.Selection) { spanText := strings.TrimSpace(li.Find("span").Text()) spanText = strings.TrimSpace(spanText) if strings.Contains(li.Text(), "作者") { book.Author = cleanString(li.Text()) book.Author = strings.ReplaceAll(book.Author, "作者:", "") book.Author = strings.ReplaceAll(book.Author, "著", "") } if strings.Contains(li.Text(), "出版社") { book.Publisher = spanText } if strings.Contains(li.Text(), "出版时间") { book.PublicationTime = validateDateFormat(spanText) } if strings.Contains(li.Text(), "ISBN") { book.ISBN = spanText } if strings.Contains(li.Text(), "装帧") { book.BindingLayout = spanText } if strings.Contains(li.Text(), "开本") { book.Format = spanText } if strings.Contains(li.Text(), "纸张") { book.Paper = spanText } if strings.Contains(li.Text(), "版次") { book.Edition = spanText } if strings.Contains(li.Text(), "页数") { book.Pages = spanText } if strings.Contains(li.Text(), "字数") { book.Wordage = spanText } }) } // 提取商品图片 var imgUrls []string tpUl := document.Find("ul.lg-list") tpUl.Find("img").Each(func(i int, s *goquery.Selection) { dataImgUrl, exists := s.Attr("data-imgurl") if exists && dataImgUrl != "" { imgUrls = append(imgUrls, dataImgUrl) } }) book.BookPicS = strings.Join(imgUrls, ",") // 提取售价 price := document.Find("i.now-price-text").Text() priceN := regexp.MustCompile(`(\d+\.?\d*)`) if match := priceN.FindStringSubmatch(price); len(match) > 0 { book.SellingPrice = match[1] } // 提取定价 fixPrice := document.Find("span.origin-price-text.clearfix").Text() fixPriceN := regexp.MustCompile(`(\d+\.?\d*)`) if match := fixPriceN.FindStringSubmatch(fixPrice); len(match) > 0 { book.FixPrice = match[1] } // 提取品相 text := document.Find("span.quality-text-cot.clearfix i").Text() book.Condition = strings.TrimSpace(text) // 设置快递费 book.ExpressDeliveryFee = fee return &book, nil } /* * 获取商品信息的快递费(定位到河南) * param url[string] 获取快递费url * param proxy[string] 代理服务器IP * return 商品列表响应信息结构体,错误信息 * Error 无效的店铺编码: %s * Error 无效的图书编码: %s * Error 请求失败 * Error HTTP错误 * Error 解析JSON失败 */ func getBookDetailShippingFee(url, proxy string) (string, error) { // 从URL中提取店铺ID和商品ID compile := regexp.MustCompile(`kongfz\.com/(\d+)/(\d+)`) match := compile.FindStringSubmatch(url) var shippingFee string var shopId int var itemId int if len(match) == 3 { // 提取店铺ID firstNum, err := strconv.Atoi(match[1]) if err != nil { return "", fmt.Errorf("无效的店铺编码: %s", match[1]) } shopId = firstNum // 提取商品ID secondNum, err := strconv.Atoi(match[2]) if err != nil { return "", fmt.Errorf("无效的图书编码: %s", match[2]) } itemId = secondNum } // 构建快递费查询URL shippingFeeUrl := fmt.Sprintf("https://book.kongfz.com/store-web/pc/v1/mould/calculateFee?area=13003000000&itemId=%d&shopId=%d", itemId, shopId) // 创建HTTP客户端 request := gorequest.New() // 设置代理(如果有提供代理URL) if proxy != "" { request.Proxy(proxy) } // 设置超时和其他配置 request.Timeout(30 * time.Second) // 发送请求 resp, body, errs := request.Get(shippingFeeUrl). 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"). End() // 错误处理 if len(errs) > 0 { return "", fmt.Errorf("请求失败: %v", errs) } // 检查HTTP状态码 if resp.StatusCode != http.StatusOK { return "", fmt.Errorf("HTTP错误: %s", resp.Status) } calculateFee := struct { ErrCode int `json:"errCode"` ErrMessage string `json:"errMessage"` Result struct { FeeList []struct { FreeCondition string `json:"freeCondition"` ShippingID string `json:"shippingId"` ShippingName string `json:"shippingName"` ShippingValue string `json:"shippingValue"` } `json:"feeList"` FeeText string `json:"feeText"` } `json:"result"` Status bool `json:"status"` }{} // 解析JSON err := json.Unmarshal([]byte(body), &calculateFee) if err != nil { return "", fmt.Errorf("解析JSON失败: %v", err) } // 提取快递费 for _, fee := range calculateFee.Result.FeeList { shippingFee = fee.ShippingValue } return shippingFee, nil } /* * 公用发送请求方法 * param url[string] url * param proxy[string] 代理服务器IP * return 商品列表响应信息结构体,错误信息 * Error 请求失败 * Error 响应为空 (尝试 %d/%d) * Error HTTP状态码: %d,HTTP请求失败: %s (尝试 %d/%d) * Error 代理认证失败 * Error 请求超时,经过 %d 次尝试,超时网址:%s * Error 网络连接错误,经过 %d 次尝试,错误网址:%s * Error 查询请求失败,经过 %d 次尝试: %v,失败网址:%s * Error HTTP错误 */ func fetchResponse(url, proxy string) (*http.Response, error) { log.Printf("调用的URL: %s", url) maxRetries := 3 var detailsResp *http.Response var errors []error // 重试机制 for attempt := 0; attempt < maxRetries; attempt++ { if attempt > 0 { log.Printf("第 %d 次重试请求...", attempt) // 重试前等待,使用指数退避策略 waitTime := time.Duration(attempt*attempt) * 1000 // 平方退避 log.Printf("等待 %v 后重试", waitTime) time.Sleep(waitTime) } // 根据是否有代理发送请求 if proxy != "" { detailsResp, _, errors = gorequest.New(). Get(url). Proxy(proxy). Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"). Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"). Set("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8"). Timeout(120 * time.Second). End() } if proxy == "" { detailsResp, _, errors = gorequest.New(). Get(url). Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"). Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"). Set("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8"). Timeout(120 * time.Second). End() } // 检查是否需要重试 shouldRetry := false if len(errors) > 0 { shouldRetry = true log.Printf("请求失败 (尝试 %d/%d): %v", attempt+1, maxRetries+1, errors) } else if detailsResp == nil { shouldRetry = true log.Printf("响应为空 (尝试 %d/%d)", attempt+1, maxRetries+1) } else if detailsResp.StatusCode != http.StatusOK { // 只对服务器错误进行重试,不对客户端错误重试 if detailsResp.StatusCode >= 500 { shouldRetry = true } log.Printf("HTTP状态码: %d,HTTP请求失败: %s (尝试 %d/%d)", detailsResp.StatusCode, detailsResp.Body, attempt+1, maxRetries+1) } // 如果不需要重试,跳出循环 if !shouldRetry { break } // 如果是最后一次尝试,不继续重试 if attempt == maxRetries { break } // 关闭响应体(如果存在) if detailsResp != nil && detailsResp.Body != nil { detailsResp.Body.Close() } } // 检测请求是否错误 if len(errors) > 0 { var proxyAuthFailed bool var timeoutError bool var connectionError bool // 分析错误类型 for _, e := range errors { errStr := e.Error() if strings.Contains(errStr, "Proxy Authentication Required") { proxyAuthFailed = true } if strings.Contains(errStr, "timeout") || strings.Contains(errStr, "i/o timeout") { timeoutError = true } if strings.Contains(errStr, "connection") || strings.Contains(errStr, "connect") { connectionError = true } } // 根据错误类型返回相应的错误信息 if proxyAuthFailed { return nil, fmt.Errorf("代理认证失败") } if timeoutError { return nil, fmt.Errorf("请求超时,经过 %d 次尝试,超时网址:%s", maxRetries+1, url) } if connectionError { return nil, fmt.Errorf("网络连接错误,经过 %d 次尝试,错误网址:%s", maxRetries+1, url) } return nil, fmt.Errorf("查询请求失败,经过 %d 次尝试: %v,失败网址:%s", maxRetries+1, errors, url) } // 检查HTTP状态码 if detailsResp.StatusCode != http.StatusOK { return nil, fmt.Errorf("HTTP错误: %s", detailsResp.Status) } return detailsResp, nil } /* * 获取销量榜商品列表 * param catId[int] 分类ID * param proxy[string] 代理服务器IP * return isbn数组,错误信息 * Error 请求失败 * Error HTTP错误 * Error 解析JSON失败 * Error API返回错误: %s (代码: %d) */ func outGetTopGoodsListMsg(catId int, proxy string) ([]string, error) { // 构建请求URL url := fmt.Sprintf("https://item.kongfz.com/api/pc/getSellWellListDetail?page=1&pageSize=100&timeRank=2&catId=%d", catId) // 创建HTTP客户端 request := gorequest.New() // 设置代理(如果有提供代理URL) if proxy != "" { request.Proxy(proxy) } // 设置超时和其他配置 request.Timeout(30 * time.Second) // 发送GET请求 resp, body, errs := request.Get(url). 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/"). End() // 错误处理 if len(errs) > 0 { return nil, fmt.Errorf("请求失败: %v", errs) } // 检查HTTP状态码 if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("HTTP错误: %s", resp.Status) } // 解析响应 var bookDetailResponse BookDetailResponse err := json.Unmarshal([]byte(body), &bookDetailResponse) if err != nil { return nil, fmt.Errorf("解析JSON失败: %v", err) } // 检查响应状态 if !bookDetailResponse.Status { return nil, fmt.Errorf("API返回错误: %s (代码: %d)", bookDetailResponse.ErrMessage, bookDetailResponse.ErrCode) } // 提取ISBN列表 var isbnList []string for _, item := range bookDetailResponse.Result.Data { if item.Isbn != "" { isbnList = append(isbnList, item.Isbn) } } // 去除重复的ISBN isbnList = removeDuplicateISBNs(isbnList) return isbnList, nil } /* * 去除重复的ISBN * param isbns[[]string] isbn数组 * return isbn数组 */ func removeDuplicateISBNs(isbns []string) []string { seen := make(map[string]bool) var result []string for _, isbn := range isbns { if !seen[isbn] { seen[isbn] = true result = append(result, isbn) } } return result } /* * 生成签名 * param params[map[string]interface{}] 生成签名的字段map * param appSecret[string] app密钥 * return 签名 */ func generateSign(params map[string]interface{}, appSecret string) string { // 获取所有键并排序 keys := make([]string, 0, len(params)) for k := range params { keys = append(keys, k) } sort.Strings(keys) // 拼接签名字符串 var signStr strings.Builder for _, k := range keys { // 跳过 sign 参数 if strings.ToLower(k) == "sign" { continue } // 获取参数值 value := "" if params[k] != nil { value = fmt.Sprintf("%v", params[k]) } // 按照文档格式:参数名+参数值 signStr.WriteString(k + value) } // 根据签名方法生成签名 signMethod := "md5" if method, ok := params["signMethod"].(string); ok { signMethod = strings.ToLower(method) } signString := signStr.String() // 使用MD5算法生成签名 if signMethod == "md5" { // MD5算法:md5(appSecret + signString + appSecret) data := appSecret + signString + appSecret hash := md5.Sum([]byte(data)) result := strings.ToUpper(fmt.Sprintf("%x", hash)) //fmt.Printf("Debug: MD5签名结果: %s\n", result) return result } return "" } // KwAPIResponse 孔网API响应结构体 type KwAPIResponse struct { ErrorResponse *ErrorResponse `json:"errorResponse"` // 错误响应 SuccessResponse []ShippingMethod `json:"successResponse"` // 成功响应 RequestId string `json:"requestId"` // 请求ID RequestMethod string `json:"requestMethod"` // 请求方法 } // ErrorResponse 孔网API错误响应结构体 type ErrorResponse struct { Code int `json:"code"` // 错误码 Msg string `json:"msg"` // 错误信息 SubCode *int `json:"subCode"` // 使用指针类型,因为可能是null SubMsg *string `json:"subMsg"` // 使用指针类型,因为可能是null } type ShippingMethod struct { ShippingId string `json:"shippingId"` // 配送方式ID ShippingName string `json:"shippingName"` // 配送方式名称 IsDefault bool `json:"isDefault"` // 是否默认配送方式 Companies []Company `json:"companies"` // 快递公司列表 } type Company struct { ShippingCom string `json:"shippingCom"` // 快递公司代号 ShippingComName string `json:"shippingComName"` // 快递公司名称 IsDefault bool `json:"isDefault"` // 是否默认 } /* * 获取配送方式列表 * param appId[int] appkey * param appSecret[string] app密钥 * param accessToken[string] 访问token * return 配送方式列表结构体字符串,错误信息 */ func kongfzDeliveryMethodList(appId int, appSecret, accessToken string) (string, error) { kUrl := fmt.Sprint("https://open.kongfz.com/router/rest") dateTime := getCurrentTimeGMT8() // 生成签名参数 params := map[string]interface{}{ "method": "kongfz.delivery.method.list", "appId": appId, "accessToken": accessToken, "datetime": dateTime, "format": "json", "v": "1.0", "signMethod": "md5", "simplify": 0, } // 生成签名 sign := generateSign(params, appSecret) // 构建请求体 formData := map[string]interface{}{ "method": "kongfz.delivery.method.list", "appId": appId, "accessToken": accessToken, "datetime": dateTime, "format": "json", "v": "1.0", "signMethod": "md5", "sign": sign, "simplify": 0, } // 发送POST请求 request := gorequest.New() resp, body, errs := request.Post(kUrl). 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", "*/*"). Set("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8"). Type("form"). // 关键:明确指定为表单格式 Timeout(30 * time.Second). Send(formData). End() // 错误处理 if len(errs) > 0 { return "", fmt.Errorf("登录请求失败: %v", errs) } // 检查HTTP状态码 if resp.StatusCode != 200 { return "", fmt.Errorf("HTTP状态码异常: %d, 响应: %s", resp.StatusCode, body) } // 解析响应 var response map[string]interface{} if err := json.Unmarshal([]byte(body), &response); err != nil { return "", fmt.Errorf("解析响应失败: %v, 响应内容: %s", err, body) } // 异常处理 if response["ErrorResponse"] != nil { var kwAPIResponse KwAPIResponse if err := json.Unmarshal([]byte(body), &kwAPIResponse); err != nil { return "", fmt.Errorf("解析 errorWrapper 失败: %v, 响应内容: %s", err, body) } return "", fmt.Errorf("请求失败: %v, 错误码: %d", kwAPIResponse.ErrorResponse.Msg, kwAPIResponse.ErrorResponse.Code) } // 转换成json字符串 responseJSON, err := json.Marshal(response) if err != nil { return "", fmt.Errorf("JSON序列化失败: %v", err) } return string(responseJSON), nil } /* * 订单发货 * param appId[int] appkey * param appSecret[string] app密钥 * param accessToken[string] 访问token * param orderId[int] 订单编号 * param shippingId[string] 配送方式 * param shippingCom[string] 快递公司。当shippingId!=noLogistics时,此参数为必填。 * param shipmentNum[string] 快递单号。当shippingId!=noLogistics时,此参数为必填。 * param userDefined[string] 用户自定义物流公司。当shippingCom=other时,此参数为必填。 * param moreShipmentNum[string] 填写更多的快递单号,以逗号分隔。 * return 订单发货结构体字符串,错误信息 */ func kongfzOrderDeliver(appId int, appSecret, accessToken string, orderId int, shippingId, shippingCom, shipmentNum, userDefined, moreShipmentNum string) (string, error) { kUrl := fmt.Sprint("https://open.kongfz.com/router/rest") dateTime := getCurrentTimeGMT8() // 参数验证 if shippingId != "noLogistics" { if shippingCom == "" { return "", fmt.Errorf("当 shippingId 不等于 noLogistics 时,shippingCom 参数为必填。shippingId是: %v", shippingId) } if shipmentNum == "" { return "", fmt.Errorf("当 shippingId 不等于 noLogistics 时, shipmentNum 参数为必填。shippingId是: %v", shippingId) } } if shipmentNum == "other" { if userDefined == "" { return "", fmt.Errorf("当 shippingCom 等于 other 时, userDefined 参数为必填。shipmentNum是: %v", shipmentNum) } } // 生成签名参数 params := map[string]interface{}{ "method": "kongfz.order.deliver", "appId": appId, "accessToken": accessToken, "datetime": dateTime, "format": "json", "v": "1.0", "signMethod": "md5", "simplify": 0, "orderId": orderId, "shippingId": shippingId, "shippingCom": shippingCom, "shipmentNum": shipmentNum, "userDefined": userDefined, "moreShipmentNum": moreShipmentNum, } // 生成签名 sign := generateSign(params, appSecret) // 构建请求体 formData := map[string]interface{}{ "method": "kongfz.order.deliver", "appId": appId, "accessToken": accessToken, "datetime": dateTime, "format": "json", "v": "1.0", "signMethod": "md5", "sign": sign, "simplify": 0, "orderId": orderId, "shippingId": shippingId, "shippingCom": shippingCom, "shipmentNum": shipmentNum, "userDefined": userDefined, "moreShipmentNum": moreShipmentNum, } // 发送POST请求 request := gorequest.New() resp, body, errs := request.Post(kUrl). 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", "*/*"). Set("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8"). Type("form"). // 关键:明确指定为表单格式 Timeout(30 * time.Second). Send(formData). End() // 错误处理 if len(errs) > 0 { return "", fmt.Errorf("登录请求失败: %v", errs) } // 检查HTTP状态码 if resp.StatusCode != 200 { return "", fmt.Errorf("HTTP状态码异常: %d, 响应: %s", resp.StatusCode, body) } // 解析响应 var response map[string]interface{} if err := json.Unmarshal([]byte(body), &response); err != nil { return "", fmt.Errorf("解析响应失败: %v, 响应内容: %s", err, body) } // 异常处理 if response["ErrorResponse"] != nil { var kwAPIResponse KwAPIResponse if err := json.Unmarshal([]byte(body), &kwAPIResponse); err != nil { return "", fmt.Errorf("解析 errorWrapper 失败: %v, 响应内容: %s", err, body) } return "", fmt.Errorf("请求失败: %v, 错误码: %d", kwAPIResponse.ErrorResponse.Msg, kwAPIResponse.ErrorResponse.Code) } // 转换成json字符串 responseJSON, err := json.Marshal(response) if err != nil { return "", fmt.Errorf("JSON序列化失败: %v", err) } return string(responseJSON), nil } /* * 孔网订单同步 * param appId[int] appkey * param appSecret[string] app密钥 * param accessToken[string] 访问token * param shippingComName[string] 快递公司名称 * param orderId[int] 订单编号 * param shippingId[string] 配送方式 * param shippingCom[string] 快递公司。当shippingId!=noLogistics时,此参数为必填。 * param shipmentNum[string] 快递单号。当shippingId!=noLogistics时,此参数为必填。 * param userDefined[string] 用户自定义物流公司。当shippingCom=other时,此参数为必填。 * param moreShipmentNum[string] 填写更多的快递单号,以逗号分隔。 * return 订单同步结构体字符串,错误信息 */ func kongfzOrderSynchronization(appId int, appSecret, accessToken string, shippingComName string, orderId int, shippingId, shippingCom, shipmentNum, userDefined, moreShipmentNum string) (string, error) { // 获取配送方式列表 deliveryMethodList, err := kongfzDeliveryMethodList(appId, appSecret, accessToken) if err != nil { return "", err } // 解析配送方式 var kw KwAPIResponse if err := json.Unmarshal([]byte(deliveryMethodList), &kw); err != nil { return "", fmt.Errorf("解析JSON失败: %v", err) } // 根据快递公司名称查找对应的配送方式和快递公司代号 for _, shippingMethod := range kw.SuccessResponse { //中国邮政 特殊处理 if shippingComName == "中国邮政" && shippingMethod.ShippingName == "快递包裹" { for _, companies := range shippingMethod.Companies { if companies.ShippingComName == "邮局" { shippingId = shippingMethod.ShippingId shippingCom = companies.ShippingCom } } } else { //正常快递 for _, companies := range shippingMethod.Companies { if shippingComName == companies.ShippingComName { shippingId = shippingMethod.ShippingId shippingCom = companies.ShippingCom } } } } // 如果未找到,使用默认值 if shippingId == "" { shippingId = "express" shippingCom = "other" userDefined = shippingComName } // 执行订单发货 orderDeliver, err := kongfzOrderDeliver(appId, appSecret, accessToken, orderId, shippingId, shippingCom, shipmentNum, userDefined, moreShipmentNum) if err != nil { return "", err } return orderDeliver, err } /* * 上传图片接口 * param appId[int] appKey * param appSecret[string] app密钥 * param accessToken[string] 访问token * param filePath[string] 图片url/本地图片路径 * param savePath[string] 图片下载路径,如果是图片url需要下载到本地 * return 上传图片响应结构体,错误信息 * Error 解析图片URL失败 * Error 读取文件失败 * Error 创建表单文件失败 * Error 写入文件数据失败 */ func kongfzImageUpload(appId int, appSecret, accessToken string, filePath, savePath string) (string, error) { var image string var needCleanup bool = false // 标记是否需要清理 defer func() { // 函数结束时删除临时图片 if needCleanup && image != "" { if err := os.Remove(image); err != nil { log.Printf("警告:删除临时图片失败 %s: %v", image, err) } else { log.Printf("已清理临时图片: %s", image) } } }() if strings.HasPrefix(filePath, "http://") || strings.HasPrefix(filePath, "https://") { // 解析URL parse, err := url.Parse(filePath) if err != nil { return "", fmt.Errorf("解析图片URL失败: %v", err) } // 获取路径部分 fPath := parse.Path // 获取文件名 fileName := path.Base(fPath) savePath = filepath.Join(savePath, fileName) image, err = downloadImage(filePath, savePath) if err != nil { return "", err } needCleanup = true // 标记需要清理 } else { // 本地文件 image = filePath // 本地文件不需要清理,由调用者管理 } kUrl := fmt.Sprint("https://open.kongfz.com/router/image/upload") dateTime := getCurrentTimeGMT8() // 生成签名参数 params := map[string]interface{}{ "method": "kongfz.image.upload", "appId": appId, "accessToken": accessToken, "datetime": dateTime, "format": "json", "v": "1.0", "signMethod": "md5", "simplify": 0, } params["bucket"] = "book" // 生成签名 sign := generateSign(params, appSecret) // 创建multipart/form-data请求体 body := &bytes.Buffer{} writer := multipart.NewWriter(body) // 读取文件内容 fileData, err := os.ReadFile(image) if err != nil { return "", fmt.Errorf("读取文件失败: %v", err) } // 添加文件字段 part, err := writer.CreateFormFile("image", filepath.Base(image)) if err != nil { return "", fmt.Errorf("创建表单文件失败: %v", err) } _, err = part.Write(fileData) if err != nil { return "", fmt.Errorf("写入文件数据失败: %v", err) } // 添加其他参数到multipart表单 for key, value := range params { writer.WriteField(key, fmt.Sprintf("%v", value)) } writer.WriteField("sign", sign) // 添加签名 writer.Close() // 关闭writer,完成表单构建 // 发送POST请求 request := gorequest.New() resp, respBody, errs := request.Post(kUrl). Timeout(30*time.Second). Set("Content-Type", writer.FormDataContentType()). // 设置Content-Type Send(body.String()). // 发送请求体 End() if len(errs) > 0 { return "", fmt.Errorf("请求失败: %v", errs) } if resp.StatusCode != 200 { return "", fmt.Errorf("HTTP状态码异常: %d, 响应: %s", resp.StatusCode, body) } // 解析响应 var response map[string]interface{} if err := json.Unmarshal([]byte(respBody), &response); err != nil { return "", fmt.Errorf("解析响应失败: %v, 响应内容: %s", err, body) } // 转换成json字符串 responseJSON, err := json.Marshal(response) if err != nil { return "", fmt.Errorf("JSON序列化失败: %v", err) } return string(responseJSON), nil } /* * 添加店铺商品 * param appId[int] appKey * param appSecret[string] app密钥 * param accessToken[string] 访问token * param shopItemAddJson[string] 店铺商品请求结构体字符串 * return 添加店铺商品响应结构体,错误信息 */ func kongfzShopItemAdd(appId int, appSecret, accessToken string, shopItemAddJson string) (string, error) { kUrl := fmt.Sprint("https://open.kongfz.com/router/rest") dateTime := getCurrentTimeGMT8() // 生成签名参数 params := map[string]interface{}{ "method": "kongfz.shop.item.add", "appId": appId, "accessToken": accessToken, "datetime": dateTime, "format": "json", "v": "1.0", "signMethod": "md5", "simplify": 0, } if shopItemAddJson == "" { return "", fmt.Errorf("shopItemAddJson 参数为空!") } toParams, err := addStructToParams(shopItemAddJson, params) if err != nil { return "", err } // 生成签名 sign := generateSign(toParams, appSecret) if sign == "" { return "", fmt.Errorf("生成 sign 签名错误!") } params["sign"] = sign marshal, _ := json.Marshal(params) fmt.Println(string(marshal)) request := gorequest.New() // 改为 POST 请求,并使用 TypeMultipartForm 或 TypeForm 格式提交 resp, body, errs := request.Post(kUrl). 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("Content-Type", "application/x-www-form-urlencoded"). // 设置表单格式 Timeout(30 * time.Second). Send(params). // gorequest 会自动将 map 转换为表单数据 End() if len(errs) > 0 { return "", fmt.Errorf("请求失败: %v", errs) } if resp.StatusCode != 200 { return "", fmt.Errorf("HTTP状态码异常: %d, 响应: %s", resp.StatusCode, body) } // 解析响应 var response map[string]interface{} if err := json.Unmarshal([]byte(body), &response); err != nil { return "", fmt.Errorf("解析响应失败: %v, 响应内容: %s", err, body) } // 转换成json字符串 responseJSON, err := json.Marshal(response) if err != nil { return "", fmt.Errorf("JSON序列化失败: %v", err) } return string(responseJSON), nil } // 订单修改发货单号 func kongfzOrderRedeliver(appId int, appSecret, accessToken, requestJson string) (string, error) { kUrl := fmt.Sprint("https://open.kongfz.com/router/rest") dateTime := getCurrentTimeGMT8() // 生成签名参数 params := map[string]interface{}{ "method": "kongfz.order.redeliver", "appId": appId, "accessToken": accessToken, "datetime": dateTime, "format": "json", "v": "1.0", "signMethod": "md5", "simplify": 0, } if requestJson == "" { return "", fmt.Errorf("orderListJson 参数为空!") } toParams, err := addStructToParams(requestJson, params) if err != nil { return "", err } // 生成签名 sign := generateSign(toParams, appSecret) if sign == "" { return "", fmt.Errorf("生成 sign 签名错误!") } params["sign"] = sign request := gorequest.New() resp, body, errs := request.Post(kUrl). 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("Content-Type", "application/x-www-form-urlencoded"). Timeout(30 * time.Second). Send(params). End() if len(errs) > 0 { return "", fmt.Errorf("请求失败: %v", errs) } if resp.StatusCode != 200 { return "", fmt.Errorf("HTTP状态码异常: %d, 响应: %s", resp.StatusCode, body) } // 解析响应 var response map[string]interface{} if err := json.Unmarshal([]byte(body), &response); err != nil { return "", fmt.Errorf("解析响应失败: %v, 响应内容: %s", err, body) } // 转换成json字符串 responseJSON, err := json.Marshal(response) if err != nil { return "", fmt.Errorf("JSON序列化失败: %v", err) } return string(responseJSON), nil } // 订单标记添加/修改 func kongfzOrderFlagAdd(appId int, appSecret, accessToken, requestJson string) (string, error) { kUrl := fmt.Sprint("https://open.kongfz.com/router/rest") dateTime := getCurrentTimeGMT8() // 生成签名参数 params := map[string]interface{}{ "method": "kongfz.order.flag.add", "appId": appId, "accessToken": accessToken, "datetime": dateTime, "format": "json", "v": "1.0", "signMethod": "md5", "simplify": 0, } if requestJson == "" { return "", fmt.Errorf("orderListJson 参数为空!") } toParams, err := addStructToParams(requestJson, params) if err != nil { return "", err } // 生成签名 sign := generateSign(toParams, appSecret) if sign == "" { return "", fmt.Errorf("生成 sign 签名错误!") } params["sign"] = sign request := gorequest.New() resp, body, errs := request.Post(kUrl). 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("Content-Type", "application/x-www-form-urlencoded"). Timeout(30 * time.Second). Send(params). End() if len(errs) > 0 { return "", fmt.Errorf("请求失败: %v", errs) } if resp.StatusCode != 200 { return "", fmt.Errorf("HTTP状态码异常: %d, 响应: %s", resp.StatusCode, body) } // 解析响应 var response map[string]interface{} if err := json.Unmarshal([]byte(body), &response); err != nil { return "", fmt.Errorf("解析响应失败: %v, 响应内容: %s", err, body) } // 转换成json字符串 responseJSON, err := json.Marshal(response) if err != nil { return "", fmt.Errorf("JSON序列化失败: %v", err) } return string(responseJSON), nil } // 订单标记删除 func kongfzOrderFlagDel(appId int, appSecret, accessToken, requestJson string) (string, error) { kUrl := fmt.Sprint("https://open.kongfz.com/router/rest") dateTime := getCurrentTimeGMT8() // 生成签名参数 params := map[string]interface{}{ "method": "kongfz.order.flag.del", "appId": appId, "accessToken": accessToken, "datetime": dateTime, "format": "json", "v": "1.0", "signMethod": "md5", "simplify": 0, } if requestJson == "" { return "", fmt.Errorf("orderListJson 参数为空!") } toParams, err := addStructToParams(requestJson, params) if err != nil { return "", err } // 生成签名 sign := generateSign(toParams, appSecret) if sign == "" { return "", fmt.Errorf("生成 sign 签名错误!") } params["sign"] = sign request := gorequest.New() resp, body, errs := request.Post(kUrl). 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("Content-Type", "application/x-www-form-urlencoded"). Timeout(30 * time.Second). Send(params). End() if len(errs) > 0 { return "", fmt.Errorf("请求失败: %v", errs) } if resp.StatusCode != 200 { return "", fmt.Errorf("HTTP状态码异常: %d, 响应: %s", resp.StatusCode, body) } // 解析响应 var response map[string]interface{} if err := json.Unmarshal([]byte(body), &response); err != nil { return "", fmt.Errorf("解析响应失败: %v, 响应内容: %s", err, body) } // 转换成json字符串 responseJSON, err := json.Marshal(response) if err != nil { return "", fmt.Errorf("JSON序列化失败: %v", err) } return string(responseJSON), nil } /* * 查询订单列表 * param appId[int] appKey * param appSecret[string] app密钥 * param accessToken[string] 访问token * param orderListJson[string] 查询订单请求结构体字符串 * return 添加店铺商品响应结构体,错误信息 */ func kongfzOrderList(appId int, appSecret, accessToken string, orderListJson string) (string, error) { kUrl := fmt.Sprint("https://open.kongfz.com/router/rest") dateTime := getCurrentTimeGMT8() // 生成签名参数 params := map[string]interface{}{ "method": "kongfz.order.list", "appId": appId, "accessToken": accessToken, "datetime": dateTime, "format": "json", "v": "1.0", "signMethod": "md5", "simplify": 0, } if orderListJson == "" { return "", fmt.Errorf("orderListJson 参数为空!") } toParams, err := addStructToParams(orderListJson, params) if err != nil { return "", err } // 生成签名 sign := generateSign(toParams, appSecret) if sign == "" { return "", fmt.Errorf("生成 sign 签名错误!") } params["sign"] = sign request := gorequest.New() resp, body, errs := request.Post(kUrl). 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("Content-Type", "application/x-www-form-urlencoded"). Timeout(30 * time.Second). Send(params). End() if len(errs) > 0 { return "", fmt.Errorf("请求失败: %v", errs) } if resp.StatusCode != 200 { return "", fmt.Errorf("HTTP状态码异常: %d, 响应: %s", resp.StatusCode, body) } // 解析响应 var response map[string]interface{} if err := json.Unmarshal([]byte(body), &response); err != nil { return "", fmt.Errorf("解析响应失败: %v, 响应内容: %s", err, body) } // 转换成json字符串 responseJSON, err := json.Marshal(response) if err != nil { return "", fmt.Errorf("JSON序列化失败: %v", err) } return string(responseJSON), nil } /* * 查询单个订单 * param appId[int] appKey * param appSecret[string] app密钥 * param accessToken[string] 访问token * param userType[string] 查询订单请求结构体字符串 * param orderId[string] 查询订单请求结构体字符串 * return 添加店铺商品响应结构体,错误信息 */ func kongfzOrderGet(appId int, appSecret, accessToken string, userType string, orderId int) (string, error) { kUrl := fmt.Sprint("https://open.kongfz.com/router/rest") dateTime := getCurrentTimeGMT8() // 生成签名参数 params := map[string]interface{}{ "method": "kongfz.order.get", "appId": appId, "accessToken": accessToken, "datetime": dateTime, "format": "json", "v": "1.0", "signMethod": "md5", "simplify": 0, } params["userType"] = userType params["orderId"] = strconv.Itoa(orderId) // 生成签名 sign := generateSign(params, appSecret) if sign == "" { return "", fmt.Errorf("生成 sign 签名错误!") } params["sign"] = sign request := gorequest.New() resp, body, errs := request.Post(kUrl). 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("Content-Type", "application/x-www-form-urlencoded"). Timeout(30 * time.Second). Send(params). End() if len(errs) > 0 { return "", fmt.Errorf("请求失败: %v", errs) } if resp.StatusCode != 200 { return "", fmt.Errorf("HTTP状态码异常: %d, 响应: %s", resp.StatusCode, body) } // 解析响应 var response map[string]interface{} if err := json.Unmarshal([]byte(body), &response); err != nil { return "", fmt.Errorf("解析响应失败: %v, 响应内容: %s", err, body) } // 转换成json字符串 responseJSON, err := json.Marshal(response) if err != nil { return "", fmt.Errorf("JSON序列化失败: %v", err) } return string(responseJSON), nil } // 获取店铺本店分类名称列表 // @param appId[int] appKey // @param appSecret[string] app密钥 // @param accessToken[string] 访问token // @return json字符串 // @return error 错误信息 func kongfzShopCategoryNameList(appId int, appSecret, accessToken string) (string, error) { kUrl := fmt.Sprint("https://open.kongfz.com/router/rest") dateTime := getCurrentTimeGMT8() // 生成签名参数 params := map[string]interface{}{ "method": "kongfz.shop.category.name.list", "appId": appId, "accessToken": accessToken, "datetime": dateTime, "format": "json", "v": "1.0", "signMethod": "md5", "simplify": 0, } // 生成签名 sign := generateSign(params, appSecret) if sign == "" { return "", fmt.Errorf("生成 sign 签名错误!") } params["sign"] = sign request := gorequest.New() resp, body, errs := request.Post(kUrl). 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("Content-Type", "application/x-www-form-urlencoded"). Timeout(30 * time.Second). Send(params). End() if len(errs) > 0 { return "", fmt.Errorf("请求失败: %v", errs) } if resp.StatusCode != 200 { return "", fmt.Errorf("HTTP状态码异常: %d, 响应: %s", resp.StatusCode, body) } // 解析响应 var response map[string]interface{} if err := json.Unmarshal([]byte(body), &response); err != nil { return "", fmt.Errorf("解析响应失败: %v, 响应内容: %s", err, body) } // 转换成json字符串 responseJSON, err := json.Marshal(response) if err != nil { return "", fmt.Errorf("JSON序列化失败: %v", err) } return string(responseJSON), nil } // 获取公用分类数据 // @param appId[int] appKey // @param appSecret[string] app密钥 // @param accessToken[string] 访问token // @return json字符串 // @return error 错误信息 func kongfzCommonCategory(appId int, appSecret, accessToken string) (string, error) { kUrl := fmt.Sprint("https://open.kongfz.com/router/rest") dateTime := getCurrentTimeGMT8() // 生成签名参数 params := map[string]interface{}{ "method": "kongfz.common.category", "appId": appId, "accessToken": accessToken, "datetime": dateTime, "format": "json", "v": "1.0", "signMethod": "md5", "simplify": 0, } // 生成签名 sign := generateSign(params, appSecret) if sign == "" { return "", fmt.Errorf("生成 sign 签名错误!") } params["sign"] = sign request := gorequest.New() resp, body, errs := request.Post(kUrl). 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("Content-Type", "application/x-www-form-urlencoded"). Timeout(30 * time.Second). Send(params). End() if len(errs) > 0 { return "", fmt.Errorf("请求失败: %v", errs) } if resp.StatusCode != 200 { return "", fmt.Errorf("HTTP状态码异常: %d, 响应: %s", resp.StatusCode, body) } // 解析响应 var response map[string]interface{} if err := json.Unmarshal([]byte(body), &response); err != nil { return "", fmt.Errorf("解析响应失败: %v, 响应内容: %s", err, body) } // 转换成json字符串 responseJSON, err := json.Marshal(response) if err != nil { return "", fmt.Errorf("JSON序列化失败: %v", err) } return string(responseJSON), nil } // 下架商品 func kongfzShopItemDelisting(appId int, appSecret, accessToken string, requestJson string) (string, error) { kUrl := fmt.Sprint("https://open.kongfz.com/router/rest") dateTime := getCurrentTimeGMT8() // 生成签名参数 params := map[string]interface{}{ "method": "kongfz.shop.item.delisting", "appId": appId, "accessToken": accessToken, "datetime": dateTime, "format": "json", "v": "1.0", "signMethod": "md5", "simplify": 0, } if requestJson == "" { return "", fmt.Errorf("requestJson 参数为空!") } toParams, err := addStructToParams(requestJson, params) if err != nil { return "", err } // 生成签名 sign := generateSign(toParams, appSecret) if sign == "" { return "", fmt.Errorf("生成 sign 签名错误!") } params["sign"] = sign request := gorequest.New() resp, body, errs := request.Post(kUrl). 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("Content-Type", "application/x-www-form-urlencoded"). Timeout(30 * time.Second). Send(params). End() if len(errs) > 0 { return "", fmt.Errorf("请求失败: %v", errs) } if resp.StatusCode != 200 { return "", fmt.Errorf("HTTP状态码异常: %d, 响应: %s", resp.StatusCode, body) } // 解析响应 var response map[string]interface{} if err := json.Unmarshal([]byte(body), &response); err != nil { return "", fmt.Errorf("解析响应失败: %v, 响应内容: %s", err, body) } // 转换成json字符串 responseJSON, err := json.Marshal(response) if err != nil { return "", fmt.Errorf("JSON序列化失败: %v", err) } return string(responseJSON), nil } // 查询店铺商品列表 func kongfzShopItemList(appId int, appSecret, accessToken string, requestJson string) (string, error) { kUrl := fmt.Sprint("https://open.kongfz.com/router/rest") dateTime := getCurrentTimeGMT8() // 生成签名参数 params := map[string]interface{}{ "method": "kongfz.shop.item.list", "appId": appId, "accessToken": accessToken, "datetime": dateTime, "format": "json", "v": "1.0", "signMethod": "md5", "simplify": 0, } if requestJson == "" { return "", fmt.Errorf("requestJson 参数为空!") } toParams, err := addStructToParams(requestJson, params) if err != nil { return "", err } // 生成签名 sign := generateSign(toParams, appSecret) if sign == "" { return "", fmt.Errorf("生成 sign 签名错误!") } params["sign"] = sign request := gorequest.New() resp, body, errs := request.Post(kUrl). 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("Content-Type", "application/x-www-form-urlencoded"). Timeout(30 * time.Second). Send(params). End() if len(errs) > 0 { return "", fmt.Errorf("请求失败: %v", errs) } if resp.StatusCode != 200 { return "", fmt.Errorf("HTTP状态码异常: %d, 响应: %s", resp.StatusCode, body) } // 解析响应 var response map[string]interface{} if err := json.Unmarshal([]byte(body), &response); err != nil { return "", fmt.Errorf("解析响应失败: %v, 响应内容: %s", err, body) } // 转换成json字符串 responseJSON, err := json.Marshal(response) if err != nil { return "", fmt.Errorf("JSON序列化失败: %v", err) } return string(responseJSON), nil } // 查询店铺商品详情 func kongfzShopItemDetail(appId int, appSecret, accessToken string, requestJson string) (string, error) { kUrl := fmt.Sprint("https://open.kongfz.com/router/rest") dateTime := getCurrentTimeGMT8() // 生成签名参数 params := map[string]interface{}{ "method": "kongfz.shop.item.detail", "appId": appId, "accessToken": accessToken, "datetime": dateTime, "format": "json", "v": "1.0", "signMethod": "md5", "simplify": 0, } if requestJson == "" { return "", fmt.Errorf("requestJson 参数为空!") } toParams, err := addStructToParams(requestJson, params) if err != nil { return "", err } // 生成签名 sign := generateSign(toParams, appSecret) if sign == "" { return "", fmt.Errorf("生成 sign 签名错误!") } params["sign"] = sign request := gorequest.New() resp, body, errs := request.Post(kUrl). 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("Content-Type", "application/x-www-form-urlencoded"). Timeout(30 * time.Second). Send(params). End() if len(errs) > 0 { return "", fmt.Errorf("请求失败: %v", errs) } if resp.StatusCode != 200 { return "", fmt.Errorf("HTTP状态码异常: %d, 响应: %s", resp.StatusCode, body) } // 解析响应 var response map[string]interface{} if err := json.Unmarshal([]byte(body), &response); err != nil { return "", fmt.Errorf("解析响应失败: %v, 响应内容: %s", err, body) } // 转换成json字符串 responseJSON, err := json.Marshal(response) if err != nil { return "", fmt.Errorf("JSON序列化失败: %v", err) } return string(responseJSON), nil } // 上架商品 func kongfzShopItemListing(appId int, appSecret, accessToken string, requestJson string) (string, error) { kUrl := fmt.Sprint("https://open.kongfz.com/router/rest") dateTime := getCurrentTimeGMT8() // 生成签名参数 params := map[string]interface{}{ "method": "kongfz.shop.item.listing", "appId": appId, "accessToken": accessToken, "datetime": dateTime, "format": "json", "v": "1.0", "signMethod": "md5", "simplify": 0, } if requestJson == "" { return "", fmt.Errorf("requestJson 参数为空!") } toParams, err := addStructToParams(requestJson, params) if err != nil { return "", err } // 生成签名 sign := generateSign(toParams, appSecret) if sign == "" { return "", fmt.Errorf("生成 sign 签名错误!") } params["sign"] = sign request := gorequest.New() resp, body, errs := request.Post(kUrl). 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("Content-Type", "application/x-www-form-urlencoded"). Timeout(30 * time.Second). Send(params). End() if len(errs) > 0 { return "", fmt.Errorf("请求失败: %v", errs) } if resp.StatusCode != 200 { return "", fmt.Errorf("HTTP状态码异常: %d, 响应: %s", resp.StatusCode, body) } // 解析响应 var response map[string]interface{} if err := json.Unmarshal([]byte(body), &response); err != nil { return "", fmt.Errorf("解析响应失败: %v, 响应内容: %s", err, body) } // 转换成json字符串 responseJSON, err := json.Marshal(response) if err != nil { return "", fmt.Errorf("JSON序列化失败: %v", err) } return string(responseJSON), nil } // 修改商品库存 func kongfzShopItemNumberUpdate(appId int, appSecret, accessToken string, requestJson string) (string, error) { kUrl := fmt.Sprint("https://open.kongfz.com/router/rest") dateTime := getCurrentTimeGMT8() // 生成签名参数 params := map[string]interface{}{ "method": "kongfz.shop.item.number.update", "appId": appId, "accessToken": accessToken, "datetime": dateTime, "format": "json", "v": "1.0", "signMethod": "md5", "simplify": 0, } if requestJson == "" { return "", fmt.Errorf("requestJson 参数为空!") } toParams, err := addStructToParams(requestJson, params) if err != nil { return "", err } // 生成签名 sign := generateSign(toParams, appSecret) if sign == "" { return "", fmt.Errorf("生成 sign 签名错误!") } params["sign"] = sign request := gorequest.New() resp, body, errs := request.Post(kUrl). 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("Content-Type", "application/x-www-form-urlencoded"). Timeout(30 * time.Second). Send(params). End() if len(errs) > 0 { return "", fmt.Errorf("请求失败: %v", errs) } if resp.StatusCode != 200 { return "", fmt.Errorf("HTTP状态码异常: %d, 响应: %s", resp.StatusCode, body) } // 解析响应 var response map[string]interface{} if err := json.Unmarshal([]byte(body), &response); err != nil { return "", fmt.Errorf("解析响应失败: %v, 响应内容: %s", err, body) } // 转换成json字符串 responseJSON, err := json.Marshal(response) if err != nil { return "", fmt.Errorf("JSON序列化失败: %v", err) } return string(responseJSON), nil } // 修改商品价格 func kongfzShopItemPriceUpdate(appId int, appSecret, accessToken string, requestJson string) (string, error) { kUrl := fmt.Sprint("https://open.kongfz.com/router/rest") dateTime := getCurrentTimeGMT8() // 生成签名参数 params := map[string]interface{}{ "method": "kongfz.shop.item.price.update", "appId": appId, "accessToken": accessToken, "datetime": dateTime, "format": "json", "v": "1.0", "signMethod": "md5", "simplify": 0, } if requestJson == "" { return "", fmt.Errorf("requestJson 参数为空!") } toParams, err := addStructToParams(requestJson, params) if err != nil { return "", err } // 生成签名 sign := generateSign(toParams, appSecret) if sign == "" { return "", fmt.Errorf("生成 sign 签名错误!") } params["sign"] = sign request := gorequest.New() resp, body, errs := request.Post(kUrl). 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("Content-Type", "application/x-www-form-urlencoded"). Timeout(30 * time.Second). Send(params). End() if len(errs) > 0 { return "", fmt.Errorf("请求失败: %v", errs) } if resp.StatusCode != 200 { return "", fmt.Errorf("HTTP状态码异常: %d, 响应: %s", resp.StatusCode, body) } // 解析响应 var response map[string]interface{} if err := json.Unmarshal([]byte(body), &response); err != nil { return "", fmt.Errorf("解析响应失败: %v, 响应内容: %s", err, body) } // 转换成json字符串 responseJSON, err := json.Marshal(response) if err != nil { return "", fmt.Errorf("JSON序列化失败: %v", err) } return string(responseJSON), nil } // 删除商品到回收站 func kongfzShopItemDelete(appId int, appSecret, accessToken string, requestJson string) (string, error) { kUrl := fmt.Sprint("https://open.kongfz.com/router/rest") dateTime := getCurrentTimeGMT8() // 生成签名参数 params := map[string]interface{}{ "method": "kongfz.shop.item.delete", "appId": appId, "accessToken": accessToken, "datetime": dateTime, "format": "json", "v": "1.0", "signMethod": "md5", "simplify": 0, } if requestJson == "" { return "", fmt.Errorf("requestJson 参数为空!") } toParams, err := addStructToParams(requestJson, params) if err != nil { return "", err } // 生成签名 sign := generateSign(toParams, appSecret) if sign == "" { return "", fmt.Errorf("生成 sign 签名错误!") } params["sign"] = sign request := gorequest.New() resp, body, errs := request.Post(kUrl). 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("Content-Type", "application/x-www-form-urlencoded"). Timeout(30 * time.Second). Send(params). End() if len(errs) > 0 { return "", fmt.Errorf("请求失败: %v", errs) } if resp.StatusCode != 200 { return "", fmt.Errorf("HTTP状态码异常: %d, 响应: %s", resp.StatusCode, body) } // 解析响应 var response map[string]interface{} if err := json.Unmarshal([]byte(body), &response); err != nil { return "", fmt.Errorf("解析响应失败: %v, 响应内容: %s", err, body) } // 转换成json字符串 responseJSON, err := json.Marshal(response) if err != nil { return "", fmt.Errorf("JSON序列化失败: %v", err) } return string(responseJSON), nil } // =============== 辅助函数 ============== /* * 将结构体的字段添加到 params 映射中 * param req[string] 需要合并的json字符串 * param params[map[string]interface{}] 合并的map * return map响应结构体,错误信息 */ func addStructToParams(req string, params map[string]interface{}) (map[string]interface{}, error) { // 将JSON字符串解析为map var tempMap map[string]interface{} if err := json.Unmarshal([]byte(req), &tempMap); err != nil { return nil, fmt.Errorf("解析 req json失败:%v ", err) } // 合并到params for k, v := range tempMap { // 只添加非nil的值 if v != nil { params[k] = v } } return params, nil } /* * 下载图片到本地 * param filePath[string] 文件路径 * param savePath[string] 需要保存的路径 * return 本地图片路径,错误信息 */ func downloadImage(filePath, savePath string) (string, error) { // 创建HTTP请求 request := gorequest.New() resp, body, err := request.Get(filePath). Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"). EndBytes() if err != nil { return "", fmt.Errorf("请求失败: %v", err) } if resp.StatusCode != 200 { return "", fmt.Errorf("HTTP 状态码错误: %d", resp.StatusCode) } errs := os.WriteFile(savePath, body, 0644) if errs != nil { return "", fmt.Errorf("保存文件失败: %v", errs) } return savePath, nil } /* * 获取GMT+8当前时间的字符串格式 * return 返回时间字符串,格式:2006-01-02 15:04:05 */ func getCurrentTimeGMT8() string { // 创建北京时间(GMT+8) loc, err := time.LoadLocation("Asia/Shanghai") if err != nil { loc = time.FixedZone("GMT+8", 8*60*60) } now := time.Now().In(loc) return now.Format("2006-01-02 15:04:05") } /* * 替换所有空白字符为空格 * return 返回字符串 */ func cleanString(s string) string { s = strings.ReplaceAll(s, "\n", "") s = strings.ReplaceAll(s, "\r", "") s = strings.ReplaceAll(s, "\t", "") s = strings.ReplaceAll(s, " ", "") return removeDuplicates(s) } /* * 字符串去重 * return 返回字符串 */ func removeDuplicates(s string) string { seen := make(map[rune]bool) var result strings.Builder for _, r := range s { if !seen[r] { seen[r] = true result.WriteRune(r) } } return result.String() } /* * 验证日期格式并转换为时间戳 * param dateStr[string] 时间字符串 * return 时间戳 */ 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() } // 初始化配置--暂时没用 func initializeConfig(config Config) { // 设置全局配置 cf = config } // =================== C 导出函数 ======================= // OutKfzLogin 孔网登录 // //export OutKfzLogin func OutKfzLogin(username, password *C.char) *C.char { goUsername := C.GoString(username) goPassword := C.GoString(password) respToken, err := outKfzLogin(goUsername, goPassword) // 构建响应数据 resp := struct { Token string `json:"token"` }{ Token: respToken, } // 构建API响应 var apiResponse APIResponse if err != nil { apiResponse = APIResponse{ Success: false, Message: err.Error(), } } else { apiResponse = APIResponse{ Success: true, Data: resp, } } // 转换为JSON字符串 jsonData, marshalErr := json.Marshal(apiResponse) if marshalErr != nil { // 如果JSON序列化失败,返回错误信息 apiResponse = APIResponse{ Success: false, Message: fmt.Sprintf("JSON序列化失败: %v", marshalErr), } errorJson, _ := json.Marshal(apiResponse) return C.CString(string(errorJson)) } return C.CString(string(jsonData)) } // OutKfzGetUserInfo 获取孔网用户信息 // //export OutKfzGetUserInfo func OutKfzGetUserInfo(token *C.char) *C.char { goToken := C.GoString(token) userInfo, err := outKfzGetUserInfo(goToken) // 构建API响应 var apiResponse APIResponse if err != nil { apiResponse = APIResponse{ Success: false, Message: err.Error(), } } else { apiResponse = APIResponse{ Success: true, Data: userInfo, } } // 转换为JSON字符串 jsonData, marshalErr := json.Marshal(apiResponse) if marshalErr != nil { // 如果JSON序列化失败,返回错误信息 apiResponse = APIResponse{ Success: false, Message: fmt.Sprintf("JSON序列化失败: %v", marshalErr), } errorJson, _ := json.Marshal(apiResponse) return C.CString(string(errorJson)) } return C.CString(string(jsonData)) } // OutGetKfzShippingTemplate 获取运费模板信息 // //export OutGetKfzShippingTemplate func OutGetKfzShippingTemplate(token *C.char) *C.char { tokenStr := C.GoString(token) template, err := outGetKfzShippingTemplate(tokenStr) // 构建API响应 var apiResponse APIResponse if err != nil { apiResponse = APIResponse{ Success: false, Message: err.Error(), } } else { apiResponse = APIResponse{ Success: true, Data: template, } } // 转换为JSON字符串 jsonData, marshalErr := json.Marshal(apiResponse) if marshalErr != nil { // 如果JSON序列化失败,返回错误信息 apiResponse = APIResponse{ Success: false, Message: fmt.Sprintf("JSON序列化失败: %v", marshalErr), } errorJson, _ := json.Marshal(apiResponse) return C.CString(string(errorJson)) } return C.CString(string(jsonData)) } // OutGetGoodsTplMsg 获取商品模版--已登的店铺 // //export OutGetGoodsTplMsg func OutGetGoodsTplMsg(token, proxy, itemId *C.char) *C.char { goToken := C.GoString(token) goProxy := C.GoString(proxy) goItemId := C.GoString(itemId) info, err := outGetGoodsTplMsg(goToken, goProxy, goItemId) // 构建API响应 var apiResponse APIResponse if err != nil { apiResponse = APIResponse{ Success: false, Message: err.Error(), } } else { apiResponse = APIResponse{ Success: true, Data: info, } } // 转换为JSON字符串 jsonData, marshalErr := json.Marshal(apiResponse) if marshalErr != nil { // 如果JSON序列化失败,返回错误信息 apiResponse = APIResponse{ Success: false, Message: fmt.Sprintf("JSON序列化失败: %v", marshalErr), } errorJson, _ := json.Marshal(apiResponse) return C.CString(string(errorJson)) } return C.CString(string(jsonData)) } // OutGetGoodsListMsgFromSelfShop 获取商品列表-已登的店铺 // //export OutGetGoodsListMsgFromSelfShop func OutGetGoodsListMsgFromSelfShop(token, proxy, itemSn, mouldId, priceMin, priceMax *C.char, startCreateTime *C.char, endCreateTime *C.char, requestType *C.char, isItemSnEqual C.int, page C.int, size C.int) *C.char { goToken := C.GoString(token) goProxy := C.GoString(proxy) goItemSn := C.GoString(itemSn) goMouldId := C.GoString(mouldId) goPriceMin := C.GoString(priceMin) goPriceMax := C.GoString(priceMax) goStartCreateTime := C.GoString(startCreateTime) goEndCreateTime := C.GoString(endCreateTime) goRequestType := C.GoString(requestType) goIsItemSnEqual := int(isItemSnEqual) goPage := int(page) goSize := int(size) info, err := outGetGoodsListMsgFromSelfShop(goToken, goProxy, goItemSn, goMouldId, goPriceMin, goPriceMax, goStartCreateTime, goEndCreateTime, goRequestType, goIsItemSnEqual, goPage, goSize) // 构建API响应 var apiResponse APIResponse if err != nil { apiResponse = APIResponse{ Success: false, Message: err.Error(), } } else { apiResponse = APIResponse{ Success: true, Data: info, } } // 转换为JSON字符串 jsonData, marshalErr := json.Marshal(apiResponse) if marshalErr != nil { // 如果JSON序列化失败,返回错误信息 apiResponse = APIResponse{ Success: false, Message: fmt.Sprintf("JSON序列化失败: %v", marshalErr), } errorJson, _ := json.Marshal(apiResponse) return C.CString(string(errorJson)) } return C.CString(string(jsonData)) } // OutGetTplFields 获取模板字段 // //export OutGetTplFields func OutGetTplFields(token, proxy, itemId *C.char) *C.char { tokenStr := C.GoString(token) proxyStr := C.GoString(proxy) itemIdStr := C.GoString(itemId) info, err := outGetTplFields(tokenStr, proxyStr, itemIdStr) // 构建API响应 var apiResponse APIResponse if err != nil { apiResponse = APIResponse{ Success: false, Message: err.Error(), } } else { apiResponse = APIResponse{ Success: true, Data: info, } } // 转换为JSON字符串 jsonData, marshalErr := json.Marshal(apiResponse) if marshalErr != nil { // 如果JSON序列化失败,返回错误信息 apiResponse = APIResponse{ Success: false, Message: fmt.Sprintf("JSON序列化失败: %v", marshalErr), } errorJson, _ := json.Marshal(apiResponse) return C.CString(string(errorJson)) } return C.CString(string(jsonData)) } // OutAddGoods 新增商品-已登的店铺 // //export OutAddGoods func OutAddGoods(token, proxy, formData *C.char) *C.char { goToken := C.GoString(token) goProxy := C.GoString(proxy) goFormData := C.GoString(formData) info, err := outAddGoods(goToken, goProxy, goFormData) // 构建API响应 var apiResponse APIResponse if err != nil { apiResponse = APIResponse{ Success: false, Message: err.Error(), } } else { apiResponse = APIResponse{ Success: true, Data: info, } } // 转换为JSON字符串 jsonData, marshalErr := json.Marshal(apiResponse) if marshalErr != nil { // 如果JSON序列化失败,返回错误信息 apiResponse = APIResponse{ Success: false, Message: fmt.Sprintf("JSON序列化失败: %v", marshalErr), } errorJson, _ := json.Marshal(apiResponse) return C.CString(string(errorJson)) } return C.CString(string(jsonData)) } // OutUpdateGoodsPrice 修改商品价格-已登的店铺--核价软件用 // //export OutUpdateGoodsPrice func OutUpdateGoodsPrice(token, proxy, itemId, updateType, value *C.char) *C.char { tokenStr := C.GoString(token) proxyStr := C.GoString(proxy) itemIdStr := C.GoString(itemId) updateTypeStr := C.GoString(updateType) valueStr := C.GoString(value) info, err := outUpdateGoodsPrice(tokenStr, proxyStr, itemIdStr, updateTypeStr, valueStr) // 构建API响应 var apiResponse APIResponse if err != nil { apiResponse = APIResponse{ Success: false, Message: err.Error(), } } else { apiResponse = APIResponse{ Success: true, Data: info["result"], } } // 转换为JSON字符串 jsonData, marshalErr := json.Marshal(apiResponse) if marshalErr != nil { // 如果JSON序列化失败,返回错误信息 apiResponse = APIResponse{ Success: false, Message: fmt.Sprintf("JSON序列化失败: %v", marshalErr), } errorJson, _ := json.Marshal(apiResponse) return C.CString(string(errorJson)) } return C.CString(string(jsonData)) } // OutGetBaseSelectData 获取孔网商品列表查询下拉选项--已登的店铺--店铺商品列表查询中下拉选项数据--孔网核价软件用 // //export OutGetBaseSelectData func OutGetBaseSelectData(token *C.char) *C.char { tokenStr := C.GoString(token) info, err := outGetBaseSelectData(tokenStr) // 构建API响应 var apiResponse APIResponse if err != nil { apiResponse = APIResponse{ Success: false, Message: err.Error(), } } else { apiResponse = APIResponse{ Success: true, Data: info["result"], } } // 转换为JSON字符串 jsonData, marshalErr := json.Marshal(apiResponse) if marshalErr != nil { // 如果JSON序列化失败,返回错误信息 apiResponse = APIResponse{ Success: false, Message: fmt.Sprintf("JSON序列化失败: %v", marshalErr), } errorJson, _ := json.Marshal(apiResponse) return C.CString(string(errorJson)) } return C.CString(string(jsonData)) } // OutAddGoodsAndFile 整合添加商品和获取孔网图片 // //export OutAddGoodsAndFile func OutAddGoodsAndFile(token, proxy, filePath, formData *C.char) *C.char { goToken := C.GoString(token) goProxy := C.GoString(proxy) goFilePath := C.GoString(filePath) goFormData := C.GoString(formData) addGoodsAndFile, err := outAddGoodsAndFile(goToken, goProxy, goFilePath, goFormData) if err != nil { return C.CString(fmt.Sprint(err)) } return C.CString(addGoodsAndFile) } // OutDelGoodsFromSelfShop 删除商品-已登的店铺 // //export OutDelGoodsFromSelfShop func OutDelGoodsFromSelfShop(token, proxy, itemId *C.char) *C.char { goToken := C.GoString(token) goProxy := C.GoString(proxy) goItemId := C.GoString(itemId) info, err := outDelGoodsFromSelfShop(goToken, goProxy, goItemId) // 构建API响应 var apiResponse APIResponse if err != nil { apiResponse = APIResponse{ Success: false, Message: err.Error(), } } else { apiResponse = APIResponse{ Success: true, Data: info, } } // 转换为JSON字符串 jsonData, marshalErr := json.Marshal(apiResponse) if marshalErr != nil { // 如果JSON序列化失败,返回错误信息 apiResponse = APIResponse{ Success: false, Message: fmt.Sprintf("JSON序列化失败: %v", marshalErr), } errorJson, _ := json.Marshal(apiResponse) return C.CString(string(errorJson)) } return C.CString(string(jsonData)) } // OutGetImageFilterShopId 获取孔网商品图片和信息(官图和拍图)-带有店铺过滤 // //export OutGetImageFilterShopId func OutGetImageFilterShopId(token, proxy, isbn *C.char, shopId C.int, isLiveImage C.int, isReturnMsg C.int) *C.char { goToken := C.GoString(token) goProxy := C.GoString(proxy) goIsbn := C.GoString(isbn) goShopId := int(shopId) goIsLiveImage := int(isLiveImage) goIsReturnMsg := int(isReturnMsg) info, err := outGetImageFilterShopId(goToken, goProxy, goIsbn, goShopId, goIsLiveImage, goIsReturnMsg) // 构建API响应 var apiResponse APIResponse if err != nil { apiResponse = APIResponse{ Success: false, Message: err.Error(), } } else { apiResponse = APIResponse{ Success: true, Data: info, } } // 转换为JSON字符串 jsonData, marshalErr := json.Marshal(apiResponse) if marshalErr != nil { // 如果JSON序列化失败,返回错误信息 apiResponse = APIResponse{ Success: false, Message: fmt.Sprintf("JSON序列化失败: %v", marshalErr), } errorJson, _ := json.Marshal(apiResponse) return C.CString(string(errorJson)) } return C.CString(string(jsonData)) } // OutGetImageByIsbn 获取孔网商品图片和信息(官图和拍图) // //export OutGetImageByIsbn func OutGetImageByIsbn(token, proxy, isbn *C.char, isLiveImage C.int, isReturnMsg C.int) *C.char { goToken := C.GoString(token) goProxy := C.GoString(proxy) goIsbn := C.GoString(isbn) goIsLiveImage := int(isLiveImage) goIsReturnMsg := int(isReturnMsg) bookInfo, err := outGetImageByIsbn(goToken, goProxy, goIsbn, goIsLiveImage, goIsReturnMsg) // 构建API响应 var apiResponse APIResponse if err != nil { apiResponse = APIResponse{ Success: false, Message: err.Error(), } } else { apiResponse = APIResponse{ Success: true, Data: bookInfo, } } // 转换为JSON字符串 jsonData, marshalErr := json.Marshal(apiResponse) if marshalErr != nil { // 如果JSON序列化失败,返回错误信息 apiResponse = APIResponse{ Success: false, Message: fmt.Sprintf("JSON序列化失败: %v", marshalErr), } errorJson, _ := json.Marshal(apiResponse) return C.CString(string(errorJson)) } return C.CString(string(jsonData)) } // OutGetAllGoods 爬取孔网所有商品页面 // //export OutGetAllGoods func OutGetAllGoods(token, proxy *C.char, queryIndex C.int, isbn, quality, itemName, author, press *C.char) *C.char { tokenStr := C.GoString(token) proxyStr := C.GoString(proxy) queryIndexInt := int(queryIndex) isbnStr := C.GoString(isbn) qualityStr := C.GoString(quality) itemNameStr := C.GoString(itemName) authorStr := C.GoString(author) pressStr := C.GoString(press) info, err := outGetAllGoods(tokenStr, proxyStr, queryIndexInt, isbnStr, qualityStr, itemNameStr, authorStr, pressStr) // 构建统一格式的响应 var apiResponse APIResponse if err != nil { apiResponse = APIResponse{ Success: false, Message: err.Error(), } } else { apiResponse = APIResponse{ Success: true, Data: info, } } // 转换为JSON字符串 jsonData, marshalErr := json.Marshal(apiResponse) if marshalErr != nil { // 如果JSON序列化失败,返回错误信息 apiResponse = APIResponse{ Success: false, Message: fmt.Sprintf("JSON序列化失败: %v", marshalErr), } errorJson, _ := json.Marshal(apiResponse) return C.CString(string(errorJson)) } return C.CString(string(jsonData)) } // OutGetMidDetail 爬取孔网 https://item.kongfz.com/book/42291389.html 网址商品信息 // //export OutGetMidDetail func OutGetMidDetail(token, mid *C.char) *C.char { goToken := C.GoString(token) gomid := C.GoString(mid) bookInfo, err := outGetMidDetail(goToken, gomid) // 构建API响应 var apiResponse APIResponse if err != nil { apiResponse = APIResponse{ Success: false, Message: err.Error(), } } else { apiResponse = APIResponse{ Success: true, Data: bookInfo, } } // 转换为JSON字符串 jsonData, marshalErr := json.Marshal(apiResponse) if marshalErr != nil { // 如果JSON序列化失败,返回错误信息 apiResponse = APIResponse{ Success: false, Message: fmt.Sprintf("JSON序列化失败: %v", marshalErr), } errorJson, _ := json.Marshal(apiResponse) return C.CString(string(errorJson)) } return C.CString(string(jsonData)) } // OutGetGoodsListMsgByShopId 获取商品列表通过店铺ID // //export OutGetGoodsListMsgByShopId func OutGetGoodsListMsgByShopId(token *C.char, shopId C.int, proxy *C.char, retPrice C.int, isImage C.int, sortType *C.char, sort *C.char, priceMin C.float, priceMax C.float, pageNum, returnNum C.int) *C.char { goToken := C.GoString(token) goShopId := int(shopId) goProxy := C.GoString(proxy) goRetPrice := int(retPrice) goIsImage := int(isImage) goSortType := C.GoString(sortType) goSort := C.GoString(sort) goPriceMin := float32(priceMin) goPriceMax := float32(priceMax) goPageNum := int(pageNum) goReturnNum := int(returnNum) books, num, pNum, err := outGetGoodsListMsgByShopId(goToken, goShopId, goProxy, goRetPrice, goIsImage, goSortType, goSort, goPriceMin, goPriceMax, goPageNum, goReturnNum) // 构建统一格式的响应 bookInfo := struct { GoodsNum string `json:"goods_num,omitempty"` PNum string `json:"pnum,omitempty"` BookInfo interface{} `json:"book_info,omitempty"` }{ GoodsNum: num, PNum: pNum, BookInfo: books, } // 构建API响应 var apiResponse APIResponse if err != nil { apiResponse = APIResponse{ Success: false, Message: err.Error(), } } else { apiResponse = APIResponse{ Success: true, Data: bookInfo, } } // 转换为JSON字符串 jsonData, marshalErr := json.Marshal(apiResponse) if marshalErr != nil { // 如果JSON序列化失败,返回错误信息 apiResponse = APIResponse{ Success: false, Message: fmt.Sprintf("JSON序列化失败: %v", marshalErr), } errorJson, _ := json.Marshal(apiResponse) return C.CString(string(errorJson)) } return C.CString(string(jsonData)) } // OutGetHisGoodsList 获取孔网他店商品数据列表--他店的商品 // //export OutGetHisGoodsList func OutGetHisGoodsList(token, shopId, proxy, retPrice, isImage, sortType, sort, priceMin, priceMax *C.char, pageNum, returnNum C.int) *C.char { tokenStr := C.GoString(token) shopIdStr := C.GoString(shopId) proxyStr := C.GoString(proxy) retPriceStr := C.GoString(retPrice) isImageStr := C.GoString(isImage) sortTypeStr := C.GoString(sortType) sortStr := C.GoString(sort) priceMinStr := C.GoString(priceMin) priceMaxStr := C.GoString(priceMax) pageNumInt := int(pageNum) returnNumInt := int(returnNum) books, num, pNum, err := outGetHisGoodsList(tokenStr, shopIdStr, proxyStr, retPriceStr, isImageStr, sortTypeStr, sortStr, priceMinStr, priceMaxStr, pageNumInt, returnNumInt) // 构建统一格式的响应 bookInfo := struct { GoodsNum string `json:"goods_num,omitempty"` PNum string `json:"p_num,omitempty"` BookInfo interface{} `json:"book_info,omitempty"` }{ GoodsNum: num, PNum: pNum, BookInfo: books, } // 构建API响应 var apiResponse APIResponse if err != nil { apiResponse = APIResponse{ Success: false, Message: err.Error(), } } else { apiResponse = APIResponse{ Success: true, Data: bookInfo, } } // 转换为JSON字符串 jsonData, marshalErr := json.Marshal(apiResponse) if marshalErr != nil { // 如果JSON序列化失败,返回错误信息 apiResponse = APIResponse{ Success: false, Message: fmt.Sprintf("JSON序列化失败: %v", marshalErr), } errorJson, _ := json.Marshal(apiResponse) return C.CString(string(errorJson)) } return C.CString(string(jsonData)) } // OutGetGoodsMsgByDetailUrl 获取商品信息通过商品详情链接 // //export OutGetGoodsMsgByDetailUrl func OutGetGoodsMsgByDetailUrl(detailUrl, proxy *C.char) *C.char { goDetailUrl := C.GoString(detailUrl) goProxy := C.GoString(proxy) response, err := outGetGoodsMsgByDetailUrl(goDetailUrl, goProxy) // 构建统一格式的响应 var apiResponse APIResponse if err != nil { apiResponse = APIResponse{ Success: false, Message: err.Error(), } } else { apiResponse = APIResponse{ Success: true, Data: response, } } // 转换为JSON字符串 jsonData, marshalErr := json.Marshal(apiResponse) if marshalErr != nil { // 如果JSON序列化失败,返回错误信息 apiResponse = APIResponse{ Success: false, Message: fmt.Sprintf("JSON序列化失败: %v", marshalErr), } errorJson, _ := json.Marshal(apiResponse) return C.CString(string(errorJson)) } return C.CString(string(jsonData)) } // OutGetTopGoodsListMsg 获取销量榜商品列表 // //export OutGetTopGoodsListMsg func OutGetTopGoodsListMsg(catId C.int, proxy *C.char) *C.char { goCatId := int(catId) goProxy := C.GoString(proxy) response, err := outGetTopGoodsListMsg(goCatId, goProxy) // 构建统一格式的响应 var apiResponse APIResponse if err != nil { apiResponse = APIResponse{ Success: false, Message: err.Error(), } } else { apiResponse = APIResponse{ Success: true, Data: response, } } // 转换为JSON字符串 jsonData, marshalErr := json.Marshal(apiResponse) if marshalErr != nil { // 如果JSON序列化失败,返回错误信息 apiResponse = APIResponse{ Success: false, Message: fmt.Sprintf("JSON序列化失败: %v", marshalErr), } errorJson, _ := json.Marshal(apiResponse) return C.CString(string(errorJson)) } return C.CString(string(jsonData)) } // KongfzDeliveryMethodList 获取配送方式列表 // //export KongfzDeliveryMethodList func KongfzDeliveryMethodList(appId C.int, appSecret, accessToken *C.char) *C.char { goAppId := int(appId) goAppSecret := C.GoString(appSecret) goAccessToken := C.GoString(accessToken) list, err := kongfzDeliveryMethodList(goAppId, goAppSecret, goAccessToken) if err != nil { return C.CString(fmt.Sprint(err)) } return C.CString(list) } // KongfzOrderDeliver 订单发货 // //export KongfzOrderDeliver func KongfzOrderDeliver(appId C.int, appSecret, accessToken *C.char, orderId C.int, shippingId, shippingCom, shipmentNum, userDefined, moreShipmentNum *C.char) *C.char { goAppId := int(appId) goAppSecret := C.GoString(appSecret) goAccessToken := C.GoString(accessToken) goOrderId := int(orderId) goShippingId := C.GoString(shippingId) goShippingCom := C.GoString(shippingCom) goShipmentNum := C.GoString(shipmentNum) goUserDefined := C.GoString(userDefined) goMoreShipmentNum := C.GoString(moreShipmentNum) deliver, err := kongfzOrderDeliver(goAppId, goAppSecret, goAccessToken, goOrderId, goShippingId, goShippingCom, goShipmentNum, goUserDefined, goMoreShipmentNum) if err != nil { return C.CString(fmt.Sprint(err)) } return C.CString(deliver) } // KongfzOrderSynchronization 孔网订单同步 // //export KongfzOrderSynchronization func KongfzOrderSynchronization(appId C.int, appSecret, accessToken, shippingComName *C.char, orderId C.int, shippingId, shippingCom, shipmentNum, userDefined, moreShipmentNum *C.char) *C.char { goAppId := int(appId) goAppSecret := C.GoString(appSecret) goAccessToken := C.GoString(accessToken) goShippingComName := C.GoString(shippingComName) goOrderId := int(orderId) goShippingId := C.GoString(shippingId) goShippingCom := C.GoString(shippingCom) goShipmentNum := C.GoString(shipmentNum) goUserDefined := C.GoString(userDefined) goMoreShipmentNum := C.GoString(moreShipmentNum) synchronization, err := kongfzOrderSynchronization(goAppId, goAppSecret, goAccessToken, goShippingComName, goOrderId, goShippingId, goShippingCom, goShipmentNum, goUserDefined, goMoreShipmentNum) if err != nil { return C.CString(fmt.Sprint(err)) } return C.CString(synchronization) } // KongfzImageUpload 上传图片接口 // //export KongfzImageUpload func KongfzImageUpload(appId C.int, appSecret, accessToken, filePath, savePath *C.char) *C.char { goAppId := int(appId) goAppSecret := C.GoString(appSecret) goAccessToken := C.GoString(accessToken) goFilePath := C.GoString(filePath) goSavePath := C.GoString(savePath) upload, err := kongfzImageUpload(goAppId, goAppSecret, goAccessToken, goFilePath, goSavePath) if err != nil { return C.CString(fmt.Sprint(err)) } return C.CString(upload) } // KongfzShopItemAdd 添加店铺商品 // //export KongfzShopItemAdd func KongfzShopItemAdd(appId C.int, appSecret, accessToken, shopItemAddJson *C.char) *C.char { goAppId := int(appId) goAppSecret := C.GoString(appSecret) goAccessToken := C.GoString(accessToken) goShopItemAddJson := C.GoString(shopItemAddJson) upload, err := kongfzShopItemAdd(goAppId, goAppSecret, goAccessToken, goShopItemAddJson) if err != nil { return C.CString(fmt.Sprint(err)) } return C.CString(upload) } // KongfzOrderList 查询订单列表 // //export KongfzOrderList func KongfzOrderList(appId C.int, appSecret, accessToken *C.char, orderListJson *C.char) *C.char { goAppId := int(appId) goAppSecret := C.GoString(appSecret) goAccessToken := C.GoString(accessToken) goOrderListJson := C.GoString(orderListJson) list, err := kongfzOrderList(goAppId, goAppSecret, goAccessToken, goOrderListJson) if err != nil { return C.CString(fmt.Sprint(err)) } return C.CString(list) } // KongfzOrderGet 查询单个订单 // //export KongfzOrderGet func KongfzOrderGet(appId C.int, appSecret, accessToken *C.char, userType *C.char, orderId C.int) *C.char { goAppId := int(appId) goAppSecret := C.GoString(appSecret) goAccessToken := C.GoString(accessToken) goUserType := C.GoString(userType) goOrderId := int(orderId) orderGet, err := kongfzOrderGet(goAppId, goAppSecret, goAccessToken, goUserType, goOrderId) if err != nil { return C.CString(fmt.Sprint(err)) } return C.CString(orderGet) } // KongfzOrderRedeliver 订单修改发货单号 // //export KongfzOrderRedeliver func KongfzOrderRedeliver(appId C.int, appSecret, accessToken *C.char, requestJson *C.char) *C.char { appIdStr := int(appId) appSecretStr := C.GoString(appSecret) accessTokenStr := C.GoString(accessToken) requestJsonStr := C.GoString(requestJson) info, err := kongfzOrderRedeliver(appIdStr, appSecretStr, accessTokenStr, requestJsonStr) if err != nil { return C.CString(fmt.Sprint(err)) } return C.CString(info) } // KongfzOrderFlagAdd 订单标记添加/修改 // //export KongfzOrderFlagAdd func KongfzOrderFlagAdd(appId C.int, appSecret, accessToken *C.char, requestJson *C.char) *C.char { appIdStr := int(appId) appSecretStr := C.GoString(appSecret) accessTokenStr := C.GoString(accessToken) requestJsonStr := C.GoString(requestJson) info, err := kongfzOrderFlagAdd(appIdStr, appSecretStr, accessTokenStr, requestJsonStr) if err != nil { return C.CString(fmt.Sprint(err)) } return C.CString(info) } // KongfzOrderFlagDel 订单标记删除 // //export KongfzOrderFlagDel func KongfzOrderFlagDel(appId C.int, appSecret, accessToken *C.char, requestJson *C.char) *C.char { appIdStr := int(appId) appSecretStr := C.GoString(appSecret) accessTokenStr := C.GoString(accessToken) requestJsonStr := C.GoString(requestJson) info, err := kongfzOrderFlagDel(appIdStr, appSecretStr, accessTokenStr, requestJsonStr) if err != nil { return C.CString(fmt.Sprint(err)) } return C.CString(info) } // KongfzShopCategoryNameList 获取店铺本店分类名称列表 // //export KongfzShopCategoryNameList func KongfzShopCategoryNameList(appId C.int, appSecret, accessToken *C.char) *C.char { appIdStr := int(appId) appSecretStr := C.GoString(appSecret) accessTokenStr := C.GoString(accessToken) info, err := kongfzShopCategoryNameList(appIdStr, appSecretStr, accessTokenStr) if err != nil { return C.CString(fmt.Sprint(err)) } return C.CString(info) } // KongfzCommonCategory 获取公用分类数据 // //export KongfzCommonCategory func KongfzCommonCategory(appId C.int, appSecret, accessToken *C.char) *C.char { appIdStr := int(appId) appSecretStr := C.GoString(appSecret) accessTokenStr := C.GoString(accessToken) info, err := kongfzCommonCategory(appIdStr, appSecretStr, accessTokenStr) if err != nil { return C.CString(fmt.Sprint(err)) } return C.CString(info) } // KongfzShopItemDelisting 下架商品 // //export KongfzShopItemDelisting func KongfzShopItemDelisting(appId C.int, appSecret, accessToken, requestJson *C.char) *C.char { appIdStr := int(appId) appSecretStr := C.GoString(appSecret) accessTokenStr := C.GoString(accessToken) requestJsonStr := C.GoString(requestJson) info, err := kongfzShopItemDelisting(appIdStr, appSecretStr, accessTokenStr, requestJsonStr) if err != nil { return C.CString(fmt.Sprint(err)) } return C.CString(info) } // KongfzShopItemList 查询店铺商品列表 // //export KongfzShopItemList func KongfzShopItemList(appId C.int, appSecret, accessToken, requestJson *C.char) *C.char { appIdStr := int(appId) appSecretStr := C.GoString(appSecret) accessTokenStr := C.GoString(accessToken) requestJsonStr := C.GoString(requestJson) info, err := kongfzShopItemList(appIdStr, appSecretStr, accessTokenStr, requestJsonStr) if err != nil { return C.CString(fmt.Sprint(err)) } return C.CString(info) } // KongfzShopItemDetail 查询店铺商品详情 // //export KongfzShopItemDetail func KongfzShopItemDetail(appId C.int, appSecret, accessToken, requestJson *C.char) *C.char { appIdStr := int(appId) appSecretStr := C.GoString(appSecret) accessTokenStr := C.GoString(accessToken) requestJsonStr := C.GoString(requestJson) info, err := kongfzShopItemDetail(appIdStr, appSecretStr, accessTokenStr, requestJsonStr) if err != nil { return C.CString(fmt.Sprint(err)) } return C.CString(info) } // KongfzShopItemListing 上架商品 // //export KongfzShopItemListing func KongfzShopItemListing(appId C.int, appSecret, accessToken, requestJson *C.char) *C.char { appIdStr := int(appId) appSecretStr := C.GoString(appSecret) accessTokenStr := C.GoString(accessToken) requestJsonStr := C.GoString(requestJson) info, err := kongfzShopItemListing(appIdStr, appSecretStr, accessTokenStr, requestJsonStr) if err != nil { return C.CString(fmt.Sprint(err)) } return C.CString(info) } // KongfzShopItemNumberUpdate 修改商品库存 // //export KongfzShopItemNumberUpdate func KongfzShopItemNumberUpdate(appId C.int, appSecret, accessToken, requestJson *C.char) *C.char { appIdStr := int(appId) appSecretStr := C.GoString(appSecret) accessTokenStr := C.GoString(accessToken) requestJsonStr := C.GoString(requestJson) info, err := kongfzShopItemNumberUpdate(appIdStr, appSecretStr, accessTokenStr, requestJsonStr) if err != nil { return C.CString(fmt.Sprint(err)) } return C.CString(info) } // KongfzShopItemPriceUpdate 修改商品价格 // //export KongfzShopItemPriceUpdate func KongfzShopItemPriceUpdate(appId C.int, appSecret, accessToken, requestJson *C.char) *C.char { appIdStr := int(appId) appSecretStr := C.GoString(appSecret) accessTokenStr := C.GoString(accessToken) requestJsonStr := C.GoString(requestJson) info, err := kongfzShopItemPriceUpdate(appIdStr, appSecretStr, accessTokenStr, requestJsonStr) if err != nil { return C.CString(fmt.Sprint(err)) } return C.CString(info) } // KongfzShopItemDelete 删除商品到回收站 // //export KongfzShopItemDelete func KongfzShopItemDelete(appId C.int, appSecret, accessToken, requestJson *C.char) *C.char { appIdStr := int(appId) appSecretStr := C.GoString(appSecret) accessTokenStr := C.GoString(accessToken) requestJsonStr := C.GoString(requestJson) info, err := kongfzShopItemDelete(appIdStr, appSecretStr, accessTokenStr, requestJsonStr) if err != nil { return C.CString(fmt.Sprint(err)) } return C.CString(info) } // Initialize 初始化配置 // //export Initialize func Initialize(configJSON *C.char) *C.char { configStr := C.GoString(configJSON) log.Printf("[DEBUG] 接收到的配置JSON: %s", configStr) var config Config if err := json.Unmarshal([]byte(configStr), &config); err != nil { return C.CString(fmt.Sprintf(`{"success":false,"message":"配置解析失败: %v"}`, err)) } initializeConfig(config) return C.CString(`{"success":true,"message":"初始化成功"}`) } // FreeCString 释放C字符串内存 // //export FreeCString func FreeCString(str *C.char) { C.free(unsafe.Pointer(str)) } // KfzVersion 版本号 const ( KfzVersion = "v2" ) // GetVersion 获取版本信息 // //export GetVersion func GetVersion() *C.char { return C.CString(KfzVersion) } // 空main函数,编译DLL时需要 func main() { //appid := 576 //key := "256e10220c5b307f5172b1a49c11467a6cfa8038bbe2a7feccc42231852324f8" //token := "8642f80ddb95826c9ad36877784c69c26a0f84d73184d08ab026ca6c851dd964" //list, err := kongfzOrderSynchronization(appid, key, token, "中国邮政", 0, "", "", "", "", "") //if err != nil { // fmt.Println(err.Error()) // return //} //fmt.Println(list) }