resourceChannel.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. package resourceChannel
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "fmt"
  6. "github.com/go-redis/redis"
  7. "golang.org/x/net/context"
  8. "io/ioutil"
  9. "log"
  10. "net/http"
  11. "net/url"
  12. "os"
  13. "path"
  14. "runtime"
  15. "strconv"
  16. "strings"
  17. "time"
  18. )
  19. func redisCli() *redis.Client {
  20. client := redis.NewClient(&redis.Options{
  21. //Addr: coo.RedisHost, // Redis地址
  22. Addr: "192.168.204.193:6379", // Redis地址
  23. Password: "", // Redis密码,默认为空
  24. DB: 1, // 使用哪个数据库,默认为0
  25. })
  26. _, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)
  27. defer cancel()
  28. return client
  29. }
  30. type ResourceAssessment struct {
  31. ID uint `gorm:"primaryKey" json:"id"` // 留学评估表
  32. DataType uint8 `json:"data_type"` // 1.网课 2.api资源 3.专题页 4.工作台录入 5.后台录入 6 小程序
  33. ChatID string `json:"chat_id"` // 会话id
  34. Channel int `json:"channel"` // 渠道id
  35. Category int `json:"category"` // 分类id
  36. CreatedAt time.Time `json:"created_at"` // 数据创建时间
  37. ReferPageURL string `json:"refer_page_url"` // 来源网址
  38. URL string `json:"url"` // 落地页地址
  39. ChatURL string `json:"chat_url"` // 对话发起页
  40. GrUserId string `json:"gr_user_id"` // 神策distinct_id
  41. }
  42. type SemJsChatRecord struct {
  43. ChatID int64 `gorm:"column:CHAT_ID"`
  44. CreateTime time.Time `gorm:"column:CREATE_TIME"`
  45. ReferPage string `gorm:"type:text;column:REFER_PAGE"`
  46. ChatURL string `gorm:"type:text;column:CHAT_URL"`
  47. ChannleID int `gorm:"column:CHANNLE_ID"`
  48. CategoryID int `gorm:"column:CATEGORY_ID"`
  49. GrUserID string `gorm:"column:gr_user_id"`
  50. SourceUrl string `gorm:"column:source_url"`
  51. }
  52. type ChannelCategory struct {
  53. Channel int
  54. Category int
  55. }
  56. // GetChannel 表单渠道归因处理
  57. func GetChannel(assessment ResourceAssessment) ChannelCategory {
  58. log.Printf("%v", assessment)
  59. // 获取神策URL(不包含utm)
  60. cc, _ := redisCli().Get("website:" + assessment.GrUserId).Result()
  61. var websiteUrl SensorsData
  62. json.Unmarshal([]byte(cc), &websiteUrl)
  63. // 到梦解析
  64. if !strings.Contains(assessment.URL, "utm") && !strings.Contains(assessment.ChatURL, "utm") && !strings.Contains(assessment.ReferPageURL, "utm") && (strings.Contains(assessment.ReferPageURL, "daomeng") || strings.Contains(assessment.ChatURL, "daomeng")) {
  65. log.Printf("解析到梦")
  66. assessment.Channel = 38
  67. assessment.Category = getCategory(201)
  68. return ChannelCategory{assessment.Channel, assessment.Category}
  69. }
  70. // 网课解析
  71. if assessment.DataType == 1 {
  72. log.Printf("解析网课")
  73. assessment.Channel = 26
  74. assessment.Category = getCategory(121)
  75. return ChannelCategory{assessment.Channel, assessment.Category}
  76. }
  77. // 小程序解析
  78. if strings.Contains(assessment.ChatURL, "pages") && strings.Split(strings.Split(assessment.ChatURL, "?")[1], "=")[0] == "miniapp" && (strings.Contains(assessment.ChatURL, "baidu") || strings.Contains(assessment.ChatURL, "wechat")) {
  79. log.Printf("解析小程序")
  80. appType := strings.Split(strings.Split(strings.Split(assessment.ChatURL, "?")[1], "=")[1], "_")[1]
  81. if appType == "baidu" {
  82. assessment.Channel = 1
  83. assessment.Category = getCategory(30)
  84. } else if appType == "wechat" {
  85. assessment.Channel = 8
  86. assessment.Category = getCategory(32)
  87. }
  88. return ChannelCategory{assessment.Channel, assessment.Category}
  89. }
  90. // URL解析
  91. if strings.Contains(assessment.URL, "link=") || strings.Contains(assessment.ReferPageURL, "link=") || strings.Contains(assessment.ChatURL, "link=") {
  92. log.Printf("解析URL")
  93. if len(strings.Split(assessment.URL, "_")) == 3 {
  94. var category, _ = strconv.Atoi(strings.Split(assessment.URL, "_")[1])
  95. if category > 10000 {
  96. assessment.Channel = category
  97. assessment.Category = category
  98. }
  99. }
  100. if strings.Contains(assessment.URL, "link=") {
  101. split := strings.Split(assessment.URL, "link")
  102. if strings.Contains(split[1], "form") || strings.Contains(split[1], "from") {
  103. assessment.Channel, _ = strconv.Atoi(strings.Split(strings.Split(strings.Split(assessment.URL, "link")[1], "form")[0], "_")[1])
  104. var category, _ = strconv.Atoi(strings.Split(strings.Split(strings.Split(assessment.URL, "link")[1], "form")[0], "_")[2])
  105. assessment.Category = getCategory(category)
  106. } else {
  107. assessment.Channel = 5
  108. assessment.Category = getCategory(11)
  109. }
  110. } else if strings.Contains(assessment.ReferPageURL, "link=") {
  111. split := strings.Split(assessment.ReferPageURL, "link")
  112. if strings.Contains(split[1], "form") || strings.Contains(split[1], "from") {
  113. assessment.Channel, _ = strconv.Atoi(strings.Split(strings.Split(strings.Split(assessment.ReferPageURL, "link")[1], "form")[0], "_")[1])
  114. var category, _ = strconv.Atoi(strings.Split(strings.Split(strings.Split(assessment.ReferPageURL, "link")[1], "form")[0], "_")[2])
  115. assessment.Category = getCategory(category)
  116. } else {
  117. assessment.Channel = 5
  118. assessment.Category = getCategory(11)
  119. }
  120. } else {
  121. split := strings.Split(assessment.ChatURL, "link")
  122. if strings.Contains(split[1], "form") || strings.Contains(split[1], "from") {
  123. assessment.Channel, _ = strconv.Atoi(strings.Split(strings.Split(strings.Split(assessment.ChatURL, "link")[1], "form")[0], "_")[1])
  124. var category, _ = strconv.Atoi(strings.Split(strings.Split(strings.Split(assessment.ChatURL, "link")[1], "form")[0], "_")[2])
  125. assessment.Category = getCategory(category)
  126. } else {
  127. assessment.Channel = 5
  128. assessment.Category = getCategory(11)
  129. }
  130. }
  131. // 百度惠生活渠道合并
  132. if assessment.Category == 239 {
  133. assessment.Category = getCategory(292)
  134. }
  135. return ChannelCategory{assessment.Channel, assessment.Category}
  136. }
  137. // 获取神策url(包含utm)
  138. cc1, _ := redisCli().Get("sensors:" + assessment.GrUserId).Result()
  139. var utmUrl SensorsData
  140. json.Unmarshal([]byte(cc1), &utmUrl)
  141. // 神策解析
  142. if utmUrl.Url != "" && !strings.Contains(assessment.URL, "link=") && !strings.Contains(assessment.ReferPageURL, "link=") && !strings.Contains(assessment.ChatURL, "link=") {
  143. log.Printf("解析神策")
  144. assessment.Channel = utmUrl.Channel
  145. assessment.Category = utmUrl.Category
  146. // 百度惠生活渠道合并
  147. if assessment.Category == 239 {
  148. assessment.Category = getCategory(292)
  149. }
  150. return ChannelCategory{assessment.Channel, assessment.Category}
  151. }
  152. // 搜索引擎SEO,外链解析
  153. if assessment.ReferPageURL != "" && !strings.Contains(assessment.ReferPageURL, "https://www.jjl.cn/") && !strings.Contains(assessment.ReferPageURL, "https://m.jjl.cn/") {
  154. log.Printf("解析SEO")
  155. assessment.Channel = 5
  156. assessment.Category = getCategory(11)
  157. return ChannelCategory{assessment.Channel, assessment.Category}
  158. }
  159. // 官网自然访问解析
  160. if strings.Contains(assessment.URL, "https://www.jjl.cn/") || strings.Contains(assessment.URL, "https://m.jjl.cn/") ||
  161. strings.Contains(assessment.ReferPageURL, "https://www.jjl.cn/") || strings.Contains(assessment.ReferPageURL, "https://m.jjl.cn/") ||
  162. strings.Contains(assessment.ChatURL, "https://www.jjl.cn/") || strings.Contains(assessment.ChatURL, "https://m.jjl.cn/") ||
  163. strings.Contains(utmUrl.Url, "https://www.jjl.cn/") || strings.Contains(utmUrl.Url, "https://m.jjl.cn/") {
  164. log.Printf("解析官网")
  165. assessment.Channel = 7
  166. assessment.Category = getCategory(126)
  167. return ChannelCategory{assessment.Channel, assessment.Category}
  168. }
  169. log.Printf("默认解析为SEO")
  170. assessment.Channel = 5
  171. assessment.Category = getCategory(11)
  172. return ChannelCategory{assessment.Channel, assessment.Category}
  173. }
  174. // GetChatChannel 会话渠道归因处理
  175. func GetChatChannel(chat SemJsChatRecord) ChannelCategory {
  176. log.Printf("%v", chat)
  177. // 获取神策URL(不包含utm)
  178. cc, _ := redisCli().Get("website:" + chat.GrUserID).Result()
  179. var websiteUrl SensorsData
  180. json.Unmarshal([]byte(cc), &websiteUrl)
  181. // 小程序解析
  182. if strings.Contains(chat.ChatURL, "pages") && strings.Split(strings.Split(chat.ChatURL, "?")[1], "=")[0] == "miniapp" && (strings.Contains(chat.ChatURL, "baidu") || strings.Contains(chat.ChatURL, "wechat")) {
  183. log.Printf("小程序解析")
  184. log.Printf(chat.ChatURL)
  185. appType := strings.Split(strings.Split(strings.Split(chat.ChatURL, "?")[1], "=")[1], "_")[1]
  186. if appType == "baidu" {
  187. chat.ChannleID = 1
  188. chat.CategoryID = getCategory(30)
  189. } else if appType == "wechat" {
  190. chat.ChannleID = 8
  191. chat.CategoryID = getCategory(32)
  192. }
  193. return ChannelCategory{chat.ChannleID, chat.CategoryID}
  194. }
  195. // 到梦解析
  196. if !strings.Contains(chat.ReferPage, "utm") && !strings.Contains(chat.ChatURL, "utm") && (strings.Contains(chat.ReferPage, "daomeng") || strings.Contains(chat.ChatURL, "daomeng")) {
  197. log.Printf("到梦解析")
  198. chat.ChannleID = 38
  199. chat.CategoryID = getCategory(201)
  200. return ChannelCategory{chat.ChannleID, chat.CategoryID}
  201. }
  202. // URL解析
  203. if strings.Contains(chat.ChatURL, "link=") || strings.Contains(chat.ReferPage, "link=") {
  204. log.Printf("解析CHATURL")
  205. if strings.Contains(chat.ChatURL, "link=") {
  206. split := strings.Split(chat.ChatURL, "link=")
  207. if strings.Contains(split[1], "form") || strings.Contains(split[1], "from") {
  208. chat.ChannleID, _ = strconv.Atoi(strings.Split(strings.Split(strings.Split(chat.ChatURL, "link")[1], "form")[0], "_")[1])
  209. var category, _ = strconv.Atoi(strings.Split(strings.Split(strings.Split(chat.ChatURL, "link")[1], "form")[0], "_")[2])
  210. chat.CategoryID = getCategory(category)
  211. } else {
  212. chat.ChannleID = 5
  213. chat.CategoryID = getCategory(11)
  214. }
  215. } else {
  216. split := strings.Split(chat.ReferPage, "link=")
  217. if strings.Contains(split[01], "form") || strings.Contains(split[1], "from") {
  218. chat.ChannleID, _ = strconv.Atoi(strings.Split(strings.Split(strings.Split(chat.ReferPage, "link")[1], "form")[0], "_")[1])
  219. var category, _ = strconv.Atoi(strings.Split(strings.Split(strings.Split(chat.ReferPage, "link")[1], "form")[0], "_")[2])
  220. chat.CategoryID = getCategory(category)
  221. } else {
  222. chat.ChannleID = 5
  223. chat.CategoryID = getCategory(11)
  224. }
  225. }
  226. // 百度惠生活渠道合并
  227. if chat.CategoryID == 239 {
  228. chat.CategoryID = getCategory(292)
  229. }
  230. return ChannelCategory{chat.ChannleID, chat.CategoryID}
  231. }
  232. // 获取神策url(包含utm)
  233. cc1, _ := redisCli().Get("sensors:" + chat.GrUserID).Result()
  234. var utmUrl SensorsData
  235. json.Unmarshal([]byte(cc1), &utmUrl)
  236. // 神策解析
  237. if utmUrl.Url != "" && utmUrl.Channel > 0 && !strings.Contains(chat.ReferPage, "link=") && !strings.Contains(chat.ChatURL, "link=") {
  238. log.Printf("解析神策")
  239. chat.ChannleID = utmUrl.Channel
  240. chat.CategoryID = utmUrl.Category
  241. // 百度惠生活渠道合并
  242. if chat.CategoryID == 239 {
  243. chat.CategoryID = getCategory(292)
  244. }
  245. return ChannelCategory{chat.ChannleID, chat.CategoryID}
  246. }
  247. // 搜索引擎SEO,外链解析
  248. if chat.ReferPage != "" && !strings.Contains(chat.ReferPage, "https://www.jjl.cn/") && !strings.Contains(chat.ReferPage, "https://m.jjl.cn/") {
  249. log.Printf("解析SEO")
  250. chat.ChannleID = 5
  251. chat.CategoryID = getCategory(11)
  252. return ChannelCategory{chat.ChannleID, chat.CategoryID}
  253. }
  254. // 官网自然访问解析
  255. if strings.Contains(chat.ReferPage, "https://www.jjl.cn/") || strings.Contains(chat.ReferPage, "https://m.jjl.cn/") ||
  256. strings.Contains(chat.ChatURL, "https://www.jjl.cn/") || strings.Contains(chat.ChatURL, "https://m.jjl.cn/") ||
  257. strings.Contains(utmUrl.Url, "https://www.jjl.cn/") || strings.Contains(utmUrl.Url, "https://m.jjl.cn/") {
  258. log.Printf("解析官网")
  259. chat.ChannleID = 7
  260. chat.CategoryID = getCategory(126)
  261. return ChannelCategory{chat.ChannleID, chat.CategoryID}
  262. }
  263. log.Printf("默认解析为SEO")
  264. chat.ChannleID = 5
  265. chat.CategoryID = getCategory(11)
  266. return ChannelCategory{chat.ChannleID, chat.CategoryID}
  267. }
  268. type SensorsData struct {
  269. DistinctId string `json:"distinctID"`
  270. Channel int `json:"channel"`
  271. Category int `json:"category"`
  272. Url string `json:"url"`
  273. }
  274. // 访问神策API
  275. func getSensorsData(sql string) string {
  276. sensorsUrl := "http://10.0.6.35:8107/api/sql/query?token=128d837f466684101710cfb308e7556de975b717c6c2465ba5fc2836d57a64c8&project=production&type=impala&q=" + url.QueryEscape(sql) + "&format=json"
  277. data := []byte("")
  278. log.Printf("REQ_URL:%s", sensorsUrl)
  279. req, err := http.NewRequest("POST", sensorsUrl, bytes.NewBuffer(data))
  280. if err != nil {
  281. log.Printf("ERROR:%s", err.Error())
  282. return err.Error()
  283. }
  284. req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
  285. client := &http.Client{}
  286. resp, err := client.Do(req)
  287. if err != nil {
  288. return err.Error()
  289. }
  290. defer resp.Body.Close()
  291. respBody, err := ioutil.ReadAll(resp.Body)
  292. if err != nil {
  293. return err.Error()
  294. }
  295. var sensors Sensors
  296. json.Unmarshal([]byte(string(respBody)), &sensors)
  297. return sensors.LatestReferrer
  298. }
  299. // Sensors 神策数据结构体
  300. type Sensors struct {
  301. Url string `json:"$url"`
  302. LatestReferrer string `json:"$latest_referrer"`
  303. }
  304. type SysChannel struct {
  305. OriginalCategory string `json:"original_category"` // 主键ID
  306. CategoryId string `json:"category_id"` // 备注
  307. }
  308. func getCurrentPath() string {
  309. _, filename, _, _ := runtime.Caller(1)
  310. return path.Dir(filename)
  311. }
  312. func getCategory(OriginalCategory int) int {
  313. endpoint := "oss-cn-beijing.aliyuncs.com" // 例如 "oss-cn-hangzhou.aliyuncs.com"
  314. accessKeyID := "LTAI5t7iAtrYaUgGgK8ws54e"
  315. accessKeySecret := "j4A6llCRqZBMzXLQ7ms84LdKl9l0IS"
  316. bucketName := "jjl-prod-bucket"
  317. objectName := "channel/category_mapper.json"
  318. client, err := oss.New(endpoint, accessKeyID, accessKeySecret)
  319. if err != nil {
  320. log.Fatalf("创建OSS客户端失败: %v", err)
  321. }
  322. // 获取存储空间
  323. bucket, err := client.Bucket(bucketName)
  324. if err != nil {
  325. log.Fatalf("获取Bucket失败: %v", err)
  326. }
  327. // 获取对象
  328. body, err := bucket.GetObject(objectName)
  329. if err != nil {
  330. log.Fatalf("获取对象失败: %v", err)
  331. }
  332. defer body.Close()
  333. // 读取对象内容
  334. var channel []SysChannel
  335. decoder := json.NewDecoder(body)
  336. if err := decoder.Decode(&channel); err != nil {
  337. log.Fatalf("解析JSON失败: %v", err)
  338. }
  339. for i := range channel {
  340. ori, _ := strconv.Atoi(channel[i].OriginalCategory)
  341. if ori == OriginalCategory {
  342. category, _ := strconv.Atoi(channel[i].CategoryId)
  343. return category
  344. }
  345. }
  346. return -1
  347. }