parse_2.cs 42 KB

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