parse_2.cs 42 KB

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