TaobaoOpenPlus.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. using dodohold.core;
  2. using Org.BouncyCastle.Ocsp;
  3. using Sayaka.Common;
  4. using System.Net;
  5. using System.Text.Json;
  6. using System.Xml;
  7. using TencentCloud.Lighthouse.V20200324.Models;
  8. using TencentCloud.Weilingwith.V20230427.Models;
  9. using Top.Api;
  10. using Top.Api.Request;
  11. using Top.Api.Response;
  12. namespace molilian.core
  13. {
  14. public partial class TaobaoOpenPlus
  15. {
  16. public enum RecommendRequestType
  17. {
  18. first,
  19. second,
  20. ori,
  21. }
  22. string _app_key = string.Empty;
  23. string _app_secret = string.Empty;
  24. string _pid = string.Empty;
  25. string _server_url = "https://eco.taobao.com/router/rest";
  26. bool _debug = false;
  27. WebProxy _proxy = null;
  28. public TaobaoOpenPlus(string app_key, string app_secret, string pid, bool debug, WebProxy proxy)
  29. {
  30. _app_key = app_key;
  31. _app_secret = app_secret;
  32. _pid = pid;
  33. _debug = debug;
  34. _proxy = proxy;
  35. }
  36. public static PromotionQueryItemDTO ConverPromotionQueryItem(JsonElement item)
  37. {
  38. PromotionQueryItemDTO result = JsonSerializer.Deserialize<PromotionQueryItemDTO>(item.GetRawText());
  39. string h5_url = item.Read("couponShareUrl", string.Empty);
  40. if (string.IsNullOrEmpty(h5_url))
  41. {
  42. h5_url = item.Read("url", string.Empty);
  43. }
  44. if (h5_url.StartsWith("//")) h5_url = "https:" + h5_url;
  45. result.h5_url = h5_url;
  46. result.deeplink_url = AlimamaPlus.GetDeeplink(h5_url);
  47. if (result.pic.StartsWith("//")) result.pic = "https:" + result.pic;
  48. return result;
  49. }
  50. public TbkThorMfrsPromotionQueryResponse PromotionQueryRequest(string base64, string oaid)
  51. {
  52. var client = new DefaultTopClient(_server_url, _app_key, _app_secret, "json");
  53. client.SetProxy(_proxy);
  54. TbkThorMfrsPromotionQueryRequest req = new();
  55. TbkThorMfrsPromotionQueryRequest.ManufacturerLaunchOptionDomain obj1 = new()
  56. {
  57. Img = base64,
  58. Pid = _pid,
  59. UniqueId = oaid,
  60. UniqueIdType = "oaid",
  61. SceneCode = "h5_img",
  62. SceneSubCode = "Hitoch"
  63. };
  64. req.Option_ = obj1;
  65. TbkThorMfrsPromotionQueryResponse rsp = client.Execute(req);
  66. if (_debug)
  67. {
  68. var _req = req.Convert2Json();
  69. var _rsp = rsp.Convert2Json();
  70. new LoggerLibrary("debug", oaid).Info(_req, _rsp).Save();
  71. }
  72. return rsp;
  73. }
  74. public TbkDgSmartAssistantLinkConvertResponse SmartAssistantLinkConvertRequest(
  75. string originalItemUrl,
  76. string oaid,
  77. TbkDgSmartAssistantLinkConvertRequest.TargetItemDtoDomain? targetItem = null,
  78. TbkDgSmartAssistantLinkConvertRequest.ItemFeedDtoDomain? itemFeed = null)
  79. {
  80. if (string.IsNullOrWhiteSpace(this._pid))
  81. {
  82. throw new ArgumentException("pid is required", nameof(this._pid));
  83. }
  84. string[] pidParts = this._pid.Split('_', StringSplitOptions.RemoveEmptyEntries);
  85. if (pidParts.Length < 4 || !long.TryParse(pidParts[^1], out long adzoneId))
  86. {
  87. throw new ArgumentException("pid format is invalid", nameof(this._pid));
  88. }
  89. var client = new DefaultTopClient(_server_url, _app_key, _app_secret, "json");
  90. client.SetProxy(_proxy);
  91. TbkDgSmartAssistantLinkConvertRequest req = new()
  92. {
  93. AdzoneId = adzoneId,
  94. SubPid = this._pid,
  95. TargetItemDto = "{}",
  96. ItemFeedDto = "{}",
  97. OriginalItemUrl = originalItemUrl,
  98. DeviceDto_ = new TbkDgSmartAssistantLinkConvertRequest.DeviceDtoDomain() { DeviceId = oaid, DeviceType = "OAID_MD5" }
  99. };
  100. if (targetItem != null)
  101. {
  102. req.TargetItemDto_ = targetItem;
  103. }
  104. if (itemFeed != null)
  105. {
  106. req.ItemFeedDto_ = itemFeed;
  107. }
  108. TbkDgSmartAssistantLinkConvertResponse rsp = client.Execute(req);
  109. if (_debug)
  110. {
  111. var _req = req.Convert2Json();
  112. var _rsp = rsp.Convert2Json();
  113. new LoggerLibrary("debug", this._pid).Info(_req, _rsp).Save();
  114. }
  115. return rsp;
  116. }
  117. public async Task<(List<PromotionQueryItemDTO>, string, int)> GetRecommendDataWithRetry(
  118. RecommendRequestType type, string oaid,
  119. string cookies,
  120. CancellationToken cancellationToken = default)
  121. {
  122. DateTime stime = DateTime.Now;
  123. // 假设传入了一个 CancellationToken cancellationToken 和 int maxRetries 表示最大重试次数
  124. int retryCount = 0;
  125. int maxRetries = 50;
  126. while (true)
  127. {
  128. try
  129. {
  130. (var data, cookies) = await GetRecommendData(type, oaid, cookies, cancellationToken);
  131. var ts = DateTime.Now - stime;
  132. int elapsedTime = (int)ts.TotalMilliseconds;
  133. return (data, cookies, elapsedTime);
  134. }
  135. catch (Exception ex)
  136. {
  137. if (type == RecommendRequestType.first &&
  138. ex.Message.Equals("RECOMMEND_UNKNOWN_ERROR::Recommend未知错误"))
  139. {
  140. return (new List<PromotionQueryItemDTO>(), cookies, 2);
  141. }
  142. if (retryCount >= maxRetries || cancellationToken.IsCancellationRequested)
  143. {
  144. throw;
  145. }
  146. retryCount++;
  147. await Task.Delay(100);
  148. }
  149. }
  150. }
  151. public async Task<(List<PromotionQueryItemDTO>, string)> GetRecommendData(RecommendRequestType type, string oaid,
  152. string cookies, CancellationToken cancellationToken = default)
  153. {
  154. string token = "undefined";
  155. if (!string.IsNullOrEmpty(cookies)) token = cookies.GetContentPart("_m_h5_tk=", "_");
  156. string url = GetRecommendUrl(_pid, oaid, token, type);
  157. string body = string.Empty;
  158. string ua = ProviderFakeUserAgent.RandomMobile;
  159. var client = new WebClientUtility();
  160. client.Proxy = _proxy;
  161. client.UserAgent = ua;
  162. if (string.IsNullOrEmpty(cookies))
  163. {
  164. var res = await client.RequestAsync(url, "GET", cancellationToken);
  165. if (!res.Successed) { throw res.ResponseException; }
  166. body = res.Body();
  167. if (_debug)
  168. {
  169. new LoggerLibrary("debug", oaid)
  170. .Info("第一次 cookies 初始化")
  171. .Info(ua, _proxy?.Address?.AbsoluteUri)
  172. .Info(url, body)
  173. .Save();
  174. }
  175. cookies = res.ResponseMessage.GetCookiesString();
  176. token = cookies.GetContentPart("_m_h5_tk=", "_");
  177. }
  178. url = GetRecommendUrl(_pid, oaid, token, type);
  179. client = new WebClientUtility();
  180. client.Proxy = _proxy;
  181. client.UserAgent = ua;
  182. if (!string.IsNullOrEmpty(cookies)) client.SetCookies(cookies);
  183. var response = await client.RequestAsync(url, "GET", cancellationToken);
  184. body = response.Body();
  185. if (_debug)
  186. {
  187. new LoggerLibrary("debug", oaid)
  188. .Info("GetRecommendData")
  189. .Info(ua, _proxy?.Address?.AbsoluteUri)
  190. .Info(url, cookies)
  191. .Info(body)
  192. .Save();
  193. }
  194. body = body.Trim().StringTrimStart("mtopjsonp1(");
  195. body = body.StringTrimEnd(")");
  196. var root = body.Convert2JsonElement();
  197. var ret = root.PathRead("ret[0]", string.Empty);
  198. if (!"SUCCESS::调用成功".Equals(ret))
  199. {
  200. throw new Exception(ret);
  201. }
  202. var resultList = new List<PromotionQueryItemDTO>();
  203. foreach (var data in root.ElementRead("data").ElementRead("resultList").EnumerateArray())
  204. {
  205. PromotionQueryItemDTO item = ConverPromotionQueryItem(data);
  206. resultList.Add(item);
  207. }
  208. return (resultList, cookies);
  209. }
  210. public string GetRecommendUrl(string pid, string oaid, string token, RecommendRequestType type)
  211. {
  212. var first_data = $"{{\"scene\":\"pltSimilarPromotion\",\"variableMap\":\"{{\\\"pid\\\":\\\"{pid}\\\",\\\"oaid\\\":\\\"{oaid}\\\",\\\"type\\\":\\\"first\\\"}}\"}}";
  213. var second_data = $"{{\"scene\":\"pltSimilarPromotion\",\"variableMap\":\"{{\\\"pid\\\":\\\"{pid}\\\",\\\"oaid\\\":\\\"{oaid}\\\",\\\"type\\\":\\\"second\\\"}}\"}}";
  214. var ori_data = $"{{\"scene\":\"pltPromotionImg\",\"variableMap\":\"{{\\\"pid\\\":\\\"{pid}\\\",\\\"oaid\\\":\\\"{oaid}\\\",\\\"hasCoupon\\\":false,\\\"filterType\\\":\\\"ori\\\",\\\"seq\\\":\\\"\\\"}}\"}}";
  215. string ts = DateTime.Now.Convert2UnixTimestamp(true).ToString();
  216. string data = type switch
  217. {
  218. RecommendRequestType.first => first_data,
  219. RecommendRequestType.second => second_data,
  220. _ => ori_data,
  221. };
  222. string sign = GetSign(token, ts, data);
  223. string url = $"https://h5api.m.taobao.com/h5/mtop.union.thor.landing.page.recommend/1.0/" +
  224. $"?jsv=2.4.16&appKey=12574478&t={ts}&sign={sign}&v=1.0&api=mtop.union.thor.landing.page.recommend" +
  225. $"&timeout=20000&AntiCreep=true&AntiFlood=true&type=jsonp&dataType=jsonp&callback=mtopjsonp1" +
  226. $"&data={data.UrlEncode()}";
  227. return url;
  228. }
  229. private string GetSign(string token, string ts, string data)
  230. {
  231. string g = "12574478";
  232. //%7B%22scene%22%3A%22pltPromotionImg%22%2C%22variableMap%22%3A%22%7B%5C%22pid%5C%22%3A%5C%22mm_5993059531_3080100059_115689750259%5C%22%2C%5C%22oaid%5C%22%3A%5C%22-7775661578900138800%5C%22%2C%5C%22hasCoupon%5C%22%3Afalse%2C%5C%22filterType%5C%22%3A%5C%22ori%5C%22%2C%5C%22seq%5C%22%3A%5C%22%5C%22%7D%22%7D
  233. //%7B%22scene%22%3A%22pltPromotionImg%22%2C%22variableMap%22%3A%22%7B%5C%22pid%5C%22%3A%5C%22mm_5993059531_3080100059_115689750259%5C%22%2C%5C%22oaid%5C%22%3A%5C%22-7775661578900138800%5C%22%2C%5C%22hasCoupon%5C%22%3Afalse%2C%5C%22filterType%5C%22%3A%5C%22ori%5C%22%2C%5C%22seq%5C%22%3A%5C%22%5C%22%7D%22%7D
  234. var signString = $"{token}&{ts}&{g}&{data}";
  235. return signString.MD5();
  236. }
  237. }
  238. }