parse_2.cs 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027
  1. using dodohold.core;
  2. using System.Text.RegularExpressions;
  3. using System.Diagnostics;
  4. using System.Text.Json;
  5. using TencentCloud.Fmu.V20191213.Models;
  6. using System;
  7. using MySqlX.XDevAPI;
  8. using static dodohold.core.ZTOExpress.CreateOrderArgs;
  9. using System.Threading;
  10. using TencentCloud.Tcm.V20210413.Models;
  11. using COSXML.Network;
  12. namespace molilian.core
  13. {
  14. public partial class AlimamaPlus
  15. {
  16. public static async Task<TkDataDTO> testTaskAsync(TkDataDTO result, CancellationToken token)
  17. {
  18. string url = "https://www.taobao.com";
  19. try
  20. {
  21. WebClientUtility client = new WebClientUtility();
  22. Thread.Sleep(5000);
  23. //await Task.Delay(5000, token); // 使用Task.Delay代替Thread.Sleep
  24. client.Timeout = TimeSpan.FromMilliseconds(3000);
  25. var response = await client.RequestAsync(url);
  26. var body = response.Body();
  27. }
  28. catch
  29. {
  30. result.success = false;
  31. result.message = "Error";
  32. }
  33. return result;
  34. }
  35. public void UnionParse2(string content, ref TkDataDTO result)
  36. {
  37. if ("veapi".Equals(_api) && _api_id > 0)
  38. {
  39. var account = VeapiPoolCore.Get(_api_id);
  40. if (account != null)
  41. {
  42. var core = new VeapiPlus(account.name, account.key, account.sessionKey);
  43. core.UnionParse(content, ref result);
  44. return;
  45. }
  46. }
  47. UnionParse(content, ref result);
  48. }
  49. public async Task<TkDataDTO> UnionParse2Async(string content, TkDataDTO result,
  50. CancellationToken cancellationToken = default,
  51. Dictionary<string, long> swData = null)
  52. {
  53. if ("veapi".Equals(_api) && _api_id > 0)
  54. {
  55. var account = VeapiPoolCore.Get(_api_id);
  56. if (account != null)
  57. {
  58. var core = new VeapiPlus(account.name, account.key, account.sessionKey);
  59. result = await core.UnionParseAsync(content, result, cancellationToken);
  60. return result;
  61. }
  62. }
  63. result = await UnionParseAsync(content, result, cancellationToken, swData);
  64. return result;
  65. }
  66. /// <summary>
  67. /// 提取url里面的id参数
  68. /// </summary>
  69. /// <param name="url"></param>
  70. /// <returns></returns>
  71. public static string? ExtractItemId(string url)
  72. {
  73. Match match = Regex.Match(url, @"(?:\?|&)id=(\d+)");
  74. if (match.Success)
  75. {
  76. return match.Groups[1].Value;
  77. }
  78. return null;
  79. }
  80. /// <summary>
  81. /// 是否淘宝链接,如果是商品链接就格式化成https://item.taobao.com/item.htm?id=****
  82. /// </summary>
  83. /// <param name="url"></param>
  84. /// <returns></returns>
  85. private static (bool, string) IsTaobaoUrl(string url)
  86. {
  87. if (url.Contains("//a.m.taobao.com/i"))
  88. {
  89. //第一种提取方法
  90. string itemId = url.GetContentPart("//a.m.taobao.com/i", ".htm");
  91. if (!string.IsNullOrEmpty(itemId))
  92. {
  93. string resultUrl = $"https://item.taobao.com/item.htm?id={itemId}";
  94. return (true, resultUrl);
  95. }
  96. }
  97. if (url.Contains("//item.taobao.com/item.htm?") ||
  98. url.Contains("//main.m.taobao.com/detail/index.html?") ||
  99. url.Contains("//h5.m.taobao.com/awp/core/detail.htm?") ||
  100. url.Contains("//new.m.taobao.com/detail.htm?") ||
  101. url.Contains("//outfliggys.m.taobao.com/app/trip/rx-travel-detail") ||
  102. url.Contains("//detail.m.tmall.com/item.htm?") ||
  103. url.Contains("//tmallx.tmall.com/app/tmallx-src/goods-detail") ||
  104. url.Contains("//detail.tmall.com/item.htm?") ||
  105. url.Contains("//internal.tt.detail.taobao.com/item.htm?") ||
  106. url.Contains("//detail.tmall.hk/hk/item.htm?"))
  107. {
  108. string? itemId = ExtractItemId(url);
  109. if (!string.IsNullOrEmpty(itemId))
  110. {
  111. string resultUrl = $"https://item.taobao.com/item.htm?id={itemId}";
  112. return (true, resultUrl);
  113. }
  114. }
  115. return (false, url);
  116. }
  117. /// <summary>
  118. /// 排除已知的淘客链接
  119. /// </summary>
  120. /// <param name="url"></param>
  121. /// <returns></returns>
  122. public static bool IsAffLink(string url)
  123. {
  124. if (!url.StartsWith("https://") || !url.StartsWith("https://")) url = "https://" + url;
  125. Uri uri = new(url);
  126. if (uri.Host.Equals("s.click.taobao.com", StringComparison.OrdinalIgnoreCase) ||
  127. uri.Host.Equals("uland.taobao.com", StringComparison.OrdinalIgnoreCase))
  128. {
  129. return true;
  130. }
  131. return false;
  132. }
  133. /// <summary>
  134. /// 判断淘客的¥羊角符号
  135. /// </summary>
  136. /// <param name="content"></param>
  137. /// <returns></returns>
  138. static bool ContainsSpecialFormat(string content)
  139. {
  140. // 使用正则表达式匹配内容中是否含有特定格式的字符串
  141. //string pattern = @"¥[a-zA-Z0-9\s]+¥";
  142. string pattern = @"[$¥🗝₴€₤£₳✔《💰🔑🎵✔️💲🔐📲₡]+[a-zA-Z0-9\s]+[$¥🗝₴€₤£₳✔《💰🔑🎵✔️💲🔐📲₡]*";
  143. return Regex.IsMatch(content, pattern);
  144. }
  145. public TimeSpan GetRequestTimeout(int deduction = 0)
  146. {
  147. #if DEBUG
  148. return TimeSpan.FromMilliseconds(10 * 1000);
  149. #endif
  150. int min = (int)(_config.rt_max * 0.3);
  151. if (_config.rt_max == 0) return TimeSpan.FromMilliseconds(1000);
  152. int timeout = _config.rt_max;
  153. if (deduction == 0)
  154. {
  155. timeout -= min;
  156. return TimeSpan.FromMilliseconds(timeout);
  157. }
  158. timeout -= deduction;
  159. if (timeout <= min) return TimeSpan.FromMilliseconds(1);
  160. return TimeSpan.FromMilliseconds(min);
  161. }
  162. /// <summary>
  163. /// 从http获取跳转的url
  164. /// </summary>
  165. /// <param name="url"></param>
  166. /// <returns></returns>
  167. public async Task<(bool, string)> GetDesiredUrlAsync(string url, CancellationToken cancellationToken = default)
  168. {
  169. string result;
  170. try
  171. {
  172. if (!url.Contains("m.tb.cn") && !url.Contains("s.tb.cn"))
  173. return (false, "不是淘宝短网址");
  174. if (!_account.enable_deep_url) return (true, url);
  175. string desiredUrlPattern = "var url = '(.*?)'";
  176. WebClientUtility client = new()
  177. {
  178. Proxy = _proxy,
  179. UserAgent = Sayaka.Common.ProviderFakeUserAgent.RandomComputer
  180. };
  181. #if DEBUG
  182. client.Proxy = null;
  183. var response = await client.RequestAsync(url, "GET");
  184. #else
  185. client.Timeout = GetRequestTimeout(0);
  186. var response = await client.RequestAsync(url, "GET", cancellationToken);
  187. #endif
  188. var responseBody = response.Body();
  189. result = responseBody;
  190. if (response.Successed)
  191. {
  192. if (response.ResponseMessage.IsSuccessStatusCode)
  193. {
  194. Match match = Regex.Match(responseBody, desiredUrlPattern);
  195. if (match.Success)
  196. {
  197. result = match.Groups[1].Value; // 返回匹配的 URL
  198. if (string.IsNullOrEmpty(result)) return (false, "没有匹配的URL");
  199. if (result.StartsWith("//"))
  200. result = "https:" + result;
  201. return (true, result);
  202. }
  203. }
  204. else
  205. {
  206. result = $"{response.ResponseMessage.StatusCode}\n{responseBody}";
  207. }
  208. }
  209. else
  210. {
  211. throw response.ResponseException;
  212. }
  213. }
  214. catch (Exception ex)
  215. {
  216. _ = new LoggerLibrary("api_error", "desiredUrl_error").Info(ex.Message, ex.StackTrace).SaveAsync();
  217. result = $"{ex.Message}\n{ex.StackTrace}";
  218. }
  219. return (false, result);
  220. }
  221. /// <summary>
  222. /// 从http获取跳转的url
  223. /// </summary>
  224. /// <param name="url"></param>
  225. /// <returns></returns>
  226. (bool, string) GetDesiredUrl(string url)
  227. {
  228. string result;
  229. try
  230. {
  231. if (!url.Contains("m.tb.cn") && !url.Contains("s.tb.cn"))
  232. return (false, "不是淘宝短网址");
  233. string desiredUrlPattern = "var url = '(.*?)'";
  234. WebClientUtility client = new()
  235. {
  236. Proxy = _proxy,
  237. UserAgent = Sayaka.Common.ProviderFakeUserAgent.RandomComputer
  238. };
  239. #if DEBUG
  240. client.Proxy = null;
  241. #endif
  242. client.Timeout = GetRequestTimeout(0);
  243. var response = client.Request(url);
  244. var responseBody = response.Body();
  245. result = responseBody;
  246. if (response.Successed)
  247. {
  248. if (response.ResponseMessage.IsSuccessStatusCode)
  249. {
  250. Match match = Regex.Match(responseBody, desiredUrlPattern);
  251. if (match.Success)
  252. {
  253. result = match.Groups[1].Value; // 返回匹配的 URL
  254. if (string.IsNullOrEmpty(result)) return (false, "没有匹配的URL");
  255. return (true, result);
  256. }
  257. }
  258. else
  259. {
  260. result = $"{response.ResponseMessage.StatusCode}\n{responseBody}";
  261. }
  262. }
  263. else
  264. {
  265. throw response.ResponseException;
  266. }
  267. }
  268. catch (Exception ex)
  269. {
  270. result = $"{ex.Message}\n{ex.StackTrace}";
  271. }
  272. return (false, result);
  273. }
  274. private void InternalTextProcessing(string content, ref TkDataDTO result)
  275. {
  276. //(result.success, result.content, result.link_type, result.shortLinkurl) = InternalTextProcessing(content,ref result);
  277. bool success;
  278. string resultText;
  279. LinkTypeEnum link_type = LinkTypeEnum.unknown;
  280. string url = GetLink(content);
  281. if (!string.IsNullOrEmpty(url))
  282. {
  283. //排除已知的淘客链接
  284. if (IsAffLink(url))
  285. {
  286. result.success = false;
  287. result.content = "排除淘客链接";
  288. result.link_type = LinkTypeEnum.other_aff;
  289. result.shortLinkurl = url;
  290. return;
  291. //return (false, "排除淘客链接", LinkTypeEnum.other_aff, url);
  292. }
  293. //直接提取
  294. (success, resultText) = IsTaobaoUrl(url);
  295. if (success)
  296. {
  297. result.success = true;
  298. result.content = resultText;
  299. result.link_type = LinkTypeEnum.goods;
  300. result.shortLinkurl = resultText;
  301. return;
  302. //return (true, result, LinkTypeEnum.goods, result);
  303. }
  304. //从http获取跳转的url
  305. Stopwatch stopwatch = Stopwatch.StartNew();
  306. stopwatch.Start();
  307. (success, resultText) = GetDesiredUrl(url);
  308. stopwatch.Stop();
  309. // 获取执行时间
  310. result.elapsedTime2 = (int)stopwatch.ElapsedMilliseconds;
  311. if (success)
  312. {
  313. //排除已知的淘客链接
  314. if (IsAffLink(resultText))
  315. {
  316. result.success = false;
  317. result.content = "排除淘客链接";
  318. result.link_type = LinkTypeEnum.other_aff;
  319. result.shortLinkurl = url;
  320. return;
  321. //return (false, "排除淘客链接", LinkTypeEnum.other_aff, url);
  322. }
  323. (success, resultText) = IsTaobaoUrl(resultText);
  324. if (success)
  325. {
  326. result.success = true;
  327. result.content = resultText;
  328. result.link_type = LinkTypeEnum.goods;
  329. result.shortLinkurl = resultText;
  330. return;
  331. //return (true, resultText, LinkTypeEnum.goods, resultText);
  332. }
  333. link_type = GetLinkType(resultText);
  334. }
  335. else
  336. {
  337. link_type = GetLinkType(url);
  338. }
  339. result.success = false;
  340. result.content = resultText;
  341. result.link_type = link_type;
  342. result.shortLinkurl = url;
  343. return;
  344. //return (false, result, link_type, url);
  345. }
  346. //判断淘客的¥羊角符号
  347. if (ContainsSpecialFormat(content))
  348. {
  349. result.success = false;
  350. result.content = "排除淘口令";
  351. result.link_type = LinkTypeEnum.other_aff;
  352. result.shortLinkurl = null;
  353. return;
  354. //return (false, "排除淘口令", LinkTypeEnum.other_aff, null);
  355. }
  356. //todo 临时应急 0614
  357. //return (false, "纯口令 没链接", link_type, null);
  358. result.success = false;
  359. result.content = "纯口令 没链接";
  360. result.link_type = LinkTypeEnum.other_aff;
  361. result.shortLinkurl = null;
  362. }
  363. public async Task<TkDataDTO> InternalTextProcessingAsync(string content, TkDataDTO result,
  364. CancellationToken cancellationToken = default,
  365. Dictionary<string, long> swData = null)
  366. {
  367. bool success;
  368. string resultText;
  369. result.link_type = LinkTypeEnum.unknown;
  370. //============================== 放弃转链-其他推广链接 ==============================
  371. string url = GetLink(content);
  372. if (!string.IsNullOrEmpty(url))
  373. {
  374. bool is_aff = IsAffLink(url);
  375. if (is_aff)
  376. {
  377. result.success = false;
  378. result.message = "放弃转链";
  379. result.reason = "其他推广链接";
  380. result.subCode = TkSubCodeEnum.OtherPromo;
  381. result.link_type = LinkTypeEnum.other_aff;
  382. result.shortLinkurl = url;
  383. return result;
  384. }
  385. (success, resultText) = IsTaobaoUrl(url);
  386. if (success)
  387. {
  388. result.success = true;
  389. result.content = resultText;
  390. result.link_type = LinkTypeEnum.goods;
  391. result.shortLinkurl = resultText;
  392. return result;
  393. }
  394. Stopwatch sw = Stopwatch.StartNew();
  395. (success, resultText) = await GetDesiredUrlAsync(url, cancellationToken);
  396. sw.Stop();
  397. // 获取执行时间
  398. result.elapsedTime2 = (int)sw.ElapsedMilliseconds;
  399. swData?.Add("\tGetDesiredUrlAsync", sw.ElapsedMilliseconds);
  400. //============================== 放弃转链-请求超时 ==============================
  401. #if DEBUG
  402. #else
  403. if (result.elapsedTime2 >= _config.rt_max || (!success && resultText.Contains("was canceled")))
  404. {
  405. result.success = false;
  406. result.message = "放弃转链";
  407. result.reason = "请求超时";
  408. result.subCode = TkSubCodeEnum.Other;
  409. return result;
  410. }
  411. #endif
  412. if (success)
  413. {
  414. string desiredUrl = resultText;
  415. //============================== 放弃转链-其他推广链接 ==============================
  416. bool is_aff2 = IsAffLink(desiredUrl);
  417. if (is_aff2)
  418. {
  419. result.success = false;
  420. result.message = "放弃转链";
  421. result.reason = "其他推广链接";
  422. result.subCode = TkSubCodeEnum.OtherPromo;
  423. result.link_type = LinkTypeEnum.other_aff;
  424. result.shortLinkurl = url;
  425. return result;
  426. }
  427. (success, desiredUrl) = IsTaobaoUrl(desiredUrl);
  428. if (success)
  429. {
  430. result.success = true;
  431. result.content = desiredUrl;
  432. result.link_type = LinkTypeEnum.goods;
  433. result.shortLinkurl = desiredUrl;
  434. return result;
  435. }
  436. result.link_type = GetLinkType(desiredUrl);
  437. }
  438. else
  439. {
  440. result.link_type = GetLinkType(url);
  441. }
  442. if (result.content.Contains("霸下通用 web 页面-验证码"))
  443. {
  444. result.subCode = TkSubCodeEnum.Captcha;
  445. result.reason = "霸下验证码";
  446. }
  447. else
  448. {
  449. if (result.link_type == LinkTypeEnum.baseDomain)
  450. {
  451. result.content = content;
  452. }
  453. else
  454. {
  455. result.reason = "非标准链接";
  456. result.subCode = TkSubCodeEnum.NonStdLink;
  457. }
  458. }
  459. result.success = false;
  460. result.message = "放弃转链";
  461. result.content = resultText;
  462. result.shortLinkurl = url;
  463. return result;
  464. //return (false, result, link_type, url);
  465. }
  466. //判断淘客的¥羊角符号
  467. bool is_aff3 = ContainsSpecialFormat(content);
  468. if (is_aff3)
  469. {
  470. result.success = false;
  471. result.message = "放弃转链";
  472. result.reason = "排除淘口令";
  473. result.subCode = TkSubCodeEnum.OtherPromo;
  474. result.link_type = LinkTypeEnum.other_aff;
  475. result.shortLinkurl = null;
  476. return result;
  477. //return (false, "排除淘口令", LinkTypeEnum.other_aff, null);
  478. }
  479. //todo 临时应急 0614
  480. //return (false, "纯口令 没链接", link_type, null);
  481. result.success = false;
  482. result.message = "放弃转链";
  483. result.reason = "纯口令 没链接";
  484. result.subCode = TkSubCodeEnum.OtherPromo;
  485. result.link_type = LinkTypeEnum.other_aff;
  486. result.shortLinkurl = null;
  487. return result;
  488. }
  489. private LinkTypeEnum GetLinkType(string url)
  490. {
  491. if (string.IsNullOrEmpty(url)) return LinkTypeEnum.unknown;
  492. if (url.Contains("m.tb.cn") || url.Contains("s.tb.cn")) return LinkTypeEnum.baseDomain;
  493. if (url.StartsWith("https://huodong.m.taobao.com/act/talent/live.html")) return LinkTypeEnum.live;
  494. if (url.StartsWith("https://web.m.taobao.com/app/tnode/web/index")) return LinkTypeEnum.video;
  495. if (url.StartsWith("https://shop.m.taobao.com/shop/shopIndex.htm")) return LinkTypeEnum.profile;
  496. string pattern = @"^https://shop\d+\.m\.taobao\.com";
  497. if (Regex.IsMatch(url, pattern))
  498. {
  499. return LinkTypeEnum.profile;
  500. }
  501. //https://shop.m.taobao.com/shop/shopIndex.htm?
  502. return LinkTypeEnum.unknown;
  503. }
  504. public async Task<TkDataDTO> alimamaParseAsync(string content, TkDataDTO result, CancellationToken cancellationToken = default)
  505. {
  506. string t = $"{DateTime.Now.Convert2UnixTimestamp(true)}";
  507. Random random = new();
  508. double randomNumber = random.NextDouble();
  509. string randomString = randomNumber.ToString()[2..];
  510. string cna = _cookies.GetContentPart("cna=", ";");
  511. string firstFiveCharacters = cna[..Math.Min(5, cna.Length)];
  512. var variableMap = new
  513. {
  514. url = content,
  515. union_lens = $"b_pvid:a219t._portal_v2_tool_links_page_home_index_htm_{t}_{randomString}_{firstFiveCharacters}",
  516. lensScene = "PUB",
  517. spmB = "_portal_v2_tool_links_page_home_index_htm"
  518. }.Convert2Json(true).UrlEncode();
  519. variableMap = variableMap.Replace(" ", "%20");
  520. string url = "https://pub.alimama.com/openapi/param2/1/gateway.unionpub/xt.entry.json?" +
  521. $"t={t}&_tb_token_={_tb_token}&floorId={_floorId}&refpid={_refpid}&variableMap={variableMap}";
  522. Stopwatch stopwatch = Stopwatch.StartNew();
  523. stopwatch.Start();
  524. var client = new WebClientUtility().SetContentType("application/json;charset=utf-8")
  525. .AddHeaders("X-Requested-With", "XMLHttpRequest")
  526. .AddHeaders("Cookie", _cookies);
  527. client.Proxy = _proxy;
  528. #if DEBUG
  529. client.Proxy = null;
  530. #endif
  531. if (!string.IsNullOrEmpty(_user_agent)) client.UserAgent = _user_agent;
  532. client.Timeout = GetRequestTimeout(result.elapsedTime2);
  533. //var response = client.Request(url);
  534. #if DEBUG
  535. var response = await client.RequestAsync(url, "GET");
  536. #else
  537. var response = await client.RequestAsync(url, "GET", cancellationToken);
  538. #endif
  539. stopwatch.Stop();
  540. result.elapsedTime3 = (int)stopwatch.ElapsedMilliseconds;
  541. var body = string.Empty;
  542. try
  543. {
  544. if (!response.Successed)
  545. {
  546. result.channel = TkChannelEnum.tb;
  547. result.link_type = LinkTypeEnum.unknown;
  548. result.success = false;
  549. result.message = "fail";
  550. if (response.ResponseException != null)
  551. {
  552. _ = new LoggerLibrary("api_error", "fail")
  553. .Info(response.ResponseException.Message, response.ResponseException.StackTrace)
  554. .SaveAsync();
  555. throw response.ResponseException;
  556. }
  557. return result;
  558. }
  559. if (response.ResponseMessage.StatusCode == System.Net.HttpStatusCode.Found)
  560. {
  561. _ = new LoggerLibrary("api_error", "fail")
  562. .Info($"302:{response.ResponseMessage.Headers.Location}")
  563. .SaveAsync();
  564. throw new Exception("302 Found, was canceled");
  565. }
  566. JsonElement root;
  567. try
  568. {
  569. body = response.Body();
  570. root = body.Convert2JsonElement();
  571. }
  572. catch (Exception ex)
  573. {
  574. _ = new LoggerLibrary("api_error", "fail")
  575. .Info(ex.Message, ex.StackTrace)
  576. .SaveAsync();
  577. if (body.Contains("https://g.alicdn.com/sd/punish/waf_block.html"))
  578. {
  579. throw new Exception("waf_block");
  580. }
  581. throw new Exception(body);
  582. }
  583. bool success = root.Read<bool>("success", false);
  584. string message = root.Read("message", string.Empty);
  585. string info_message = root.PathRead("info.message", string.Empty);
  586. if (!string.IsNullOrEmpty(info_message)) message = info_message;
  587. string taoToken = root.PathRead("data.taoToken", string.Empty);
  588. string shortLinkurl = root.PathRead("data.shortLinkurl", string.Empty);
  589. string couponLinkTaoToken = root.PathRead("data.couponLinkTaoToken", string.Empty);
  590. string couponShortLinkUrl = root.PathRead("data.couponShortLinkUrl", string.Empty);
  591. decimal couponAmount = root.PathRead<decimal>("data.couponAmount", 0);
  592. string couponEffectiveEndTime = root.PathRead("data.couponEffectiveEndTime", string.Empty);
  593. string couponEffectiveStartTime = root.PathRead("data.couponEffectiveStartTime", string.Empty);
  594. string itemId = root.PathRead("data.itemId", string.Empty);
  595. string itemName = root.PathRead("data.itemName", string.Empty);
  596. decimal promotionPrice = root.PathRead<decimal>("data.promotionPrice", 0);
  597. string sellerNickName = root.PathRead("data.sellerNickName", string.Empty);
  598. string shopTitle = root.PathRead("data.shopTitle", string.Empty);
  599. string pic = root.PathRead("data.pic", string.Empty);
  600. if (pic.StartsWith("//")) pic = "https:" + pic;
  601. string qrCodeUrl = root.PathRead("data.qrCodeUrl", string.Empty);
  602. if (response.ResponseMessage != null)
  603. {
  604. switch (response.ResponseMessage.StatusCode)
  605. {
  606. case System.Net.HttpStatusCode.OK:
  607. {
  608. if (couponAmount > 0 && !string.IsNullOrEmpty(couponLinkTaoToken) && !string.IsNullOrEmpty(couponShortLinkUrl))
  609. {
  610. taoToken = couponLinkTaoToken;
  611. shortLinkurl = couponShortLinkUrl;
  612. }
  613. string shortLink = GetLink(taoToken);
  614. content = ReplaceUrls(content, shortLink);
  615. }
  616. break;
  617. case System.Net.HttpStatusCode.Found:
  618. string location = response.ResponseMessage.Headers.Location.OriginalString;
  619. if (!string.IsNullOrEmpty(location) && location.Contains("www.alimama.com/member/login.htm"))
  620. {
  621. success = false;
  622. message = "nologin";
  623. }
  624. break;
  625. default:
  626. {
  627. success = false;
  628. message = "other";
  629. }
  630. break;
  631. }
  632. }
  633. if (!success)
  634. {
  635. shortLinkurl = GetLink(content);
  636. switch (message)
  637. {
  638. case "该商品已经下架或未加入淘宝客":
  639. case "该链接不支持转化,请更换链接尝试":
  640. result.subCode = TkSubCodeEnum.NoConvert;
  641. break;
  642. case "网络错误":
  643. result.subCode = TkSubCodeEnum.NetError;
  644. break;
  645. default:
  646. var _headers = response.ResponseMessage.Headers;
  647. var headers = "";
  648. foreach (var h in _headers)
  649. {
  650. foreach (var Value in h.Value)
  651. {
  652. headers += $"{h.Key}: {Value}\n";
  653. }
  654. }
  655. _ = new LoggerLibrary("api_error", "fail")
  656. .Info(message, content)
  657. .Info(headers, body)
  658. .SaveAsync();
  659. break;
  660. }
  661. }
  662. string deeplink_url = GetDeeplink(shortLinkurl);
  663. result.channel = TkChannelEnum.tb;
  664. if (success)
  665. {
  666. result.subCode = TkSubCodeEnum.Success;
  667. switch (result.link_type)
  668. {
  669. case LinkTypeEnum.profile:
  670. case LinkTypeEnum.goods:
  671. case LinkTypeEnum.video:
  672. case LinkTypeEnum.live:
  673. break;
  674. default:
  675. result.link_type = LinkTypeEnum.goods;
  676. break;
  677. }
  678. }
  679. result.success = success;
  680. result.message = message;
  681. result.reason = string.Empty;
  682. result.content = content;
  683. result.couponAmount = couponAmount;
  684. result.couponEffectiveEndTime = couponEffectiveEndTime;
  685. result.couponEffectiveStartTime = couponEffectiveStartTime;
  686. result.taoToken = taoToken;
  687. result.shortLinkurl = shortLinkurl;
  688. result.deeplink_url = deeplink_url;
  689. result.itemId = itemId;
  690. result.itemName = itemName;
  691. result.promotionPrice = promotionPrice;
  692. result.sellerNickName = sellerNickName;
  693. result.shopTitle = shopTitle;
  694. result.pic = pic;
  695. result.qrCodeUrl = qrCodeUrl;
  696. }
  697. catch (Exception ex)
  698. {
  699. if (response.ResponseMessage?.StatusCode == System.Net.HttpStatusCode.OK)
  700. {
  701. if (body.Contains("<p>抱歉!页面无法访问……</p>"))
  702. {
  703. throw new APIException("抱歉!页面无法访问……");
  704. }
  705. }
  706. throw;
  707. }
  708. return result;
  709. }
  710. private TkDataDTO alimamaParse(string content, TkDataDTO result)
  711. {
  712. string t = $"{DateTime.Now.Convert2UnixTimestamp(true)}";
  713. Random random = new();
  714. double randomNumber = random.NextDouble();
  715. string randomString = randomNumber.ToString()[2..];
  716. string cna = _cookies.GetContentPart("cna=", ";");
  717. string firstFiveCharacters = cna[..Math.Min(5, cna.Length)];
  718. var variableMap = new
  719. {
  720. url = content,
  721. union_lens = $"b_pvid:a219t._portal_v2_tool_links_page_home_index_htm_{t}_{randomString}_{firstFiveCharacters}",
  722. lensScene = "PUB",
  723. spmB = "_portal_v2_tool_links_page_home_index_htm"
  724. }.Convert2Json(true).UrlEncode();
  725. variableMap = variableMap.Replace(" ", "%20");
  726. string url = "https://pub.alimama.com/openapi/param2/1/gateway.unionpub/xt.entry.json?" +
  727. $"t={t}&_tb_token_={_tb_token}&floorId={_floorId}&refpid={_refpid}&variableMap={variableMap}";
  728. Stopwatch stopwatch = Stopwatch.StartNew();
  729. stopwatch.Start();
  730. var client = new WebClientUtility().SetContentType("application/json;charset=utf-8")
  731. .AddHeaders("X-Requested-With", "XMLHttpRequest")
  732. .AddHeaders("Cookie", _cookies);
  733. client.Proxy = _proxy;
  734. if (!string.IsNullOrEmpty(_user_agent)) client.UserAgent = _user_agent;
  735. #if DEBUG
  736. client.Proxy = null;
  737. url = "https://47.246.177.226/openapi/param2/1/gateway.unionpub/xt.entry.json?" +
  738. $"t={t}&_tb_token_={_tb_token}&floorId={_floorId}&refpid={_refpid}&variableMap={variableMap}";
  739. client.Headers["Host"] = "pub.alimama.com";
  740. #endif
  741. client.Timeout = GetRequestTimeout(result.elapsedTime2);
  742. //var response = client.Request(url);
  743. var response = client.Request(url);
  744. stopwatch.Stop();
  745. result.elapsedTime3 = (int)stopwatch.ElapsedMilliseconds;
  746. var body = string.Empty;
  747. try
  748. {
  749. if (!response.Successed)
  750. {
  751. result.channel = TkChannelEnum.tb;
  752. result.accountId = _accountId;
  753. result.accountName = _accountName;
  754. result.link_type = LinkTypeEnum.unknown;
  755. result.success = false;
  756. result.message = "fail";
  757. if (response.ResponseException != null)
  758. {
  759. _ = new LoggerLibrary("api_error", "fail")
  760. .Info(response.ResponseException.Message, response.ResponseException.StackTrace)
  761. .SaveAsync();
  762. throw response.ResponseException;
  763. }
  764. return result;
  765. }
  766. body = response.Body();
  767. //{"code":601,"info":{"ok":false,"message":"nologin"}}
  768. JsonElement root = body.Convert2JsonElement();
  769. bool success = root.Read<bool>("success", false);
  770. string message = root.Read("message", string.Empty);
  771. string info_message = root.PathRead("info.message", string.Empty);
  772. if (!string.IsNullOrEmpty(info_message)) message = info_message;
  773. string taoToken = root.PathRead("data.taoToken", string.Empty);
  774. string shortLinkurl = root.PathRead("data.shortLinkurl", string.Empty);
  775. string couponLinkTaoToken = root.PathRead("data.couponLinkTaoToken", string.Empty);
  776. string couponShortLinkUrl = root.PathRead("data.couponShortLinkUrl", string.Empty);
  777. decimal couponAmount = root.PathRead<decimal>("data.couponAmount", 0);
  778. string couponEffectiveEndTime = root.PathRead("data.couponEffectiveEndTime", string.Empty);
  779. string couponEffectiveStartTime = root.PathRead("data.couponEffectiveStartTime", string.Empty);
  780. string itemId = root.PathRead("data.itemId", string.Empty);
  781. string itemName = root.PathRead("data.itemName", string.Empty);
  782. decimal promotionPrice = root.PathRead<decimal>("data.promotionPrice", 0);
  783. string sellerNickName = root.PathRead("data.sellerNickName", string.Empty);
  784. string shopTitle = root.PathRead("data.shopTitle", string.Empty);
  785. string pic = root.PathRead("data.pic", string.Empty);
  786. string qrCodeUrl = root.PathRead("data.qrCodeUrl", string.Empty);
  787. if (response.ResponseMessage != null)
  788. {
  789. switch (response.ResponseMessage.StatusCode)
  790. {
  791. case System.Net.HttpStatusCode.OK:
  792. {
  793. if (couponAmount > 0 && !string.IsNullOrEmpty(couponLinkTaoToken) && !string.IsNullOrEmpty(couponShortLinkUrl))
  794. {
  795. taoToken = couponLinkTaoToken;
  796. shortLinkurl = couponShortLinkUrl;
  797. }
  798. string shortLink = GetLink(taoToken);
  799. content = ReplaceUrls(content, shortLink);
  800. }
  801. break;
  802. case System.Net.HttpStatusCode.Found:
  803. string location = response.ResponseMessage.Headers.Location.OriginalString;
  804. if (!string.IsNullOrEmpty(location) && location.Contains("www.alimama.com/member/login.htm"))
  805. {
  806. success = false;
  807. message = "nologin";
  808. }
  809. break;
  810. default:
  811. {
  812. success = false;
  813. message = "other";
  814. }
  815. break;
  816. }
  817. }
  818. if (!success)
  819. {
  820. shortLinkurl = GetLink(content);
  821. switch (message)
  822. {
  823. case "该商品已经下架或未加入淘宝客":
  824. case "该链接不支持转化,请更换链接尝试":
  825. case "网络错误":
  826. break;
  827. default:
  828. var _headers = response.ResponseMessage.Headers;
  829. var headers = "";
  830. foreach (var h in _headers)
  831. {
  832. foreach (var Value in h.Value)
  833. {
  834. headers += $"{h.Key}: {Value}\n";
  835. }
  836. }
  837. _ = new LoggerLibrary("api_error", "fail")
  838. .Info(message, content)
  839. .Info(headers, body)
  840. .SaveAsync();
  841. break;
  842. }
  843. }
  844. if (success)
  845. {
  846. if (string.IsNullOrEmpty(itemName))
  847. {
  848. itemName = GetTitle(taoToken);
  849. }
  850. }
  851. else
  852. {
  853. itemName = GetTitle(content);
  854. }
  855. string deeplink_url = GetDeeplink(shortLinkurl);
  856. result.channel = TkChannelEnum.tb;
  857. result.accountId = _accountId;
  858. result.accountName = _accountName;
  859. if (success)
  860. {
  861. switch (result.link_type)
  862. {
  863. case LinkTypeEnum.profile:
  864. case LinkTypeEnum.goods:
  865. case LinkTypeEnum.video:
  866. case LinkTypeEnum.live:
  867. break;
  868. default:
  869. result.link_type = LinkTypeEnum.goods;
  870. break;
  871. }
  872. }
  873. result.success = success;
  874. result.message = message;
  875. result.content = content;
  876. result.couponAmount = couponAmount;
  877. result.couponEffectiveEndTime = couponEffectiveEndTime;
  878. result.couponEffectiveStartTime = couponEffectiveStartTime;
  879. result.taoToken = taoToken;
  880. result.shortLinkurl = shortLinkurl;
  881. result.deeplink_url = deeplink_url;
  882. result.itemId = itemId;
  883. result.itemName = itemName;
  884. result.promotionPrice = promotionPrice;
  885. result.sellerNickName = sellerNickName;
  886. result.shopTitle = shopTitle;
  887. result.pic = pic;
  888. result.qrCodeUrl = qrCodeUrl;
  889. }
  890. catch
  891. {
  892. if (response.ResponseMessage?.StatusCode == System.Net.HttpStatusCode.OK)
  893. {
  894. if (body.Contains("<p>抱歉!页面无法访问……</p>"))
  895. {
  896. throw new APIException("抱歉!页面无法访问……");
  897. }
  898. }
  899. throw;
  900. }
  901. return result;
  902. }
  903. }
  904. }