promo_goods.cs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567
  1. using dodohold.core;
  2. using StackExchange.Redis;
  3. using System.Diagnostics;
  4. using System.Text.Json;
  5. namespace molilian.core
  6. {
  7. public partial class AlimamaPlus
  8. {
  9. public async Task<TkDataDTO> endpoint_promo_goods(string content, TkDataDTO result, CancellationToken cancellationToken = default)
  10. {
  11. string t = $"{DateTime.Now.Convert2UnixTimestamp(true)}";
  12. Random random = new();
  13. double randomNumber = random.NextDouble();
  14. string randomString = randomNumber.ToString()[2..];
  15. string cna = _cookies.GetContentPart("cna=", ";");
  16. string firstFiveCharacters = cna[..Math.Min(5, cna.Length)];
  17. //var variableMap = new
  18. //{
  19. // url = content,
  20. // union_lens = $"b_pvid:a219t._portal_v2_tool_links_page_home_index_htm_{t}_{randomString}_{firstFiveCharacters}",
  21. // lensScene = "PUB",
  22. // spmB = "_portal_v2_tool_links_page_home_index_htm"
  23. //}.Convert2Json(true).UrlEncode();
  24. string item_id = content.GetContentPart("item.htm?id=", "");
  25. var variableMap = new
  26. {
  27. itemId = item_id
  28. }.Convert2Json(true).UrlEncode();
  29. variableMap = variableMap.Replace(" ", "%20");
  30. _floorId = "102359";
  31. string url = "https://pub.alimama.com/openapi/param2/1/gateway.unionpub/xt.entry.json?" +
  32. $"t={t}&_tb_token_={_tb_token}&floorId={_floorId}&refpid={_refpid}&variableMap={variableMap}";
  33. Stopwatch stopwatch = Stopwatch.StartNew();
  34. stopwatch.Start();
  35. var client = new WebClientUtility().SetContentType("application/json;charset=utf-8")
  36. .AddHeaders("X-Requested-With", "XMLHttpRequest")
  37. .AddHeaders("Cookie", _cookies);
  38. client.Proxy = _proxy;
  39. #if DEBUG
  40. client.Proxy = null;
  41. #endif
  42. if (!string.IsNullOrEmpty(_user_agent)) client.UserAgent = _user_agent;
  43. client.Timeout = GetRequestTimeout2(result.elapsedTime2);
  44. //var response = client.Request(url);
  45. #if DEBUG
  46. var response = await client.RequestAsync(url, "GET");
  47. #else
  48. var response = await client.RequestAsync(url, "GET", cancellationToken);
  49. #endif
  50. stopwatch.Stop();
  51. result.elapsedTime3 = (int)stopwatch.ElapsedMilliseconds;
  52. var body = string.Empty;
  53. try
  54. {
  55. if (!response.Successed)
  56. {
  57. result.channel = TkChannelEnum.tb;
  58. result.link_type = LinkTypeEnum.unknown;
  59. result.success = false;
  60. result.message = "fail";
  61. if (response.ResponseException != null)
  62. {
  63. _ = new LoggerLibrary("api_error", "fail")
  64. .Info(response.ResponseException.Message, response.ResponseException.StackTrace)
  65. .SaveAsync();
  66. throw response.ResponseException;
  67. }
  68. return result;
  69. }
  70. if (response.ResponseMessage.StatusCode == System.Net.HttpStatusCode.Found)
  71. {
  72. _ = new LoggerLibrary("api_error", "fail")
  73. .Info($"302:{response.ResponseMessage.Headers.Location}")
  74. .SaveAsync();
  75. throw new Exception("302 Found, was canceled");
  76. }
  77. JsonElement root;
  78. try
  79. {
  80. body = response.Body();
  81. //{"success":false,"message":"result empty"}
  82. if (body.Contains("bixi.alicdn.com"))
  83. {
  84. await TkEndpointManager.SuspendAsync(_accountId, "promo_goods", TkEndpointManager.SuspendReason.Passive);
  85. result.channel = TkChannelEnum.tb;
  86. result.link_type = LinkTypeEnum.unknown;
  87. result.subCode = TkSubCodeEnum.ParseDeny;
  88. result.success = false;
  89. result.message = "waf_block";
  90. result.reason = "接口风控";
  91. return result;
  92. }
  93. root = body.Convert2JsonElement();
  94. }
  95. catch (Exception ex)
  96. {
  97. _ = new LoggerLibrary("api_error", "fail")
  98. .Info(ex.Message, ex.StackTrace)
  99. .SaveAsync();
  100. if (body.Contains("https://g.alicdn.com/sd/punish/waf_block.html"))
  101. {
  102. await TkEndpointManager.SuspendAsync(_accountId, "promo_goods", TkEndpointManager.SuspendReason.Passive);
  103. result.channel = TkChannelEnum.tb;
  104. result.link_type = LinkTypeEnum.unknown;
  105. result.success = false;
  106. result.message = "waf_block";
  107. result.reason = "接口风控";
  108. return result;
  109. }
  110. throw new Exception(body);
  111. }
  112. bool success = root.Read<bool>("success", false);
  113. string message = root.Read("message", string.Empty);
  114. string info_message = root.PathRead("info.message", string.Empty);
  115. if (!string.IsNullOrEmpty(info_message)) message = info_message;
  116. if ("result empty".Equals(message))
  117. {
  118. result.subCode = TkSubCodeEnum.NoConvert;
  119. }
  120. JsonElement item = default;
  121. if (success)
  122. {
  123. var data = root.ElementRead("data");
  124. var resultList = data.ElementRead("resultList");
  125. if (resultList.ValueKind != JsonValueKind.Array)
  126. {
  127. _ = new LoggerLibrary("api_error", "fail")
  128. .Info("resultList Undefined", body)
  129. .SaveAsync();
  130. throw new Exception("resultList Undefined");
  131. }
  132. item = resultList[0];
  133. }
  134. string taoToken = item.Read("taoToken", string.Empty);
  135. string shortLinkurl = item.Read("shortLinkurl", string.Empty);
  136. string couponLinkTaoToken = item.Read("couponLinkTaoToken", string.Empty);
  137. string couponShortLinkUrl = item.Read("couponShortLinkUrl", string.Empty);
  138. decimal couponAmount = item.Read<decimal>("couponAmount", 0);
  139. string couponEffectiveEndTime = item.Read("couponEffectiveEndTime", string.Empty);
  140. string couponEffectiveStartTime = item.Read("couponEffectiveStartTime", string.Empty);
  141. string itemId = item.Read("itemId", string.Empty);
  142. string mktId = item.Read("outputMktId", string.Empty);
  143. string itemName = item.Read("itemName", string.Empty);
  144. decimal promotionPrice = item.Read<decimal>("promotionPrice", 0);
  145. string sellerNickName = item.Read("sellerNickName", string.Empty);
  146. string shopTitle = item.Read("shopTitle", string.Empty);
  147. string pic = item.Read("data.pic", string.Empty);
  148. if (pic.StartsWith("//")) pic = "https:" + pic;
  149. string qrCodeUrl = item.Read("qrCodeUrl", string.Empty);
  150. if (response.ResponseMessage != null)
  151. {
  152. switch (response.ResponseMessage.StatusCode)
  153. {
  154. case System.Net.HttpStatusCode.OK:
  155. {
  156. if (couponAmount > 0 && !string.IsNullOrEmpty(couponLinkTaoToken) && !string.IsNullOrEmpty(couponShortLinkUrl))
  157. {
  158. taoToken = couponLinkTaoToken;
  159. shortLinkurl = couponShortLinkUrl;
  160. }
  161. string shortLink = GetLink(taoToken);
  162. content = ReplaceUrls(content, shortLink);
  163. }
  164. break;
  165. case System.Net.HttpStatusCode.Found:
  166. string location = response.ResponseMessage.Headers.Location.OriginalString;
  167. if (!string.IsNullOrEmpty(location) && location.Contains("www.alimama.com/member/login.htm"))
  168. {
  169. success = false;
  170. message = "nologin";
  171. }
  172. break;
  173. default:
  174. {
  175. success = false;
  176. message = "other";
  177. }
  178. break;
  179. }
  180. }
  181. if (!success)
  182. {
  183. shortLinkurl = GetLink(content);
  184. switch (message)
  185. {
  186. case "该商品已经下架或未加入淘宝客":
  187. case "该链接不支持转化,请更换链接尝试":
  188. case "result empty":
  189. result.subCode = TkSubCodeEnum.NoConvert;
  190. break;
  191. case "网络错误":
  192. result.subCode = TkSubCodeEnum.NetError;
  193. break;
  194. default:
  195. var _headers = response.ResponseMessage.Headers;
  196. var headers = "";
  197. foreach (var h in _headers)
  198. {
  199. foreach (var Value in h.Value)
  200. {
  201. headers += $"{h.Key}: {Value}\n";
  202. }
  203. }
  204. _ = new LoggerLibrary("api_error", "fail")
  205. .Info(message, content)
  206. .Info(headers, body)
  207. .SaveAsync();
  208. break;
  209. }
  210. }
  211. shortLinkurl = GetLink(taoToken);
  212. string deeplink_url = GetDeeplink(shortLinkurl);
  213. result.channel = TkChannelEnum.tb;
  214. if (success)
  215. {
  216. result.subCode = TkSubCodeEnum.Success;
  217. switch (result.link_type)
  218. {
  219. case LinkTypeEnum.profile:
  220. case LinkTypeEnum.goods:
  221. case LinkTypeEnum.video:
  222. case LinkTypeEnum.live:
  223. break;
  224. default:
  225. result.link_type = LinkTypeEnum.goods;
  226. break;
  227. }
  228. }
  229. result.success = success;
  230. result.message = message;
  231. result.reason = string.Empty;
  232. result.content = content;
  233. result.couponAmount = couponAmount;
  234. result.couponEffectiveEndTime = couponEffectiveEndTime;
  235. result.couponEffectiveStartTime = couponEffectiveStartTime;
  236. result.taoToken = taoToken;
  237. if (!string.IsNullOrEmpty(shortLinkurl))
  238. {
  239. result.shortLinkurl = shortLinkurl;
  240. result.deeplink_url = deeplink_url;
  241. }
  242. result.mktId = mktId;
  243. result.itemId = itemId;
  244. result.itemName = itemName;
  245. result.promotionPrice = promotionPrice;
  246. result.sellerNickName = sellerNickName;
  247. result.shopTitle = shopTitle;
  248. result.pic = pic;
  249. result.qrCodeUrl = qrCodeUrl;
  250. }
  251. catch (Exception ex)
  252. {
  253. if (response.ResponseMessage?.StatusCode == System.Net.HttpStatusCode.OK)
  254. {
  255. if (body.Contains("<p>抱歉!页面无法访问……</p>"))
  256. {
  257. throw new APIException("抱歉!页面无法访问……");
  258. }
  259. }
  260. throw;
  261. }
  262. return result;
  263. }
  264. public async Task<TkDataDTO> alimamaParseAsync(string content, TkDataDTO result, CancellationToken cancellationToken = default)
  265. {
  266. string t = $"{DateTime.Now.Convert2UnixTimestamp(true)}";
  267. Random random = new();
  268. double randomNumber = random.NextDouble();
  269. string randomString = randomNumber.ToString()[2..];
  270. string cna = _cookies.GetContentPart("cna=", ";");
  271. string firstFiveCharacters = cna[..Math.Min(5, cna.Length)];
  272. var variableMap = new
  273. {
  274. url = content,
  275. union_lens = $"b_pvid:a219t._portal_v2_tool_links_page_home_index_htm_{t}_{randomString}_{firstFiveCharacters}",
  276. lensScene = "PUB",
  277. spmB = "_portal_v2_tool_links_page_home_index_htm"
  278. }.Convert2Json(true).UrlEncode();
  279. variableMap = variableMap.Replace(" ", "%20");
  280. string url = "https://pub.alimama.com/openapi/param2/1/gateway.unionpub/xt.entry.json?" +
  281. $"t={t}&_tb_token_={_tb_token}&floorId={_floorId}&refpid={_refpid}&variableMap={variableMap}";
  282. Stopwatch stopwatch = Stopwatch.StartNew();
  283. stopwatch.Start();
  284. var client = new WebClientUtility().SetContentType("application/json;charset=utf-8")
  285. .AddHeaders("X-Requested-With", "XMLHttpRequest")
  286. .AddHeaders("Cookie", _cookies);
  287. client.Proxy = _proxy;
  288. #if DEBUG
  289. client.Proxy = null;
  290. #endif
  291. if (!string.IsNullOrEmpty(_user_agent)) client.UserAgent = _user_agent;
  292. client.Timeout = GetRequestTimeout2(result.elapsedTime2);
  293. //var response = client.Request(url);
  294. #if DEBUG
  295. var response = await client.RequestAsync(url, "GET");
  296. #else
  297. var response = await client.RequestAsync(url, "GET", cancellationToken);
  298. #endif
  299. stopwatch.Stop();
  300. result.elapsedTime3 = (int)stopwatch.ElapsedMilliseconds;
  301. var body = string.Empty;
  302. try
  303. {
  304. if (!response.Successed)
  305. {
  306. result.channel = TkChannelEnum.tb;
  307. result.link_type = LinkTypeEnum.unknown;
  308. result.success = false;
  309. result.message = "fail";
  310. if (response.ResponseException != null)
  311. {
  312. _ = new LoggerLibrary("api_error", "fail")
  313. .Info(response.ResponseException.Message, response.ResponseException.StackTrace)
  314. .SaveAsync();
  315. throw response.ResponseException;
  316. }
  317. return result;
  318. }
  319. if (response.ResponseMessage.StatusCode == System.Net.HttpStatusCode.Found)
  320. {
  321. _ = new LoggerLibrary("api_error", "fail")
  322. .Info($"302:{response.ResponseMessage.Headers.Location}")
  323. .SaveAsync();
  324. throw new Exception("302 Found, was canceled");
  325. }
  326. JsonElement root;
  327. try
  328. {
  329. body = response.Body();
  330. root = body.Convert2JsonElement();
  331. }
  332. catch (Exception ex)
  333. {
  334. _ = new LoggerLibrary("api_error", "fail")
  335. .Info(ex.Message, ex.StackTrace)
  336. .SaveAsync();
  337. if (body.Contains("https://g.alicdn.com/sd/punish/waf_block.html"))
  338. {
  339. result.channel = TkChannelEnum.tb;
  340. result.link_type = LinkTypeEnum.unknown;
  341. result.success = false;
  342. result.message = "waf_block";
  343. return result;
  344. }
  345. if (body.Contains("https://bixi.alicdn.com") && body.Contains("\"action\": \"deny\""))
  346. {
  347. result.channel = TkChannelEnum.tb;
  348. result.link_type = LinkTypeEnum.unknown;
  349. result.subCode = TkSubCodeEnum.ParseDeny;
  350. result.success = false;
  351. result.message = "waf_block";
  352. result.reason = "接口风控";
  353. return result;
  354. }
  355. throw new Exception(body);
  356. }
  357. bool success = root.Read<bool>("success", false);
  358. string message = root.Read("message", string.Empty);
  359. string info_message = root.PathRead("info.message", string.Empty);
  360. if (!string.IsNullOrEmpty(info_message)) message = info_message;
  361. string taoToken = root.PathRead("data.taoToken", string.Empty);
  362. string shortLinkurl = root.PathRead("data.shortLinkurl", string.Empty);
  363. string couponLinkTaoToken = root.PathRead("data.couponLinkTaoToken", string.Empty);
  364. string couponShortLinkUrl = root.PathRead("data.couponShortLinkUrl", string.Empty);
  365. decimal couponAmount = root.PathRead<decimal>("data.couponAmount", 0);
  366. string couponEffectiveEndTime = root.PathRead("data.couponEffectiveEndTime", string.Empty);
  367. string couponEffectiveStartTime = root.PathRead("data.couponEffectiveStartTime", string.Empty);
  368. string itemId = root.PathRead("data.itemId", string.Empty);
  369. string mktId = root.PathRead("data.outputMktId", string.Empty);
  370. string itemName = root.PathRead("data.itemName", string.Empty);
  371. decimal promotionPrice = root.PathRead<decimal>("data.promotionPrice", 0);
  372. string sellerNickName = root.PathRead("data.sellerNickName", string.Empty);
  373. string shopTitle = root.PathRead("data.shopTitle", string.Empty);
  374. string pic = root.PathRead("data.pic", string.Empty);
  375. if (pic.StartsWith("//")) pic = "https:" + pic;
  376. string qrCodeUrl = root.PathRead("data.qrCodeUrl", string.Empty);
  377. if (response.ResponseMessage != null)
  378. {
  379. switch (response.ResponseMessage.StatusCode)
  380. {
  381. case System.Net.HttpStatusCode.OK:
  382. {
  383. if (couponAmount > 0 && !string.IsNullOrEmpty(couponLinkTaoToken) && !string.IsNullOrEmpty(couponShortLinkUrl))
  384. {
  385. taoToken = couponLinkTaoToken;
  386. shortLinkurl = couponShortLinkUrl;
  387. }
  388. string shortLink = GetLink(taoToken);
  389. content = ReplaceUrls(content, shortLink);
  390. }
  391. break;
  392. case System.Net.HttpStatusCode.Found:
  393. string location = response.ResponseMessage.Headers.Location.OriginalString;
  394. if (!string.IsNullOrEmpty(location) && location.Contains("www.alimama.com/member/login.htm"))
  395. {
  396. success = false;
  397. message = "nologin";
  398. }
  399. break;
  400. default:
  401. {
  402. success = false;
  403. message = "other";
  404. }
  405. break;
  406. }
  407. }
  408. if (!success)
  409. {
  410. shortLinkurl = GetLink(content);
  411. switch (message)
  412. {
  413. case "该商品已经下架或未加入淘宝客":
  414. case "该链接不支持转化,请更换链接尝试":
  415. result.subCode = TkSubCodeEnum.NoConvert;
  416. break;
  417. case "网络错误":
  418. result.subCode = TkSubCodeEnum.NetError;
  419. break;
  420. default:
  421. var _headers = response.ResponseMessage.Headers;
  422. var headers = "";
  423. foreach (var h in _headers)
  424. {
  425. foreach (var Value in h.Value)
  426. {
  427. headers += $"{h.Key}: {Value}\n";
  428. }
  429. }
  430. _ = new LoggerLibrary("api_error", "fail")
  431. .Info(message, content)
  432. .Info(headers, body)
  433. .SaveAsync();
  434. break;
  435. }
  436. }
  437. shortLinkurl = GetLink(taoToken);
  438. string deeplink_url = GetDeeplink(shortLinkurl);
  439. result.channel = TkChannelEnum.tb;
  440. if (success)
  441. {
  442. result.subCode = TkSubCodeEnum.Success;
  443. switch (result.link_type)
  444. {
  445. case LinkTypeEnum.profile:
  446. case LinkTypeEnum.goods:
  447. case LinkTypeEnum.video:
  448. case LinkTypeEnum.live:
  449. break;
  450. default:
  451. result.link_type = LinkTypeEnum.goods;
  452. break;
  453. }
  454. }
  455. result.success = success;
  456. result.message = message;
  457. result.reason = string.Empty;
  458. result.content = content;
  459. result.couponAmount = couponAmount;
  460. result.couponEffectiveEndTime = couponEffectiveEndTime;
  461. result.couponEffectiveStartTime = couponEffectiveStartTime;
  462. result.taoToken = taoToken;
  463. if (!string.IsNullOrEmpty(shortLinkurl))
  464. {
  465. result.shortLinkurl = shortLinkurl;
  466. result.deeplink_url = deeplink_url;
  467. }
  468. result.mktId = mktId;
  469. result.itemId = itemId;
  470. result.itemName = itemName;
  471. result.promotionPrice = promotionPrice;
  472. result.sellerNickName = sellerNickName;
  473. result.shopTitle = shopTitle;
  474. result.pic = pic;
  475. result.qrCodeUrl = qrCodeUrl;
  476. }
  477. catch (Exception ex)
  478. {
  479. if (response.ResponseMessage?.StatusCode == System.Net.HttpStatusCode.OK)
  480. {
  481. if (body.Contains("<p>抱歉!页面无法访问……</p>"))
  482. {
  483. throw new APIException("抱歉!页面无法访问……");
  484. }
  485. }
  486. throw;
  487. }
  488. return result;
  489. }
  490. }
  491. }