parse_2.cs 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032
  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. result.channel = TkChannelEnum.tb;
  580. result.link_type = LinkTypeEnum.unknown;
  581. result.success = false;
  582. result.message = "waf_block";
  583. return result;
  584. }
  585. throw new Exception(body);
  586. }
  587. bool success = root.Read<bool>("success", false);
  588. string message = root.Read("message", string.Empty);
  589. string info_message = root.PathRead("info.message", string.Empty);
  590. if (!string.IsNullOrEmpty(info_message)) message = info_message;
  591. string taoToken = root.PathRead("data.taoToken", string.Empty);
  592. string shortLinkurl = root.PathRead("data.shortLinkurl", string.Empty);
  593. string couponLinkTaoToken = root.PathRead("data.couponLinkTaoToken", string.Empty);
  594. string couponShortLinkUrl = root.PathRead("data.couponShortLinkUrl", string.Empty);
  595. decimal couponAmount = root.PathRead<decimal>("data.couponAmount", 0);
  596. string couponEffectiveEndTime = root.PathRead("data.couponEffectiveEndTime", string.Empty);
  597. string couponEffectiveStartTime = root.PathRead("data.couponEffectiveStartTime", string.Empty);
  598. string itemId = root.PathRead("data.itemId", string.Empty);
  599. string itemName = root.PathRead("data.itemName", string.Empty);
  600. decimal promotionPrice = root.PathRead<decimal>("data.promotionPrice", 0);
  601. string sellerNickName = root.PathRead("data.sellerNickName", string.Empty);
  602. string shopTitle = root.PathRead("data.shopTitle", string.Empty);
  603. string pic = root.PathRead("data.pic", string.Empty);
  604. if (pic.StartsWith("//")) pic = "https:" + pic;
  605. string qrCodeUrl = root.PathRead("data.qrCodeUrl", string.Empty);
  606. if (response.ResponseMessage != null)
  607. {
  608. switch (response.ResponseMessage.StatusCode)
  609. {
  610. case System.Net.HttpStatusCode.OK:
  611. {
  612. if (couponAmount > 0 && !string.IsNullOrEmpty(couponLinkTaoToken) && !string.IsNullOrEmpty(couponShortLinkUrl))
  613. {
  614. taoToken = couponLinkTaoToken;
  615. shortLinkurl = couponShortLinkUrl;
  616. }
  617. string shortLink = GetLink(taoToken);
  618. content = ReplaceUrls(content, shortLink);
  619. }
  620. break;
  621. case System.Net.HttpStatusCode.Found:
  622. string location = response.ResponseMessage.Headers.Location.OriginalString;
  623. if (!string.IsNullOrEmpty(location) && location.Contains("www.alimama.com/member/login.htm"))
  624. {
  625. success = false;
  626. message = "nologin";
  627. }
  628. break;
  629. default:
  630. {
  631. success = false;
  632. message = "other";
  633. }
  634. break;
  635. }
  636. }
  637. if (!success)
  638. {
  639. shortLinkurl = GetLink(content);
  640. switch (message)
  641. {
  642. case "该商品已经下架或未加入淘宝客":
  643. case "该链接不支持转化,请更换链接尝试":
  644. result.subCode = TkSubCodeEnum.NoConvert;
  645. break;
  646. case "网络错误":
  647. result.subCode = TkSubCodeEnum.NetError;
  648. break;
  649. default:
  650. var _headers = response.ResponseMessage.Headers;
  651. var headers = "";
  652. foreach (var h in _headers)
  653. {
  654. foreach (var Value in h.Value)
  655. {
  656. headers += $"{h.Key}: {Value}\n";
  657. }
  658. }
  659. _ = new LoggerLibrary("api_error", "fail")
  660. .Info(message, content)
  661. .Info(headers, body)
  662. .SaveAsync();
  663. break;
  664. }
  665. }
  666. string deeplink_url = GetDeeplink(shortLinkurl);
  667. result.channel = TkChannelEnum.tb;
  668. if (success)
  669. {
  670. result.subCode = TkSubCodeEnum.Success;
  671. switch (result.link_type)
  672. {
  673. case LinkTypeEnum.profile:
  674. case LinkTypeEnum.goods:
  675. case LinkTypeEnum.video:
  676. case LinkTypeEnum.live:
  677. break;
  678. default:
  679. result.link_type = LinkTypeEnum.goods;
  680. break;
  681. }
  682. }
  683. result.success = success;
  684. result.message = message;
  685. result.reason = string.Empty;
  686. result.content = content;
  687. result.couponAmount = couponAmount;
  688. result.couponEffectiveEndTime = couponEffectiveEndTime;
  689. result.couponEffectiveStartTime = couponEffectiveStartTime;
  690. result.taoToken = taoToken;
  691. result.shortLinkurl = shortLinkurl;
  692. result.deeplink_url = deeplink_url;
  693. result.itemId = itemId;
  694. result.itemName = itemName;
  695. result.promotionPrice = promotionPrice;
  696. result.sellerNickName = sellerNickName;
  697. result.shopTitle = shopTitle;
  698. result.pic = pic;
  699. result.qrCodeUrl = qrCodeUrl;
  700. }
  701. catch (Exception ex)
  702. {
  703. if (response.ResponseMessage?.StatusCode == System.Net.HttpStatusCode.OK)
  704. {
  705. if (body.Contains("<p>抱歉!页面无法访问……</p>"))
  706. {
  707. throw new APIException("抱歉!页面无法访问……");
  708. }
  709. }
  710. throw;
  711. }
  712. return result;
  713. }
  714. private TkDataDTO alimamaParse(string content, TkDataDTO result)
  715. {
  716. string t = $"{DateTime.Now.Convert2UnixTimestamp(true)}";
  717. Random random = new();
  718. double randomNumber = random.NextDouble();
  719. string randomString = randomNumber.ToString()[2..];
  720. string cna = _cookies.GetContentPart("cna=", ";");
  721. string firstFiveCharacters = cna[..Math.Min(5, cna.Length)];
  722. var variableMap = new
  723. {
  724. url = content,
  725. union_lens = $"b_pvid:a219t._portal_v2_tool_links_page_home_index_htm_{t}_{randomString}_{firstFiveCharacters}",
  726. lensScene = "PUB",
  727. spmB = "_portal_v2_tool_links_page_home_index_htm"
  728. }.Convert2Json(true).UrlEncode();
  729. variableMap = variableMap.Replace(" ", "%20");
  730. string url = "https://pub.alimama.com/openapi/param2/1/gateway.unionpub/xt.entry.json?" +
  731. $"t={t}&_tb_token_={_tb_token}&floorId={_floorId}&refpid={_refpid}&variableMap={variableMap}";
  732. Stopwatch stopwatch = Stopwatch.StartNew();
  733. stopwatch.Start();
  734. var client = new WebClientUtility().SetContentType("application/json;charset=utf-8")
  735. .AddHeaders("X-Requested-With", "XMLHttpRequest")
  736. .AddHeaders("Cookie", _cookies);
  737. client.Proxy = _proxy;
  738. if (!string.IsNullOrEmpty(_user_agent)) client.UserAgent = _user_agent;
  739. #if DEBUG
  740. client.Proxy = null;
  741. url = "https://47.246.177.226/openapi/param2/1/gateway.unionpub/xt.entry.json?" +
  742. $"t={t}&_tb_token_={_tb_token}&floorId={_floorId}&refpid={_refpid}&variableMap={variableMap}";
  743. client.Headers["Host"] = "pub.alimama.com";
  744. #endif
  745. client.Timeout = GetRequestTimeout(result.elapsedTime2);
  746. //var response = client.Request(url);
  747. var response = client.Request(url);
  748. stopwatch.Stop();
  749. result.elapsedTime3 = (int)stopwatch.ElapsedMilliseconds;
  750. var body = string.Empty;
  751. try
  752. {
  753. if (!response.Successed)
  754. {
  755. result.channel = TkChannelEnum.tb;
  756. result.accountId = _accountId;
  757. result.accountName = _accountName;
  758. result.link_type = LinkTypeEnum.unknown;
  759. result.success = false;
  760. result.message = "fail";
  761. if (response.ResponseException != null)
  762. {
  763. _ = new LoggerLibrary("api_error", "fail")
  764. .Info(response.ResponseException.Message, response.ResponseException.StackTrace)
  765. .SaveAsync();
  766. throw response.ResponseException;
  767. }
  768. return result;
  769. }
  770. body = response.Body();
  771. //{"code":601,"info":{"ok":false,"message":"nologin"}}
  772. JsonElement root = body.Convert2JsonElement();
  773. bool success = root.Read<bool>("success", false);
  774. string message = root.Read("message", string.Empty);
  775. string info_message = root.PathRead("info.message", string.Empty);
  776. if (!string.IsNullOrEmpty(info_message)) message = info_message;
  777. string taoToken = root.PathRead("data.taoToken", string.Empty);
  778. string shortLinkurl = root.PathRead("data.shortLinkurl", string.Empty);
  779. string couponLinkTaoToken = root.PathRead("data.couponLinkTaoToken", string.Empty);
  780. string couponShortLinkUrl = root.PathRead("data.couponShortLinkUrl", string.Empty);
  781. decimal couponAmount = root.PathRead<decimal>("data.couponAmount", 0);
  782. string couponEffectiveEndTime = root.PathRead("data.couponEffectiveEndTime", string.Empty);
  783. string couponEffectiveStartTime = root.PathRead("data.couponEffectiveStartTime", string.Empty);
  784. string itemId = root.PathRead("data.itemId", string.Empty);
  785. string itemName = root.PathRead("data.itemName", string.Empty);
  786. decimal promotionPrice = root.PathRead<decimal>("data.promotionPrice", 0);
  787. string sellerNickName = root.PathRead("data.sellerNickName", string.Empty);
  788. string shopTitle = root.PathRead("data.shopTitle", string.Empty);
  789. string pic = root.PathRead("data.pic", string.Empty);
  790. string qrCodeUrl = root.PathRead("data.qrCodeUrl", string.Empty);
  791. if (response.ResponseMessage != null)
  792. {
  793. switch (response.ResponseMessage.StatusCode)
  794. {
  795. case System.Net.HttpStatusCode.OK:
  796. {
  797. if (couponAmount > 0 && !string.IsNullOrEmpty(couponLinkTaoToken) && !string.IsNullOrEmpty(couponShortLinkUrl))
  798. {
  799. taoToken = couponLinkTaoToken;
  800. shortLinkurl = couponShortLinkUrl;
  801. }
  802. string shortLink = GetLink(taoToken);
  803. content = ReplaceUrls(content, shortLink);
  804. }
  805. break;
  806. case System.Net.HttpStatusCode.Found:
  807. string location = response.ResponseMessage.Headers.Location.OriginalString;
  808. if (!string.IsNullOrEmpty(location) && location.Contains("www.alimama.com/member/login.htm"))
  809. {
  810. success = false;
  811. message = "nologin";
  812. }
  813. break;
  814. default:
  815. {
  816. success = false;
  817. message = "other";
  818. }
  819. break;
  820. }
  821. }
  822. if (!success)
  823. {
  824. shortLinkurl = GetLink(content);
  825. switch (message)
  826. {
  827. case "该商品已经下架或未加入淘宝客":
  828. case "该链接不支持转化,请更换链接尝试":
  829. case "网络错误":
  830. break;
  831. default:
  832. var _headers = response.ResponseMessage.Headers;
  833. var headers = "";
  834. foreach (var h in _headers)
  835. {
  836. foreach (var Value in h.Value)
  837. {
  838. headers += $"{h.Key}: {Value}\n";
  839. }
  840. }
  841. _ = new LoggerLibrary("api_error", "fail")
  842. .Info(message, content)
  843. .Info(headers, body)
  844. .SaveAsync();
  845. break;
  846. }
  847. }
  848. if (success)
  849. {
  850. if (string.IsNullOrEmpty(itemName))
  851. {
  852. itemName = GetTitle(taoToken);
  853. }
  854. }
  855. else
  856. {
  857. itemName = GetTitle(content);
  858. }
  859. string deeplink_url = GetDeeplink(shortLinkurl);
  860. result.channel = TkChannelEnum.tb;
  861. result.accountId = _accountId;
  862. result.accountName = _accountName;
  863. if (success)
  864. {
  865. switch (result.link_type)
  866. {
  867. case LinkTypeEnum.profile:
  868. case LinkTypeEnum.goods:
  869. case LinkTypeEnum.video:
  870. case LinkTypeEnum.live:
  871. break;
  872. default:
  873. result.link_type = LinkTypeEnum.goods;
  874. break;
  875. }
  876. }
  877. result.success = success;
  878. result.message = message;
  879. result.content = content;
  880. result.couponAmount = couponAmount;
  881. result.couponEffectiveEndTime = couponEffectiveEndTime;
  882. result.couponEffectiveStartTime = couponEffectiveStartTime;
  883. result.taoToken = taoToken;
  884. result.shortLinkurl = shortLinkurl;
  885. result.deeplink_url = deeplink_url;
  886. result.itemId = itemId;
  887. result.itemName = itemName;
  888. result.promotionPrice = promotionPrice;
  889. result.sellerNickName = sellerNickName;
  890. result.shopTitle = shopTitle;
  891. result.pic = pic;
  892. result.qrCodeUrl = qrCodeUrl;
  893. }
  894. catch
  895. {
  896. if (response.ResponseMessage?.StatusCode == System.Net.HttpStatusCode.OK)
  897. {
  898. if (body.Contains("<p>抱歉!页面无法访问……</p>"))
  899. {
  900. throw new APIException("抱歉!页面无法访问……");
  901. }
  902. }
  903. throw;
  904. }
  905. return result;
  906. }
  907. }
  908. }