|
@@ -0,0 +1,178 @@
|
|
|
+package main
|
|
|
+
|
|
|
+import (
|
|
|
+ "flag"
|
|
|
+ "fmt"
|
|
|
+ "git.aionnect.com/aionnect/go-common/utils"
|
|
|
+ "git.aionnect.com/aionnect/go-common/utils/jsonutil"
|
|
|
+ "github.com/tealeg/xlsx"
|
|
|
+ "net/http"
|
|
|
+ "strings"
|
|
|
+ "sync"
|
|
|
+)
|
|
|
+
|
|
|
+/*
|
|
|
+调用微信公众平台接口,长链接批量转短链接小工具
|
|
|
+
|
|
|
+long2short.exe 是Windows版本
|
|
|
+long2short 是Mac版本
|
|
|
+
|
|
|
+不是直接双击使用,需要在控制台或终端中输入命令调用
|
|
|
+用 long2short -help 查看命令参数说明
|
|
|
+
|
|
|
+使用步骤:
|
|
|
+1. 准备好包含长链接的Excel文件,文件务必保存为xlsx格式
|
|
|
+2. 问研发或管理员获取最新有效的微信公众号AccessToken
|
|
|
+3. 打开Windows控制台或Mac终端,执行类似下面的命令
|
|
|
+
|
|
|
+Windows:
|
|
|
+
|
|
|
+.\long2short.exe -i .\input.xlsx -o .\output.xlsx -h 长链接 -t AccessToken的值
|
|
|
+
|
|
|
+Mac:
|
|
|
+
|
|
|
+./long2short -i ./input.xlsx -o ./output.xlsx -h 长链接 -t AccessToken的值
|
|
|
+
|
|
|
+4. 如果出错,会在命令窗口打印错误信息,如果顺利,会在程序所在目录下输出新的xlsx文件
|
|
|
+*/
|
|
|
+
|
|
|
+func main() {
|
|
|
+ var inputFileName string
|
|
|
+ var accessToken string
|
|
|
+ var headerName string
|
|
|
+ var outputFileName string
|
|
|
+ flag.StringVar(&inputFileName, "i", "input.xlsx", "xlsx输入文件路径,默认值\"input.xlsx\"")
|
|
|
+ flag.StringVar(&accessToken, "t", "", "Access Token,必填")
|
|
|
+ flag.StringVar(&headerName, "h", "合成链接", "长链接列名,默认值\"合成链接\"")
|
|
|
+ flag.StringVar(&outputFileName, "o", "output.xlsx", "xlsx输出文件路径,会在文件名后加上时间戳,默认值\"output.xlsx\"")
|
|
|
+ flag.Parse()
|
|
|
+ if accessToken == "" {
|
|
|
+ println("-t AccessToken 参数是必须的")
|
|
|
+ return
|
|
|
+ }
|
|
|
+ reqUrl := fmt.Sprintf("https://api.weixin.qq.com/cgi-bin/shorturl?access_token=%s", accessToken)
|
|
|
+
|
|
|
+ file, err := xlsx.OpenFile(inputFileName)
|
|
|
+ if err != nil {
|
|
|
+ panic(fmt.Sprintf("读取输入文件%s失败 %s", inputFileName, err.Error()))
|
|
|
+ }
|
|
|
+
|
|
|
+ sheets := file.Sheets
|
|
|
+ if nil == sheets || len(sheets) == 0 {
|
|
|
+ println("输入文件中没有工作表")
|
|
|
+ return
|
|
|
+ }
|
|
|
+ for _, sheet := range file.Sheets {
|
|
|
+ rows := sheet.Rows
|
|
|
+ if nil == rows || len(rows) < 2 {
|
|
|
+ fmt.Printf("工作表%s中没有数据\n", sheet.Name)
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ header := rows[0]
|
|
|
+ idx := -1
|
|
|
+ for i, cell := range header.Cells {
|
|
|
+ text := cell.String()
|
|
|
+ if strings.TrimSpace(text) == headerName {
|
|
|
+ idx = i
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if idx < 0 {
|
|
|
+ fmt.Printf("工作表%s中没有找到长链接列名列名\"%s\"\n", sheet.Name, headerName)
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ newHeader := header.AddCell()
|
|
|
+ newHeader.SetString("短链接")
|
|
|
+
|
|
|
+ length := len(rows) - 1
|
|
|
+ pNo := 1
|
|
|
+ if length > 5 {
|
|
|
+ pNo = 5
|
|
|
+ }
|
|
|
+ if length > 100 {
|
|
|
+ pNo = 10
|
|
|
+ }
|
|
|
+ if length > 500 {
|
|
|
+ pNo = 100
|
|
|
+ }
|
|
|
+ size := length / pNo
|
|
|
+ var firstArr []*RowInfo
|
|
|
+ rowGroup := [][]*RowInfo{firstArr}
|
|
|
+ var j, ct int
|
|
|
+ for i := 1; i < len(rows); i++ {
|
|
|
+ rowGroup[j] = append(rowGroup[j], &RowInfo{Row: rows[i], RowNo: i + 1})
|
|
|
+ ct++
|
|
|
+ if ct >= size {
|
|
|
+ var newArr []*RowInfo
|
|
|
+ rowGroup = append(rowGroup, newArr)
|
|
|
+ ct = 0
|
|
|
+ j++
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ var counter sync.WaitGroup
|
|
|
+ counter.Add(length)
|
|
|
+ for i := 0; i < len(rowGroup); i++ {
|
|
|
+ arr := rowGroup[i]
|
|
|
+ go func(reqUrl string, idx int, sheetName string, arr []*RowInfo) {
|
|
|
+ for j := 0; j < len(arr); j++ {
|
|
|
+ info := arr[j]
|
|
|
+ call(reqUrl, idx, sheetName, info)
|
|
|
+ counter.Done()
|
|
|
+ }
|
|
|
+ }(reqUrl, idx, sheet.Name, arr)
|
|
|
+ }
|
|
|
+ counter.Wait()
|
|
|
+ }
|
|
|
+
|
|
|
+ dotIdx := strings.LastIndex(outputFileName, ".")
|
|
|
+ outputFileName = fmt.Sprintf("%s_%d.xlsx", outputFileName[:dotIdx], utils.NextId())
|
|
|
+ err = file.Save(outputFileName)
|
|
|
+ if nil != err {
|
|
|
+ panic(fmt.Sprintf("写输出文件%s失败 %s", outputFileName, err.Error()))
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func call(reqUrl string, idx int, sheetName string, info *RowInfo) {
|
|
|
+ row := info.Row
|
|
|
+ var longUrl string
|
|
|
+ if len(row.Cells) > idx {
|
|
|
+ longUrl = row.Cells[idx].String()
|
|
|
+ }
|
|
|
+ longUrl = strings.TrimSpace(longUrl)
|
|
|
+ if longUrl == "" {
|
|
|
+ fmt.Printf("工作表%s中第%d行长链接值为空\n", sheetName, info.RowNo)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ reqBody := fmt.Sprintf(`{"action":"long2short","long_url":"%s"}`, longUrl)
|
|
|
+ respBody, err := utils.NewRequest().Call(http.MethodPost, reqUrl, strings.NewReader(reqBody))
|
|
|
+ if nil != err {
|
|
|
+ fmt.Printf("工作表%s中第%d行请求短链接失败 %s\n", sheetName, info.RowNo, err.Error())
|
|
|
+ return
|
|
|
+ }
|
|
|
+ var res ShortResult
|
|
|
+ err = jsonutil.Unmarshal(respBody, &res)
|
|
|
+ if nil != err {
|
|
|
+ fmt.Printf("工作表%s中第%d行请求短链接返回了意外的结果 %s\n", sheetName, info.RowNo, string(respBody))
|
|
|
+ return
|
|
|
+ }
|
|
|
+ res.ShortUrl = strings.TrimSpace(res.ShortUrl)
|
|
|
+ if res.ErrCode != 0 || res.ShortUrl == "" {
|
|
|
+ fmt.Printf("工作表%s中第%d行请求短链接出错 %s\n", sheetName, info.RowNo, string(respBody))
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ newCell := row.AddCell()
|
|
|
+ newCell.SetString(res.ShortUrl)
|
|
|
+}
|
|
|
+
|
|
|
+type RowInfo struct {
|
|
|
+ Row *xlsx.Row
|
|
|
+ RowNo int
|
|
|
+}
|
|
|
+
|
|
|
+type ShortResult struct {
|
|
|
+ ErrCode int `json:"errcode"`
|
|
|
+ ErrMsg string `json:"errmsg"`
|
|
|
+ ShortUrl string `json:"short_url"`
|
|
|
+}
|