parse_2.cs 42 KB

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