parse_2.cs 42 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052
  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 = ProxyNodesCore.RandomOne(_account.nodeName),
  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 = ProxyNodesCore.RandomOne(_account.nodeName),
  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. shortLinkurl = GetLink(taoToken);
  685. string deeplink_url = GetDeeplink(shortLinkurl);
  686. result.channel = TkChannelEnum.tb;
  687. if (success)
  688. {
  689. result.subCode = TkSubCodeEnum.Success;
  690. switch (result.link_type)
  691. {
  692. case LinkTypeEnum.profile:
  693. case LinkTypeEnum.goods:
  694. case LinkTypeEnum.video:
  695. case LinkTypeEnum.live:
  696. break;
  697. default:
  698. result.link_type = LinkTypeEnum.goods;
  699. break;
  700. }
  701. }
  702. result.success = success;
  703. result.message = message;
  704. result.reason = string.Empty;
  705. result.content = content;
  706. result.couponAmount = couponAmount;
  707. result.couponEffectiveEndTime = couponEffectiveEndTime;
  708. result.couponEffectiveStartTime = couponEffectiveStartTime;
  709. result.taoToken = taoToken;
  710. result.shortLinkurl = shortLinkurl;
  711. result.deeplink_url = deeplink_url;
  712. result.itemId = itemId;
  713. result.itemName = itemName;
  714. result.promotionPrice = promotionPrice;
  715. result.sellerNickName = sellerNickName;
  716. result.shopTitle = shopTitle;
  717. result.pic = pic;
  718. result.qrCodeUrl = qrCodeUrl;
  719. }
  720. catch (Exception ex)
  721. {
  722. if (response.ResponseMessage?.StatusCode == System.Net.HttpStatusCode.OK)
  723. {
  724. if (body.Contains("<p>抱歉!页面无法访问……</p>"))
  725. {
  726. throw new APIException("抱歉!页面无法访问……");
  727. }
  728. }
  729. throw;
  730. }
  731. return result;
  732. }
  733. private TkDataDTO alimamaParse(string content, TkDataDTO result)
  734. {
  735. string t = $"{DateTime.Now.Convert2UnixTimestamp(true)}";
  736. Random random = new();
  737. double randomNumber = random.NextDouble();
  738. string randomString = randomNumber.ToString()[2..];
  739. string cna = _cookies.GetContentPart("cna=", ";");
  740. string firstFiveCharacters = cna[..Math.Min(5, cna.Length)];
  741. var variableMap = new
  742. {
  743. url = content,
  744. union_lens = $"b_pvid:a219t._portal_v2_tool_links_page_home_index_htm_{t}_{randomString}_{firstFiveCharacters}",
  745. lensScene = "PUB",
  746. spmB = "_portal_v2_tool_links_page_home_index_htm"
  747. }.Convert2Json(true).UrlEncode();
  748. variableMap = variableMap.Replace(" ", "%20");
  749. string url = "https://pub.alimama.com/openapi/param2/1/gateway.unionpub/xt.entry.json?" +
  750. $"t={t}&_tb_token_={_tb_token}&floorId={_floorId}&refpid={_refpid}&variableMap={variableMap}";
  751. Stopwatch stopwatch = Stopwatch.StartNew();
  752. stopwatch.Start();
  753. var client = new WebClientUtility().SetContentType("application/json;charset=utf-8")
  754. .AddHeaders("X-Requested-With", "XMLHttpRequest")
  755. .AddHeaders("Cookie", _cookies);
  756. client.Proxy = _proxy;
  757. if (!string.IsNullOrEmpty(_user_agent)) client.UserAgent = _user_agent;
  758. #if DEBUG
  759. client.Proxy = null;
  760. url = "https://47.246.177.226/openapi/param2/1/gateway.unionpub/xt.entry.json?" +
  761. $"t={t}&_tb_token_={_tb_token}&floorId={_floorId}&refpid={_refpid}&variableMap={variableMap}";
  762. client.Headers["Host"] = "pub.alimama.com";
  763. #endif
  764. client.Timeout = GetRequestTimeout(result.elapsedTime2);
  765. //var response = client.Request(url);
  766. var response = client.Request(url);
  767. stopwatch.Stop();
  768. result.elapsedTime3 = (int)stopwatch.ElapsedMilliseconds;
  769. var body = string.Empty;
  770. try
  771. {
  772. if (!response.Successed)
  773. {
  774. result.channel = TkChannelEnum.tb;
  775. result.accountId = _accountId;
  776. result.accountName = _accountName;
  777. result.link_type = LinkTypeEnum.unknown;
  778. result.success = false;
  779. result.message = "fail";
  780. if (response.ResponseException != null)
  781. {
  782. _ = new LoggerLibrary("api_error", "fail")
  783. .Info(response.ResponseException.Message, response.ResponseException.StackTrace)
  784. .SaveAsync();
  785. throw response.ResponseException;
  786. }
  787. return result;
  788. }
  789. body = response.Body();
  790. //{"code":601,"info":{"ok":false,"message":"nologin"}}
  791. JsonElement root = body.Convert2JsonElement();
  792. bool success = root.Read<bool>("success", false);
  793. string message = root.Read("message", string.Empty);
  794. string info_message = root.PathRead("info.message", string.Empty);
  795. if (!string.IsNullOrEmpty(info_message)) message = info_message;
  796. string taoToken = root.PathRead("data.taoToken", string.Empty);
  797. string shortLinkurl = root.PathRead("data.shortLinkurl", string.Empty);
  798. string couponLinkTaoToken = root.PathRead("data.couponLinkTaoToken", string.Empty);
  799. string couponShortLinkUrl = root.PathRead("data.couponShortLinkUrl", string.Empty);
  800. decimal couponAmount = root.PathRead<decimal>("data.couponAmount", 0);
  801. string couponEffectiveEndTime = root.PathRead("data.couponEffectiveEndTime", string.Empty);
  802. string couponEffectiveStartTime = root.PathRead("data.couponEffectiveStartTime", string.Empty);
  803. string itemId = root.PathRead("data.itemId", string.Empty);
  804. string itemName = root.PathRead("data.itemName", string.Empty);
  805. decimal promotionPrice = root.PathRead<decimal>("data.promotionPrice", 0);
  806. string sellerNickName = root.PathRead("data.sellerNickName", string.Empty);
  807. string shopTitle = root.PathRead("data.shopTitle", string.Empty);
  808. string pic = root.PathRead("data.pic", string.Empty);
  809. string qrCodeUrl = root.PathRead("data.qrCodeUrl", string.Empty);
  810. if (response.ResponseMessage != null)
  811. {
  812. switch (response.ResponseMessage.StatusCode)
  813. {
  814. case System.Net.HttpStatusCode.OK:
  815. {
  816. if (couponAmount > 0 && !string.IsNullOrEmpty(couponLinkTaoToken) && !string.IsNullOrEmpty(couponShortLinkUrl))
  817. {
  818. taoToken = couponLinkTaoToken;
  819. shortLinkurl = couponShortLinkUrl;
  820. }
  821. string shortLink = GetLink(taoToken);
  822. content = ReplaceUrls(content, shortLink);
  823. }
  824. break;
  825. case System.Net.HttpStatusCode.Found:
  826. string location = response.ResponseMessage.Headers.Location.OriginalString;
  827. if (!string.IsNullOrEmpty(location) && location.Contains("www.alimama.com/member/login.htm"))
  828. {
  829. success = false;
  830. message = "nologin";
  831. }
  832. break;
  833. default:
  834. {
  835. success = false;
  836. message = "other";
  837. }
  838. break;
  839. }
  840. }
  841. if (!success)
  842. {
  843. shortLinkurl = GetLink(content);
  844. switch (message)
  845. {
  846. case "该商品已经下架或未加入淘宝客":
  847. case "该链接不支持转化,请更换链接尝试":
  848. case "网络错误":
  849. break;
  850. default:
  851. var _headers = response.ResponseMessage.Headers;
  852. var headers = "";
  853. foreach (var h in _headers)
  854. {
  855. foreach (var Value in h.Value)
  856. {
  857. headers += $"{h.Key}: {Value}\n";
  858. }
  859. }
  860. _ = new LoggerLibrary("api_error", "fail")
  861. .Info(message, content)
  862. .Info(headers, body)
  863. .SaveAsync();
  864. break;
  865. }
  866. }
  867. if (success)
  868. {
  869. if (string.IsNullOrEmpty(itemName))
  870. {
  871. itemName = GetTitle(taoToken);
  872. }
  873. }
  874. else
  875. {
  876. itemName = GetTitle(content);
  877. }
  878. string deeplink_url = GetDeeplink(shortLinkurl);
  879. result.channel = TkChannelEnum.tb;
  880. result.accountId = _accountId;
  881. result.accountName = _accountName;
  882. if (success)
  883. {
  884. switch (result.link_type)
  885. {
  886. case LinkTypeEnum.profile:
  887. case LinkTypeEnum.goods:
  888. case LinkTypeEnum.video:
  889. case LinkTypeEnum.live:
  890. break;
  891. default:
  892. result.link_type = LinkTypeEnum.goods;
  893. break;
  894. }
  895. }
  896. result.success = success;
  897. result.message = message;
  898. result.content = content;
  899. result.couponAmount = couponAmount;
  900. result.couponEffectiveEndTime = couponEffectiveEndTime;
  901. result.couponEffectiveStartTime = couponEffectiveStartTime;
  902. result.taoToken = taoToken;
  903. result.shortLinkurl = shortLinkurl;
  904. result.deeplink_url = deeplink_url;
  905. result.itemId = itemId;
  906. result.itemName = itemName;
  907. result.promotionPrice = promotionPrice;
  908. result.sellerNickName = sellerNickName;
  909. result.shopTitle = shopTitle;
  910. result.pic = pic;
  911. result.qrCodeUrl = qrCodeUrl;
  912. }
  913. catch
  914. {
  915. if (response.ResponseMessage?.StatusCode == System.Net.HttpStatusCode.OK)
  916. {
  917. if (body.Contains("<p>抱歉!页面无法访问……</p>"))
  918. {
  919. throw new APIException("抱歉!页面无法访问……");
  920. }
  921. }
  922. throw;
  923. }
  924. return result;
  925. }
  926. }
  927. }