parse_2.cs 39 KB

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