527 lines
29 KiB
C#
527 lines
29 KiB
C#
using Api.Framework.Tools;
|
||
using Api.Framework.Utils;
|
||
using CsharpHttpHelper;
|
||
using Newtonsoft.Json;
|
||
using System;
|
||
using System.Collections;
|
||
using System.Collections.Generic;
|
||
using System.Drawing;
|
||
using System.IO;
|
||
using System.Linq;
|
||
using System.Text;
|
||
using System.Text.RegularExpressions;
|
||
using System.Threading.Tasks;
|
||
using TBAppraisalTools.Entitys;
|
||
|
||
namespace TBAppraisalTools
|
||
{
|
||
/// <summary>
|
||
/// 淘宝解析类
|
||
/// </summary>
|
||
public class TbAnalysis
|
||
{
|
||
/// <summary>
|
||
/// 获得淘宝的基础信息
|
||
/// </summary>
|
||
/// <param name="itemId">宝贝id</param>
|
||
/// <param name="cookies">淘宝的cookies</param>
|
||
public TbBaseInfo FindTbBaseInfo(string itemId)
|
||
{
|
||
// 目标: 店铺名称,店铺头像,标题,主图,价格,月销 优惠券金额,有效期 - 自定义
|
||
try
|
||
{
|
||
var html = "";
|
||
//var item = TbTools.GetH5Result("mtop.taobao.detail.getdetail", new { itemNumId = itemId, exParams = new { id = itemId }, detail_v = "3.1.1", ttid = "2018@taobao_iphone_9.9.9", utdid = "123123123123123" }, out html);
|
||
|
||
var item = TbTools.GetH5Result("mtop.taobao.detail.getdetail", new { itemNumId = itemId, exParams = new { id = itemId }, ttid = "2016@taobao_h5_2.0.0", isSec = "0", ecode = "0", AntiFlood = "true", AntiCreep = "true", H5Request = "true", type = "jsonp", dataType = "jsonp" }, out html);
|
||
|
||
var _item = item["item"] as Dictionary<string, object>;
|
||
var sellerId = string.Empty;
|
||
//这里可以通过图片的地址获取店铺的id
|
||
if (_item.ContainsKey("images"))
|
||
{
|
||
var images = _item["images"] as ArrayList;
|
||
if (images != null && images.Count != 0)
|
||
{
|
||
var reg = Regex.Match(images[0].ToString(), @"http://img.alicdn.com/imgextra/i\d/(?<店铺Id>\d+)/");
|
||
if (reg.Success)
|
||
sellerId = reg.Groups["店铺Id"].Value;
|
||
}
|
||
}
|
||
|
||
var price = string.Empty;//价格
|
||
var sellCount = string.Empty;
|
||
var apiStack = item["apiStack"] as ArrayList;
|
||
if (apiStack != null && apiStack.Count != 0)
|
||
{
|
||
var _apiStack = apiStack[0] as Dictionary<string, object>;
|
||
if (_apiStack.ContainsKey("value"))
|
||
{
|
||
var valueJsonStr = _apiStack["value"].ToString();
|
||
var valueJson = HttpExtend.JsonToDictionary(valueJsonStr);
|
||
|
||
#region 获取销量 sellCount
|
||
var itemTag = valueJson["item"] as Dictionary<string, object>;
|
||
if (itemTag.ContainsKey("sellCount"))
|
||
sellCount = itemTag["sellCount"].ToString();
|
||
#endregion
|
||
|
||
#region 获取价格 price
|
||
var priceTag = valueJson["price"] as Dictionary<string, object>;
|
||
if (priceTag.ContainsKey("price"))
|
||
{
|
||
var priceSub = priceTag["price"] as Dictionary<string, object>;
|
||
if (priceSub.ContainsKey("priceText"))
|
||
price = priceSub["priceText"].ToString();
|
||
}
|
||
if (string.IsNullOrEmpty(price) && priceTag.ContainsKey("transmitPrice"))
|
||
{
|
||
var transmitPrice = priceTag["transmitPrice"] as Dictionary<string, object>;
|
||
if (transmitPrice.ContainsKey("priceText"))
|
||
price = transmitPrice["priceText"].ToString();
|
||
}
|
||
if (!string.IsNullOrEmpty(price) && price.Contains("-")) //TODO 这里可能还存在带问号的价格,目前不清楚是什么情况,先空着
|
||
price = price.Split('-')[0];
|
||
#endregion
|
||
}
|
||
}
|
||
|
||
var _seller = item["seller"] as Dictionary<string, object>;
|
||
//店铺名称
|
||
var shopName = _seller["shopName"].ToString();
|
||
//店铺图片
|
||
string shopIcon = _seller["shopIcon"].ToString();
|
||
shopIcon = string.IsNullOrEmpty(shopIcon) ? "https://ss2.bdstatic.com/8_V1bjqh_Q23odCf/pacific/1659832877.jpg" : shopIcon.StartsWith("http") ? _seller["shopIcon"].ToString() : "http:" + _seller["shopIcon"].ToString();
|
||
if (string.IsNullOrEmpty(shopIcon) || shopName == "天猫超市")
|
||
shopIcon = "https://ss2.bdstatic.com/8_V1bjqh_Q23odCf/pacific/1659832877.jpg";
|
||
var userId = _seller["userId"].ToString();
|
||
//主图图片
|
||
var item_image = string.Empty;
|
||
if (_item.ContainsKey("images"))
|
||
item_image = (_item["images"] as ArrayList)[0].ToString();
|
||
//商品标题
|
||
var item_title = _item["title"].ToString();
|
||
|
||
return new TbBaseInfo() { ItemId = itemId, ItemImage = item_image, ItemTitle = item_title, Price = price, SellCount = sellCount, ShopIcon = shopIcon, ShopName = shopName, UserId = userId, SellerId = sellerId };
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
return null;
|
||
}
|
||
}
|
||
|
||
private Random ra = new Random();
|
||
|
||
/// <summary>
|
||
/// 生成优惠券图片
|
||
/// </summary>
|
||
/// <param name="tb">宝贝的信息</param>
|
||
/// <returns>返回生成后优惠券的路径,异常直接报错</returns>
|
||
public string GenerateCouponImage(TbBaseInfo tb)
|
||
{
|
||
try
|
||
{
|
||
if (File.Exists(TbTools.TBCONFIGJSON))//存在优惠券模板的情况
|
||
{
|
||
var objDic = JsonConvert.DeserializeObject<Dictionary<string, TbConfig>>(File.ReadAllText(TbTools.TBCONFIGJSON));
|
||
if (objDic != null)
|
||
{
|
||
var panel = objDic.FirstOrDefault(f => f.Key.Contains("panel"));
|
||
if (!default(KeyValuePair<string, object>).Equals(panel))
|
||
{
|
||
TbConfig tbConfig = objDic[panel.Key] as TbConfig;
|
||
if (!File.Exists(TbTools.BACKICO)) throw new Exception("不存在优惠券背景图");
|
||
var backImage = Tools.RefreshFileAddress(TbTools.BACKICO, TbTools.BASEPATH + @"\", Util.MapPath(TbTools.BASEPATH));
|
||
using (var backIco = new Bitmap(Image.FromFile(backImage), tbConfig.C_Size))
|
||
{
|
||
using (Graphics g = Graphics.FromImage(backIco))
|
||
{
|
||
#region 计算优惠券价 discounts
|
||
var srcPrice = float.Parse(tb.Price);
|
||
var rates = Class1.Config.CouponDenomination.Split('-');
|
||
float min = 0.3f;//默认最小比例
|
||
float max = 0.6f;//默认最大比例
|
||
if (rates.Length == 2)
|
||
{
|
||
min = float.Parse(rates[0]) / 100f;//最小比例
|
||
max = float.Parse(rates[1]) / 100f;//最大比例
|
||
}
|
||
var discounts = (ra.Next(int.Parse(Math.Ceiling(srcPrice * min).ToString()), int.Parse(Math.Ceiling(srcPrice * max).ToString())));
|
||
//默认选中取整 时 - 商品现价要是小于10的时候,将不会取整,其他的取十的倍数
|
||
if (Class1.Config.IsRounding == Api.Framework.Enums.SwitchType.开启)
|
||
{
|
||
if (discounts > 10 && discounts < srcPrice)
|
||
{
|
||
double xx = discounts / 10;
|
||
discounts = int.Parse((Math.Round(xx) * 10).ToString());
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
foreach (KeyValuePair<string, TbConfig> item in objDic)
|
||
{
|
||
var temp = item.Value;
|
||
if (item.Key.Contains("label"))
|
||
{
|
||
var validityBegin = string.Empty;//优惠券有效期开始日期
|
||
var validityEnd = string.Empty;//优惠券有效期结局日期
|
||
#region 计算优惠券有效期区间
|
||
if (temp.T_Text.Contains("#开始时间") || temp.T_Text.Contains("#结束时间"))
|
||
{
|
||
var tempDate = DateTime.Now.AddDays(Class1.Config.ManufacturePlansAddDay);
|
||
validityBegin = tempDate.ToString("yyyy.MM.dd");
|
||
validityEnd = tempDate.AddDays(Class1.Config.ExpirationDate).ToString("yyyy.MM.dd");
|
||
}
|
||
#endregion
|
||
|
||
var txt = temp.T_Text
|
||
.Replace("#店铺名称", tb.ShopName)
|
||
.Replace("#商品标题", tb.ItemTitle)
|
||
.Replace("#商品现价", tb.Price)
|
||
.Replace("#月销售量", tb.SellCount)
|
||
.Replace("#优惠券价", discounts.ToString())
|
||
.Replace("#券后特价", (float.Parse(tb.Price) - discounts).ToString())
|
||
.Replace("#开始时间", validityBegin)
|
||
.Replace("#结束时间", validityEnd);
|
||
SizeF crSize = new SizeF();
|
||
crSize = g.MeasureString(txt, temp.T_Font);
|
||
txt = Tools.RefreshTextFormat(tbConfig.C_Size.Width, temp.C_Point.X, txt, crSize.Width);
|
||
g.DrawString(txt, temp.T_Font, new SolidBrush(temp.T_ForeColor), temp.C_Point);
|
||
}
|
||
else if (item.Key.Contains("picbox"))
|
||
{
|
||
var tagDic = CsharpHttpHelper.HttpExtend.JsonToDictionary(temp.C_Tag.ToString());
|
||
var imageInfo = new ImageInfo() { ImagePath = tagDic["ImagePath"].ToString(), Shape = tagDic["Shape"].ToString() == "false" ? false : true, Varible = tagDic["Varible"].ToString() };
|
||
|
||
Bitmap bitmap = null;
|
||
|
||
if (imageInfo.Varible == "#店铺头像" || imageInfo.Varible == "#商品主图")
|
||
{
|
||
var cacheFile = TbTools.RandomFile();
|
||
Tools.DownloadImage(imageInfo.Varible == "#商品主图" ? tb.ItemImage : tb.ShopIcon, cacheFile);
|
||
bitmap = new Bitmap(Tools.ReadImageFile(cacheFile), temp.C_Size);
|
||
}
|
||
else if (imageInfo.Varible == "#其他图片")
|
||
{
|
||
var otherImage = Tools.RefreshFileAddress(imageInfo.ImagePath, @"评价工具\其他图片\", TbTools.OTHERSICOPATH);
|
||
bitmap = Tools.ReadImageFile(otherImage);
|
||
}
|
||
if (bitmap != null)
|
||
{
|
||
g.DrawImage(bitmap, temp.C_Point);
|
||
bitmap.Dispose();
|
||
bitmap = null;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
var url = TbTools.RandomFile();
|
||
backIco.Save(url);
|
||
return url;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else
|
||
throw new Exception("未找到优惠券模板配置文件");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
throw ex;
|
||
}
|
||
return string.Empty;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 通过宝贝id获取宝贝评价标签集合
|
||
/// </summary>
|
||
/// <param name="itemId">宝贝id</param>
|
||
/// <returns>返回标签集合</returns>
|
||
public List<TagCloud> FindTagsByItemId(string itemId)
|
||
{
|
||
try
|
||
{
|
||
var tags = TbTools.FindTagsByItemId(itemId);
|
||
if (tags != null) tags = tags.Where(f => f.posi).ToList();
|
||
return tags;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
throw ex;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取PC端的评语信息
|
||
/// </summary>
|
||
/// <param name="itemId">宝贝Id</param>
|
||
/// <param name="sellerId">店铺Id</param>
|
||
/// <param name="analyticPageNum">分析多少页</param>
|
||
/// <param name="tagid">标签的id</param>
|
||
/// <returns></returns>
|
||
public List<Comment> FindPcCommentInfos(string itemId, string sellerId, int analyticPageNum, int tagid = 0)
|
||
{
|
||
try
|
||
{
|
||
try
|
||
{
|
||
var comments = new List<Comment>();
|
||
for (int i = 1; i <= analyticPageNum; i++)
|
||
{
|
||
//int error = 0;
|
||
// Next:
|
||
string url = string.Format("https://rate.tmall.com/list_detail_rate.htm?itemId={0}&sellerId={1}&order=3¤tPage={2}&append=0&content=1&posi=1&picture=&callback=jsonp443&tagId={3}", itemId, sellerId, analyticPageNum, tagid);
|
||
|
||
//var cookies = Tools.ReadTBCookies();
|
||
HttpHelper http = new HttpHelper();
|
||
var item = http.GetItem(url);
|
||
item.Cookie = TbTools.RandomTbCookies();
|
||
item.Allowautoredirect = true;
|
||
item.UserAgent = @"Mozilla/4.0 (compatible; MSIE 9.0; Windows NT6.1)";
|
||
item.ContentType = @"application/x-www-form-urlencoded";
|
||
var result = http.GetHtml(item);
|
||
var html = result.Html.Trim();
|
||
//TbCookies = result.Cookie;//这个就不保存了,因为写了淘宝心跳
|
||
if (!html.StartsWith("jsonp443")) throw new Exception("评语解析不出:" + html);
|
||
|
||
html = html.Replace("jsonp443(", "").Replace(")", "");
|
||
var json = HttpExtend.JsonToDictionary(html) as Dictionary<string, object>;
|
||
if (json != null && json.ContainsKey("rgv587_flag"))//登录过期
|
||
throw new Exception("淘宝已经掉线,请重新登录~!");//这里可能会是频率显示(歇息一下,喝口水什么的)
|
||
if (json == null || !json.ContainsKey("rateDetail")) throw new Exception("未获得评价数据:" + html);
|
||
json = json["rateDetail"] as Dictionary<string, object>;
|
||
|
||
if (!json.ContainsKey("rateList")) throw new Exception("该宝贝没有评论数据");
|
||
var list = json["rateList"] as ArrayList;
|
||
|
||
foreach (Dictionary<string, object> obj in list)
|
||
{
|
||
var pics = obj["pics"] as ArrayList;
|
||
var comment = new Comment() { position = obj["position"].ToString(), rateContent = obj["rateContent"].ToString() };
|
||
if (pics != null)
|
||
{
|
||
foreach (var t in pics)
|
||
{
|
||
comment.pics.Add("http:" + t);
|
||
}
|
||
}
|
||
comments.Add(comment);
|
||
}
|
||
if (json.ContainsKey("paginator"))//获取评论区的页数
|
||
{
|
||
var paginator = json["paginator"] as Dictionary<string, object>;
|
||
var lastPage = int.Parse(paginator["lastPage"].ToString());//总页数
|
||
var page = int.Parse(paginator["page"].ToString());//当前页数
|
||
if (lastPage <= page) break;
|
||
}
|
||
}
|
||
return comments;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
throw ex;
|
||
}
|
||
//return new List<Comment>();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
throw ex;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取移动端的评语信息
|
||
/// </summary>
|
||
/// <param name="itemId">宝贝Id</param>
|
||
/// <param name="sellerId">店铺Id</param>
|
||
/// <param name="analyticPageNum">分析多少页</param>
|
||
/// <param name="tagid">标签Id</param>
|
||
/// <returns></returns>
|
||
public List<Comment> FindWebappCommentInfos(string itemId, int analyticPageNum)
|
||
{
|
||
try
|
||
{
|
||
List<Comment> commentList = new List<Comment>();
|
||
TaskTool tasks = new TaskTool();
|
||
for (int i = 1; i <= analyticPageNum; i++)
|
||
{
|
||
|
||
var _i = i;
|
||
tasks.AddTask(delegate
|
||
{
|
||
try
|
||
{
|
||
//获取评价json数据
|
||
var json = string.Empty;
|
||
var _url = @"https://rate.taobao.com/feedRateList.htm?auctionNumId=" + itemId + "&userNumId=" + new Random(Guid.NewGuid().GetHashCode()).Next(100000, 999999).ToString() + new Random(Guid.NewGuid().GetHashCode()).Next(10000, 99999) + "¤tPageNum=" + _i + "&pageSize=20&rateType=&orderType=sort_weight&attribute=&sku=&hasSku=false&folded=0&callback=jsonp_tbcrate_reviews_list";
|
||
HttpHelper http = new HttpHelper();
|
||
var temp = http.GetItem(_url);
|
||
temp.Cookie = TbTools.RandomTbCookies();
|
||
temp.SetProxyipCDN();
|
||
temp.Allowautoredirect = true;
|
||
temp.UserAgent = @"Mozilla/4.0 (compatible; MSIE 9.0; Windows NT6.1)";
|
||
temp.ContentType = @"application/x-www-form-urlencoded";
|
||
var rst = http.GetHtml(temp);
|
||
//if (!string.IsNullOrEmpty(rst.Cookie)) rst.UpdateCookies(temp.Cookie);//更新cookies
|
||
json = rst.Html.Replace("jsonp_tbcrate_reviews_list(", "").Trim();
|
||
json = json.Substring(0, json.Length - 1);
|
||
//StringBuilder strb = new StringBuilder();
|
||
//StringBuilder strbPic = new StringBuilder();
|
||
|
||
var obj = HttpExtend.JsonToDictionary(json);
|
||
|
||
#region 最大页数
|
||
var maxPageObj = obj["maxPage"];
|
||
var maxPage = -1;
|
||
if (maxPageObj != null)
|
||
maxPage = int.Parse(maxPageObj.ToString());
|
||
#endregion
|
||
|
||
#region 获取评语和图片数据
|
||
var comments = obj["comments"] as ArrayList;
|
||
if (comments != null && comments.Count != 0)
|
||
{
|
||
foreach (var _item in comments)
|
||
{
|
||
var pj = new Comment();
|
||
var item = _item as Dictionary<string, object>;
|
||
var photos = item["photos"] as ArrayList;
|
||
if (photos != null && photos.Count != 0)
|
||
{
|
||
foreach (var _pic in photos)
|
||
{
|
||
var pic = _pic as Dictionary<string, object>;
|
||
var url = pic["url"].ToString();//图片
|
||
pj.pics.Add("http:" + url);
|
||
}
|
||
}
|
||
var content = item["content"].ToString();//初评语
|
||
if (content != "此用户没有填写评价。")
|
||
pj.rateContent = content;
|
||
var appendList = item["appendList"] as ArrayList;//追评数量
|
||
if (appendList != null && appendList.Count != 0)
|
||
{
|
||
foreach (var _appendItem in appendList)//追评部分
|
||
{
|
||
var appendItem = _appendItem as Dictionary<string, object>;
|
||
var appendPhotos = appendItem["photos"] as ArrayList;
|
||
if (appendPhotos != null && appendPhotos.Count != 0)
|
||
{
|
||
foreach (var _appendPic in appendPhotos)
|
||
{
|
||
var appendPic = _appendPic as Dictionary<string, object>;
|
||
var appendUrl = appendPic["url"].ToString();//追加图片
|
||
pj.pics.Add("http:" + appendUrl);
|
||
}
|
||
}
|
||
var appendContent = appendItem["content"].ToString();//追评语
|
||
if (content != "此用户没有填写评价。")
|
||
pj.rateContent += appendContent;
|
||
}
|
||
}
|
||
if (!string.IsNullOrEmpty(pj.rateContent)) commentList.Add(pj);
|
||
}
|
||
}
|
||
#endregion
|
||
}
|
||
catch { }
|
||
});
|
||
}
|
||
tasks.Start(10, null);
|
||
return commentList;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
throw ex;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 将图片集合转换成Gif图片
|
||
/// </summary>
|
||
/// <param name="pics">图片集合</param>
|
||
/// <param name="secondImage">最后一针图片(底图)</param>
|
||
/// <param name="path"></param>
|
||
/// <param name="time">图片之间的间隔时间</param>
|
||
/// <param name="repeat">是否重复</param>
|
||
public void FindGifsBySrcPic(List<string> pics, string secondImage, string path, string itemId, int time = 0, bool repeat = false)
|
||
{
|
||
try
|
||
{
|
||
if (pics != null && pics.Count != 0) //判断是否图片集合为空
|
||
{
|
||
//if (Directory.Exists(path)) //检测是否存在日期部分的目录
|
||
//{
|
||
// if (Directory.Exists($"{path}\\{itemId}")) //检测当天解析的宝贝一样时,删除之前解析的所有内容
|
||
// Tools.DelectDir(path);
|
||
//}
|
||
//else
|
||
// throw new Exception("解析以后保存路径不存在,请先设置保存路径");
|
||
|
||
TaskTool tasks = new TaskTool(); //定义线程池
|
||
|
||
foreach (var pic in pics) //循环要遍历的图片
|
||
{
|
||
tasks.AddTask(delegate () //添加线程任务
|
||
{
|
||
try
|
||
{
|
||
var secondImg = Tools.ReadImageFile(secondImage); //获取优惠券bitmap
|
||
var bitmap = Tools.ZoomPicture(Image.FromFile(pic), secondImg.Width, secondImg.Height);//评价图压缩成和优惠券图大小一致
|
||
Graphics g = null;
|
||
if (File.Exists(TbTools.BUTTONICO)) //是否有按钮图标
|
||
{
|
||
g = Graphics.FromImage(bitmap); //创建以底图为基础的画板
|
||
var bitmapLogo = Tools.ReadImageFile(TbTools.BUTTONICO); //按钮图片bitmap
|
||
int size = 200; //按钮大小
|
||
float rate = 2.00f; //比例
|
||
bitmapLogo = new Bitmap(bitmapLogo, new Size(size, size)); //固定按钮的大小
|
||
var point = new PointF(secondImg.Width / rate - size / rate, secondImg.Height / rate - size / rate); //按钮的坐标
|
||
g.DrawImage(bitmapLogo, point); //将按钮画在底图中
|
||
}
|
||
//000000000000
|
||
var saveImgPath = TbTools.RandomFile(); //带随机名字的缓存地址(临时图片)
|
||
bitmap.Save(saveImgPath); //将评价图保存只缓存
|
||
if (g != null) //如果增加了按钮,则将画板释放
|
||
g.Dispose();
|
||
bitmap.Dispose(); //释放
|
||
|
||
if (Class1.Config.BondCommentPic == Api.Framework.Enums.SwitchType.开启)
|
||
{
|
||
var gifFile = Tools.PngsToGif(new string[] { saveImgPath, secondImage }, Util.MapFile(Guid.NewGuid().ToString() + ".png", path), time, repeat); //将处理好的图片保存在宝贝路径中
|
||
if (!string.IsNullOrEmpty(gifFile))
|
||
{
|
||
if (File.Exists(saveImgPath))
|
||
try
|
||
{
|
||
File.Delete(saveImgPath); //删除临时图片
|
||
}
|
||
catch (Exception ex)
|
||
{ }
|
||
}
|
||
}
|
||
else
|
||
{
|
||
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
|
||
}
|
||
});
|
||
}
|
||
tasks.Start(8, null); //执行线程池
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
throw ex;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
}
|
||
}
|