提交 b7b0a674 authored 作者: Whispa's avatar Whispa

commit

上级 37e87b9b
......@@ -73,6 +73,26 @@
<version>1.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.yunpian.sdk/yunpian-java-sdk -->
<dependency>
<groupId>com.yunpian.sdk</groupId>
<artifactId>yunpian-java-sdk</artifactId>
<version>1.2.5</version>
<exclusions>
<exclusion>
<artifactId>commons-logging</artifactId>
<groupId>commons-logging</groupId>
</exclusion>
<exclusion>
<artifactId>httpclient</artifactId>
<groupId>org.apache.httpcomponents</groupId>
</exclusion>
<exclusion>
<artifactId>httpcore</artifactId>
<groupId>org.apache.httpcomponents</groupId>
</exclusion>
</exclusions>
</dependency>
<!-- OSS-->
<dependency>
<groupId>com.aliyun.oss</groupId>
......@@ -80,6 +100,22 @@
<version>3.8.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.jsoup/jsoup 解析html-->
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.12.1</version>
</dependency>
<!--stripe-->
<dependency>
<groupId>com.stripe</groupId>
<artifactId>stripe-java</artifactId>
<version>11.6.1</version>
</dependency>
<dependency>
<groupId>com.google.firebase</groupId>
<artifactId>firebase-admin</artifactId>
......@@ -119,6 +155,20 @@
<artifactId>commons-lang3</artifactId>
<!--<version>3.8</version>-->
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/org.apache.commons.lang -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>org.apache.commons.lang</artifactId>
<version>2.4.0</version>
</dependency>
<!--解码-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-text</artifactId>
<version>1.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/net.sf.json-lib/json-lib -->
<dependency>
<groupId>net.sf.json-lib</groupId>
......@@ -143,6 +193,26 @@
</exclusion>
</exclusions>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-lang/commons-lang -->
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-email -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-email</artifactId>
<version>1.5</version>
<exclusions>
<exclusion>
<artifactId>activation</artifactId>
<groupId>javax.activation</groupId>
</exclusion>
</exclusions>
</dependency>
<!--发邮件 END-->
</dependencies>
<build>
......
package com.example.afrishop_v3.bis;
import net.sf.json.JSONObject;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
/**
* 商品爬虫接口
*
* @author G
*/
public interface IItemSpider {
/**
* 爬取商品数据
* @param targetUrl 商品详情页路径
* @return 返回格式化及翻译后的 Json 数据
* @throws InterruptedException 被打断异常
* @throws IOException IO异常
* @throws ExecutionException 运行时异常
* @throws URISyntaxException 语法异常
* @throws TimeoutException 超时异常
*/
JSONObject captureItem(String targetUrl) throws InterruptedException, IOException, ExecutionException, URISyntaxException, TimeoutException;
}
package com.example.afrishop_v3.bis.impl;
import com.example.afrishop_v3.bis.IItemSpider;
import com.example.afrishop_v3.enums.PlatformEnum;
import com.example.afrishop_v3.vo.*;
import com.example.afrishop_v3.util.*;
import net.sf.json.JSONObject;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import java.util.regex.Pattern;
import static com.example.afrishop_v3.util.SpiderUtil.exchangeRate;
/**
* Abercrombie&Fitch 数据爬虫
*
* @author 爱酱油不爱醋
*/
@Component("aberCrombieFitchSpider")
public class AberCrombieFitchSpider implements IItemSpider {
private static Logger logger = LoggerFactory.getLogger(PullandbearSpider.class);
/**
* Abercrombie&Fitch 数据爬虫
* @param targetUrl 接收的商品详情路径
* @return 格式化与翻译后的 Json 数据
*/
@Override
public JSONObject captureItem(String targetUrl) throws URISyntaxException, IOException, ExecutionException, InterruptedException, TimeoutException {
String content = HttpClientUtil.getContentByUrl(targetUrl, PlatformEnum.ABERCROMBIEFITCH.getValue());
ProductResponse productResponse = formatProductResponse(content);
JSONObject resultJson = JSONObject.fromObject(productResponse);
TranslateHelper.translateProductResponse(resultJson);
return resultJson;
}
/**
* 正则匹配是否为商品详情页的链接
* TODO 正则编写
* @param targetUrl url路径
* @return 匹配失败则返回错误信息
*/
private boolean urlPattern(String targetUrl) {
String regex = "";
return Pattern.matches(regex, targetUrl);
}
/**
* 格式化返回数据
* @param content 主要的页面数据
* @return 格式化后的数据
*/
private ProductResponse formatProductResponse(String content) {
// 声明封装类
ProductResponse productResponse = new ProductResponse();
// 含有商品的属性,设置为true
productResponse.setPropFlag(true);
// 无库存信息
productResponse.setStockFlag(false);
// 库存信息,如果没有可使用的库存信息则默认为999
DynStock dynStock = new DynStock();
dynStock.setSellableQuantity(9999);
List<ProductSkuStock> productSkuStockList = dynStock.getProductSkuStockList();
// 产品的原始价与优惠价
List<OriginalPrice> originalPriceList = new ArrayList<>();
List<ProductPromotion> promotionList = new ArrayList<>();
// 商品的属性,常用的商品属性为颜色与尺码
Map<String, Set<ProductProp>> productPropSet = new HashMap<>(16);
Set<ProductProp> propSet = new HashSet<>(16);
Set<ProductProp> sizePropSet = new HashSet<>(16);
// 商品的基本属性
ItemInfo itemInfo = new ItemInfo();
// 解析为 Document 对象
Document document = Jsoup.parse(content);
String pId = document.select("div[class=find-in-store display-none]").attr("pid");
//////////////////////////////////// 获取商品基本信息 ////////////////////////////
itemInfo.setShopName("Abercrombie&Fitch");
itemInfo.setShopUrl("https://www.abercrombie.cn/");
itemInfo.setItemId(pId);
itemInfo.setTitle(document.select("meta[property=og:title]").attr("content"));
itemInfo.setPic(document.select("input[id=shoppingcartpic]").attr("value"));
//////////////////////////////////// 获取商品基本信息End /////////////////////////
String fullPrice = document.select("meta[property=og:price:amount]").attr("content");
fullPrice = exchangeRate(fullPrice);
Elements colorsEle = document.select("ul[class=swatches color]").select("li");
Elements sizesEle = document.select("ul[class=product__sizes]")
.select("ul[class=swatches option va_1mprmry]").select("li");
for (int i = 0; i < colorsEle.size(); i++) {
//////////////////////////////////// 获取商品颜色属性 ////////////////////////////
String colorNo = i + "";
String color = colorsEle.get(i).attr("title");
String dataLgimg = colorsEle.select("span").attr("data-lgimg");
JSONObject datLgimgObj = JSONObject.fromObject(dataLgimg);
String imgUrl = datLgimgObj.getString("url");
ProductProp productPropColor = new ProductProp();
productPropColor.setPropId(colorNo);
productPropColor.setPropName(color);
productPropColor.setImage(imgUrl);
propSet.add(productPropColor);
if (productPropSet.get("颜色") == null) {
productPropSet.put("颜色", propSet);
} else {
Set<ProductProp> oldPropSet = productPropSet.get("颜色");
propSet.addAll(oldPropSet);
productPropSet.put("颜色", propSet);
}
//////////////////////////////////// 获取商品颜色属性 END ////////////////////////////////////////////
for (Element sizeEle : sizesEle) {
///////////////////////// 获取商品尺码属性 ////////////////////
String sizeNo = sizeEle.attr("title");
String size = sizeNo;
ProductProp productPropSize = new ProductProp();
productPropSize.setPropId(sizeNo);
productPropSize.setPropName(size);
sizePropSet.add(productPropSize);
if (productPropSet.get("尺码") == null) {
productPropSet.put("尺码", sizePropSet);
} else {
Set<ProductProp> oldPropSet = productPropSet.get("尺码");
sizePropSet.addAll(oldPropSet);
productPropSet.put("尺码", sizePropSet);
}
///////////////////////// 获取商品尺码属性 END////////////////////
// 库存对应的id(颜色id + 尺码id)
String skuStr = ";" + colorNo + ";" + sizeNo + ";";
//////////////////////////////////// 获取库存 ////////////////////////////////////////////
// 设置:商品包含库存信息
if (productSkuStockList == null) {
productSkuStockList = new ArrayList<>();
}
ProductSkuStock productSkuStock = new ProductSkuStock();
productSkuStock.setSkuStr(skuStr);
productSkuStock.setSellableQuantity(999);
productSkuStockList.add(productSkuStock);
dynStock.setProductSkuStockList(productSkuStockList);
//////////////////////////////////// 获取库存 END/////////////////////////////////////////
//////////////////////////////////// 获取原始价 //////////////////////////////////
OriginalPrice originalPrice = new OriginalPrice();
originalPrice.setSkuStr(skuStr);
originalPrice.setPrice(fullPrice);
originalPriceList.add(originalPrice);
productResponse.setPrice(fullPrice);
productResponse.setSalePrice(fullPrice + "-" + fullPrice);
//////////////////////////////////// 获取原始价 END///////////////////////////////
}
}
productResponse.setProductPropSet(productPropSet);
productResponse.setPlatform("Abercrombie&Fitch");
productResponse.setPromotionList(promotionList);
productResponse.setOriginalPriceList(originalPriceList);
productResponse.setItemInfo(itemInfo);
productResponse.setDynStock(dynStock);
return productResponse;
}
}
package com.example.afrishop_v3.bis.impl;
import com.example.afrishop_v3.bis.IItemSpider;
import com.example.afrishop_v3.enums.PlatformEnum;
import com.example.afrishop_v3.vo.*;
import com.example.afrishop_v3.util.*;
import net.sf.json.JSONObject;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static com.example.afrishop_v3.util.SpiderUtil.exchangeRate;
/**
* Adidas 数据爬虫
*
* @author 爱酱油不爱醋
*/
@Component("adidasSpider")
public class AdidasSpider implements IItemSpider {
private static Logger logger = LoggerFactory.getLogger(PullandbearSpider.class);
/**
* Adidas 数据爬虫
*
* @param targetUrl 接收的商品详情路径
* @return 格式化与翻译后的 Json 数据
*/
@Override
public JSONObject captureItem(String targetUrl) throws URISyntaxException, IOException, ExecutionException, InterruptedException, TimeoutException {
// 截取商品的 id
final String regex = "\\w+\\d+";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(targetUrl);
matcher.find();
String pId = matcher.group(0);
// 对应的商品数据接口
targetUrl = "https://www.adidas.com.cn/item/othercolor?itemCode=" + pId;
String content = HttpClientUtil.getContentByUrl(targetUrl, PlatformEnum.ADIDAS.getValue());
ProductResponse productResponse = formatProductResponse(content, pId);
JSONObject resultJson = JSONObject.fromObject(productResponse);
TranslateHelper.translateProductResponse(resultJson);
return resultJson;
}
/**
* 格式化返回数据
*
* @param content 主要的页面数据
* @return 格式化后的数据
*/
private ProductResponse formatProductResponse(String content, String pId) throws IOException, URISyntaxException {
// 声明封装类
ProductResponse productResponse = new ProductResponse();
// 含有商品的属性,设置为true
productResponse.setPropFlag(true);
// 无库存信息
productResponse.setStockFlag(false);
// 库存信息,如果没有可使用的库存信息则默认为999
DynStock dynStock = new DynStock();
dynStock.setSellableQuantity(9999);
List<ProductSkuStock> productSkuStockList = dynStock.getProductSkuStockList();
// 产品的原始价与优惠价
List<OriginalPrice> originalPriceList = new ArrayList<>();
List<ProductPromotion> promotionList = new ArrayList<>();
// 商品的属性,常用的商品属性为颜色与尺码
Map<String, Set<ProductProp>> productPropSet = new HashMap<>(16);
Set<ProductProp> propSet = new HashSet<>(16);
Set<ProductProp> sizePropSet = new HashSet<>(16);
// 商品的基本属性
ItemInfo itemInfo = new ItemInfo();
// 解析为 Document 对象
Document document = Jsoup.parse(content);
// 获取价格
String originalFullPrice = document.select("input[id=salePrice]").attr("value");
originalFullPrice = exchangeRate(originalFullPrice);
//////////////////////////////////// 获取商品基本信息 ////////////////////////////
itemInfo.setShopName("Adidas");
itemInfo.setShopUrl("https://www.adidas.com");
itemInfo.setItemId(pId);
String colorNo = document.select("input[id=itemCode]").attr("value");
itemInfo.setTitle(colorNo);
itemInfo.setPic(document.select("input[id=shoppingcartpic]").attr("value"));
//////////////////////////////////// 获取商品基本信息End /////////////////////////
//////////////////////////////////// 获取商品颜色属性 ////////////////////////////
Elements colorEle = document.select("ul[id=itemColor]").select("li");
for (Element colorElement : colorEle) {
String color = colorElement.attr("code");
String imgUrl = colorElement.select("img").attr("lazy-src");
ProductProp productPropColor = new ProductProp();
productPropColor.setPropId(color);
productPropColor.setPropName(color);
productPropColor.setImage(imgUrl);
propSet.add(productPropColor);
if (productPropSet.get("颜色") == null) {
productPropSet.put("颜色", propSet);
} else {
Set<ProductProp> oldPropSet = productPropSet.get("颜色");
propSet.addAll(oldPropSet);
productPropSet.put("颜色", propSet);
}
//////////////////////////////////// 获取商品颜色属性 END ////////////////////////////////////////////
Elements sizeEles = document.select("div[class=overview product-size]").select("li");
for (Element sizeEle : sizeEles) {
String size = sizeEle.attr("dispalySize");
///////////////////////// 获取商品尺码属性 ////////////////////
ProductProp productPropSize = new ProductProp();
productPropSize.setPropId(size);
productPropSize.setPropName(size);
sizePropSet.add(productPropSize);
if (productPropSet.get("尺码") == null) {
productPropSet.put("尺码", sizePropSet);
} else {
Set<ProductProp> oldPropSet = productPropSet.get("尺码");
sizePropSet.addAll(oldPropSet);
productPropSet.put("尺码", sizePropSet);
}
///////////////////////// 获取商品尺码属性 END////////////////////
// 库存对应的id(颜色id + 尺码id)
String skuStr = ";" + color + ";" + size + ";";
//////////////////////////////////// 获取库存 ////////////////////////////////////////////
// 设置:商品包含库存信息
if (productSkuStockList == null) {
productSkuStockList = new ArrayList<>();
}
ProductSkuStock productSkuStock = new ProductSkuStock();
productSkuStock.setSkuStr(skuStr);
productSkuStock.setSellableQuantity(999);
productSkuStockList.add(productSkuStock);
dynStock.setProductSkuStockList(productSkuStockList);
//////////////////////////////////// 获取库存 END/////////////////////////////////////////
//////////////////////////////////// 获取原始价 //////////////////////////////////
OriginalPrice originalPrice = new OriginalPrice();
originalPrice.setSkuStr(skuStr);
originalPrice.setPrice(originalFullPrice);
originalPriceList.add(originalPrice);
productResponse.setPrice(originalFullPrice);
productResponse.setSalePrice(originalFullPrice + "-" + originalFullPrice);
//////////////////////////////////// 获取原始价 END///////////////////////////////
}
}
productResponse.setProductPropSet(productPropSet);
productResponse.setPlatform("Adidas");
productResponse.setPromotionList(promotionList);
productResponse.setOriginalPriceList(originalPriceList);
productResponse.setItemInfo(itemInfo);
productResponse.setDynStock(dynStock);
return productResponse;
}
}
package com.example.afrishop_v3.bis.impl;
import com.example.afrishop_v3.bis.IItemSpider;
import com.example.afrishop_v3.enums.PlatformEnum;
import com.example.afrishop_v3.util.HttpClientUtil;
import com.example.afrishop_v3.util.SpiderUtil;
import com.example.afrishop_v3.util.TranslateHelper;
import com.example.afrishop_v3.vo.*;
import net.sf.json.JSONObject;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import static com.example.afrishop_v3.util.SpiderUtil.exchangeRate;
/**
* Apple(苹果) 数据爬虫
*
* @author 爱酱油不爱醋
*/
@Component("appleSpider")
public class AppleSpider implements IItemSpider {
private static Logger logger = LoggerFactory.getLogger(PullandbearSpider.class);
/**
* Apple(苹果) 数据爬虫
* @param targetUrl 接收的商品详情路径
* @return 格式化与翻译后的 Json 数据
*/
@Override
public JSONObject captureItem(String targetUrl) throws URISyntaxException, IOException, ExecutionException, InterruptedException, TimeoutException {
String content = HttpClientUtil.getContentByUrl(targetUrl, PlatformEnum.APPLE.getValue());
ProductResponse productResponse = formatProductResponse(content);
JSONObject resultObj = JSONObject.fromObject(productResponse);
TranslateHelper.translateProductResponse(resultObj);
return resultObj;
}
/**
* 格式化返回数据
*
* @param content 主要的页面数据
* @return 格式化后的数据
*/
private ProductResponse formatProductResponse(String content) throws IOException, URISyntaxException {
// 声明封装类
ProductResponse productResponse = new ProductResponse();
// 含有商品的属性,设置为true
productResponse.setPropFlag(true);
// 库存信息,如果没有可使用的库存信息则默认为999
DynStock dynStock = new DynStock();
dynStock.setSellableQuantity(9999);
List<ProductSkuStock> productSkuStockList = dynStock.getProductSkuStockList();
// 产品的原始价与优惠价
List<OriginalPrice> originalPriceList = new ArrayList<>();
List<ProductPromotion> promotionList = new ArrayList<>();
// 商品的属性,常用的商品属性为颜色与尺码
Map<String, Set<ProductProp>> productPropSet = new HashMap<>(16);
Set<ProductProp> propSet = new HashSet<>(16);
Set<ProductProp> sizePropSet = new HashSet<>(16);
productResponse.setStockFlag(true);
// 商品的基本属性
ItemInfo itemInfo = new ItemInfo();
// 解析为 Document 对象
Document document = Jsoup.parse(content);
String pTitle = document.select("meta[property=og:title]").attr("content");
String imgUrl = document.select("meta[property=og:image]").attr("content");
String shopUrl = "https://www.apple.com/";
//////////////////////////////////// 获取商品基本信息 ////////////////////////////
itemInfo.setShopName("Apple");
itemInfo.setShopUrl(shopUrl);
itemInfo.setTitle(pTitle);
itemInfo.setPic(imgUrl);
//////////////////////////////////// 获取商品基本信息End /////////////////////////
// 获取该商品下的所有款式的链接
Elements pUrlEle = document.select("div[class=selection-buttons]").select("div[class=item equalize-capacity-button-height ]");
for (Element element : pUrlEle) {
String targetUrl = element.select("a").attr("href");
if (!targetUrl.contains("https://www.apple.com")) {
targetUrl = shopUrl + targetUrl;
}
String[] spilt = targetUrl.split("/");
String pId = spilt[spilt.length - 2] + "/" + spilt[spilt.length - 1];
content = HttpClientUtil.getContentByUrl(targetUrl, PlatformEnum.APPLE.getValue());
document = Jsoup.parse(content);
String skuStr = ";" + pId + ";" + pId + ";";
//////////////////////////////////// 获取款式 ////////////////////////////////////////////
pTitle = document.select("meta[property=og:title]").attr("content");
imgUrl = document.select("meta[property=og:image]").attr("content");
ProductProp productPropModel = new ProductProp();
productPropModel.setPropId(pId);
productPropModel.setPropName(pTitle);
productPropModel.setImage(imgUrl);
propSet.add(productPropModel);
if (productPropSet.get("款式") == null) {
productPropSet.put("款式", propSet);
} else {
Set<ProductProp> oldPropSet = productPropSet.get("款式");
propSet.addAll(oldPropSet);
productPropSet.put("款式", propSet);
}
//////////////////////////////////// 获取款式 END ////////////////////////////////////////////
//////////////////////////////////// 获取库存 ////////////////////////////////////////////
// 设置:商品包含库存信息
if (productSkuStockList == null) {
productSkuStockList = new ArrayList<>();
}
ProductSkuStock productSkuStock = new ProductSkuStock();
productSkuStock.setSellableQuantity(999);
productSkuStock.setSkuStr(skuStr);
productSkuStockList.add(productSkuStock);
dynStock.setProductSkuStockList(productSkuStockList);
//////////////////////////////////// 获取库存 END/////////////////////////////////////////
//////////////////////////////////// 获取原始价 //////////////////////////////////
// 获取商品的原始价
String fullPrice = document.select("span[class=as-price-currentprice]").text();
fullPrice = SpiderUtil.retainNumber(fullPrice);
fullPrice = exchangeRate(fullPrice);
OriginalPrice originalPrice = new OriginalPrice();
originalPrice.setSkuStr(skuStr);
originalPrice.setPrice(fullPrice);
originalPriceList.add(originalPrice);
productResponse.setPrice(fullPrice);
productResponse.setSalePrice(fullPrice + "-" + fullPrice);
//////////////////////////////////// 获取原始价 END///////////////////////////////
}
productResponse.setProductPropSet(productPropSet);
productResponse.setPlatform("Apple");
productResponse.setPromotionList(promotionList);
productResponse.setOriginalPriceList(originalPriceList);
productResponse.setItemInfo(itemInfo);
productResponse.setDynStock(dynStock);
return productResponse;
}
}
package com.example.afrishop_v3.bis.impl;
import com.example.afrishop_v3.bis.IItemSpider;
import com.example.afrishop_v3.enums.PlatformEnum;
import com.example.afrishop_v3.util.HttpClientUtil;
import com.example.afrishop_v3.util.SpiderUtil;
import com.example.afrishop_v3.util.TranslateHelper;
import com.example.afrishop_v3.vo.*;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import static com.example.afrishop_v3.util.SpiderUtil.exchangeRate;
/**
* Burberry(博柏利) 数据爬虫
* TODO 需要模拟登录,暂留
* @author 爱酱油不爱醋
*/
public class BurberrySpider implements IItemSpider {
private static Logger logger = LoggerFactory.getLogger(ZaraSpider.class);
/**
* Burberry(博柏利) 数据爬虫
* @param targetUrl 接收的商品详情路径
* @return 格式化与翻译后的 Json 数据
*/
@Override
public JSONObject captureItem(String targetUrl) throws URISyntaxException, IOException, ExecutionException, InterruptedException, TimeoutException {
String[] spilt = targetUrl.split("/");
spilt = spilt[5].split("[?]");
String pId = spilt[0];
String styleId = pId.substring(0, 5);
targetUrl = "https://www.gucci.cn/zh/pr/sameStyleBuriedPoint?itemCode=" + pId +"&style=" + styleId + "&categoryPath=&_=1572859976423";
String content = HttpClientUtil.getContentByUrl(targetUrl, PlatformEnum.GUCCI.getValue());
ProductResponse productResponse = formatProductResponse(content, pId);
JSONObject resultObj = JSONObject.fromObject(productResponse);
TranslateHelper.translateProductResponse(resultObj);
return resultObj;
}
/**
* 格式化返回数据
* @return 格式化后的数据
*/
private ProductResponse formatProductResponse(String content, String pId) {
// 声明封装类
ProductResponse productResponse = new ProductResponse();
// 含有商品的属性,设置为true
productResponse.setPropFlag(true);
// 库存信息,如果没有可使用的库存信息则默认为999
DynStock dynStock = new DynStock();
dynStock.setSellableQuantity(9999);
List<ProductSkuStock> productSkuStockList = dynStock.getProductSkuStockList();
// 产品的原始价与优惠价
List<OriginalPrice> originalPriceList = new ArrayList<>();
List<ProductPromotion> promotionList = new ArrayList<>();
// 商品的属性,常用的商品属性为颜色与尺码
Map<String, Set<ProductProp>> productPropSet = new HashMap<>(16);
Set<ProductProp> propSet = new HashSet<>(16);
Set<ProductProp> sizePropSet = new HashSet<>(16);
productResponse.setStockFlag(true);
// 商品的基本属性
ItemInfo itemInfo = new ItemInfo();
JSONObject dataMap = JSONObject.fromObject(content);
// 取 data 节点对象
JSONObject dataObj = dataMap.getJSONObject("data");
// 如果获取的长度为空,哪说明没有在商品的详情页内,返回空参数
if (dataObj.size() == 0) {
return productResponse;
}
//////////////////////////////////// 获取商品基本信息 ////////////////////////////
itemInfo.setShopName(PlatformEnum.COACH.getLabel());
itemInfo.setShopUrl("https://china.coach.com");
itemInfo.setItemId(pId);
itemInfo.setTitle(dataObj.getString("name"));
//////////////////////////////////// 获取商品基本信息(图片下取)End /////////////////////////
List<String> sizeNoList = new ArrayList<>();
List<String> colorNoList = new ArrayList<>();
// 取 attributes 节点数组
JSONArray attributesArr = dataObj.getJSONArray("attributes");
for (int i = 0; i < attributesArr.size(); i++) {
///////////////////////// 获取商品颜色属性 ////////////////////////////////////////////////////////////////
// 0 位为颜色属性
if (i == 0) {
// 取 values 节点数组
JSONArray valuesArr = attributesArr.getJSONObject(i).getJSONArray("values");
for (int j = 0; j < valuesArr.size(); j++) {
JSONObject valuesObj = valuesArr.getJSONObject(j);
// 获取图片路径
String imageUrl = valuesObj.getString("image");
// 设置商品基本信息的图片
if (i == 0) {
itemInfo.setPic(imageUrl);
}
ProductProp productPropColor = new ProductProp();
String colorNo = valuesObj.getString("value_index");
colorNoList.add(colorNo);
productPropColor.setPropId(colorNo);
productPropColor.setPropName(valuesObj.getString("label"));
productPropColor.setImage(imageUrl);
propSet.add(productPropColor);
if (productPropSet.get("颜色") == null) {
productPropSet.put("颜色", propSet);
} else {
Set<ProductProp> oldPropSet = productPropSet.get("颜色");
propSet.addAll(oldPropSet);
productPropSet.put("颜色", propSet);
}
}
///////////////////////// 获取商品颜色属性End ////////////////////////////////////////////////////////////////
// 1 位为尺寸属性(有的商品不一定会存在,如手提包)
} else if (i == 1) {
// 取 values 节点数组
JSONArray valuesArr = attributesArr.getJSONObject(i).getJSONArray("values");
///////////////////////// 获取商品尺码属性 ////////////////////////////////////////////////////////////////
for (int j = 0; j < valuesArr.size(); j++) {
JSONObject valuesObj = valuesArr.getJSONObject(j);
ProductProp productPropSize = new ProductProp();
String sizeNo = valuesObj.getString("value_index");
sizeNoList.add(sizeNo);
productPropSize.setPropId(sizeNo);
productPropSize.setPropName(valuesObj.getString("label"));
sizePropSet.add(productPropSize);
if (productPropSet.get("尺码") == null) {
productPropSet.put("尺码", sizePropSet);
} else {
Set<ProductProp> oldPropSet = productPropSet.get("尺码");
sizePropSet.addAll(oldPropSet);
productPropSet.put("尺码", sizePropSet);
}
///////////////////////// 获取商品尺码属性 END/////////////////////////////////////////////////////
}
}
}
for (String colorNo : colorNoList) {
for (String sizeNo : sizeNoList) {
// 设置 skuStr
String skuStr = ";" + colorNo + ";" + sizeNo + ";";
// 设置:商品包含库存信息
if (productSkuStockList == null) {
productSkuStockList = new ArrayList<>();
}
ProductSkuStock productSkuStock = new ProductSkuStock();
// 设置:可用库存值,未有可用的库存数据
productSkuStock.setSellableQuantity(999);
// 设置:库存对应的id
productSkuStock.setSkuStr(skuStr);
productSkuStockList.add(productSkuStock);
dynStock.setProductSkuStockList(productSkuStockList);
//////////////////////////////////// 获取库存 END/////////////////////////////////////////
//////////////////////////////////// 获取原始价 //////////////////////////////////
// 获取商品的原始价(存在优惠价格)
OriginalPrice originalPrice = new OriginalPrice();
String fullPrice = dataObj.getString("price");
fullPrice = SpiderUtil.retainNumber(fullPrice);
// TODO 转换汇率,目前商品单位是人民币
fullPrice = exchangeRate(fullPrice);
productResponse.setPrice(fullPrice);
productResponse.setSalePrice(fullPrice + "-" + fullPrice);
originalPrice.setPrice(fullPrice);
originalPrice.setSkuStr(skuStr);
originalPriceList.add(originalPrice);
//////////////////////////////////// 获取原始价 END //////////////////////////////////
}
}
productResponse.setProductPropSet(productPropSet);
productResponse.setPlatform(PlatformEnum.COACH.getValue());
productResponse.setPromotionList(promotionList);
productResponse.setOriginalPriceList(originalPriceList);
productResponse.setItemInfo(itemInfo);
productResponse.setDynStock(dynStock);
return productResponse;
}
}
package com.example.afrishop_v3.bis.impl;
import com.example.afrishop_v3.bis.IItemSpider;
import com.example.afrishop_v3.enums.PlatformEnum;
import com.example.afrishop_v3.util.HttpClientUtil;
import com.example.afrishop_v3.util.SpiderUtil;
import com.example.afrishop_v3.util.TranslateHelper;
import com.example.afrishop_v3.vo.*;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import static com.example.afrishop_v3.util.SpiderUtil.exchangeRate;
/**
* COACH(蔻驰)
*
* @author 爱酱油不爱醋
*/
@Component("coachSpider")
public class CoachSpider implements IItemSpider {
private static Logger logger = LoggerFactory.getLogger(ZaraSpider.class);
/**
* Coach 数据爬虫
* @param targetUrl 接收的商品详情路径
* @return 格式化与翻译后的 Json 数据
*/
@Override
public JSONObject captureItem(String targetUrl) throws URISyntaxException, IOException, ExecutionException, InterruptedException, TimeoutException {
String[] urlSpilt = targetUrl.split("/");
String[] pIdSpilt = urlSpilt[4].split(".html");
String pId = pIdSpilt[0];
targetUrl = "https://" + urlSpilt[2] + "/rest/default/V1/applet/product/CONF" + pId;
String content = HttpClientUtil.getContentByUrl(targetUrl, PlatformEnum.COACH.getValue());
JSONObject resultObj = JSONObject.fromObject(content);
ProductResponse productResponse = formatProductResponse(resultObj, pId);
resultObj = JSONObject.fromObject(productResponse);
TranslateHelper.translateProductResponse(resultObj);
return resultObj;
}
/**
* 格式化返回数据
* @param dataMap 主要的Json数据
* @return 格式化后的数据
*/
private ProductResponse formatProductResponse(JSONObject dataMap, String pId) {
// 声明封装类
ProductResponse productResponse = new ProductResponse();
// 含有商品的属性,设置为true
productResponse.setPropFlag(true);
// 库存信息,如果没有可使用的库存信息则默认为999
DynStock dynStock = new DynStock();
dynStock.setSellableQuantity(9999);
List<ProductSkuStock> productSkuStockList = dynStock.getProductSkuStockList();
// 产品的原始价与优惠价
List<OriginalPrice> originalPriceList = new ArrayList<>();
List<ProductPromotion> promotionList = new ArrayList<>();
// 商品的属性,常用的商品属性为颜色与尺码
Map<String, Set<ProductProp>> productPropSet = new HashMap<>(16);
Set<ProductProp> propSet = new HashSet<>(16);
Set<ProductProp> sizePropSet = new HashSet<>(16);
productResponse.setStockFlag(true);
// 商品的基本属性
ItemInfo itemInfo = new ItemInfo();
// 取 data 节点对象
JSONObject dataObj = dataMap.getJSONObject("data");
// 如果获取的长度为空,哪说明没有在商品的详情页内,返回空参数
if (dataObj.size() == 0) {
return productResponse;
}
//////////////////////////////////// 获取商品基本信息 ////////////////////////////
itemInfo.setShopName("Coach");
itemInfo.setShopUrl("https://china.coach.com");
itemInfo.setItemId(pId);
itemInfo.setTitle(dataObj.getString("name"));
//////////////////////////////////// 获取商品基本信息(图片下取)End /////////////////////////
List<String> sizeNoList = new ArrayList<>();
List<String> colorNoList = new ArrayList<>();
// 取 attributes 节点数组
JSONArray attributesArr = dataObj.getJSONArray("attributes");
for (int i = 0; i < attributesArr.size(); i++) {
///////////////////////// 获取商品颜色属性 ////////////////////////////////////////////////////////////////
// 0 位为颜色属性
if (i == 0) {
JSONArray valuesArr = attributesArr.getJSONObject(i).getJSONArray("values");
for (int j = 0; j < valuesArr.size(); j++) {
JSONObject valuesObj = valuesArr.getJSONObject(j);
String colorNo = valuesObj.getString("value_index");
String color = valuesObj.getString("label");
String imageUrl = valuesObj.getString("image");
if (i == 0) {
itemInfo.setPic(imageUrl);
}
colorNoList.add(colorNo);
ProductProp productPropColor = new ProductProp();
productPropColor.setPropId(colorNo);
productPropColor.setPropName(color);
productPropColor.setImage(imageUrl);
propSet.add(productPropColor);
if (productPropSet.get("颜色") == null) {
productPropSet.put("颜色", propSet);
} else {
Set<ProductProp> oldPropSet = productPropSet.get("颜色");
propSet.addAll(oldPropSet);
productPropSet.put("颜色", propSet);
}
}
///////////////////////// 获取商品颜色属性End ////////////////////////////////////////////////////////////////
// 1 位为尺寸属性(有的商品不一定会存在,如手提包)
} else if (i == 1) {
// 取 values 节点数组
JSONArray valuesArr = attributesArr.getJSONObject(i).getJSONArray("values");
///////////////////////// 获取商品尺码属性 ////////////////////////////////////////////////////////////////
for (int j = 0; j < valuesArr.size(); j++) {
JSONObject valuesObj = valuesArr.getJSONObject(j);
String sizeNo = valuesObj.getString("value_index");
String size = valuesObj.getString("label");
sizeNoList.add(sizeNo);
ProductProp productPropSize = new ProductProp();
productPropSize.setPropId(sizeNo);
productPropSize.setPropName(size);
sizePropSet.add(productPropSize);
if (productPropSet.get("尺码") == null) {
productPropSet.put("尺码", sizePropSet);
} else {
Set<ProductProp> oldPropSet = productPropSet.get("尺码");
sizePropSet.addAll(oldPropSet);
productPropSet.put("尺码", sizePropSet);
}
///////////////////////// 获取商品尺码属性 END/////////////////////////////////////////////////////
}
}
}
for (String colorNo : colorNoList) {
for (String sizeNo : sizeNoList) {
// 设置 skuStr
String skuStr = ";" + colorNo + ";" + sizeNo + ";";
if (productSkuStockList == null) {
productSkuStockList = new ArrayList<>();
}
ProductSkuStock productSkuStock = new ProductSkuStock();
productSkuStock.setSkuStr(skuStr);
productSkuStock.setSellableQuantity(999);
productSkuStockList.add(productSkuStock);
dynStock.setProductSkuStockList(productSkuStockList);
//////////////////////////////////// 获取库存 END/////////////////////////////////////////
//////////////////////////////////// 获取原始价 //////////////////////////////////
// 获取商品的原始价(存在优惠价格)
String fullPrice = dataObj.getString("price");
fullPrice = SpiderUtil.retainNumber(fullPrice);
// TODO 转换汇率,目前商品单位是人民币
fullPrice = exchangeRate(fullPrice);
OriginalPrice originalPrice = new OriginalPrice();
originalPrice.setPrice(fullPrice);
originalPrice.setSkuStr(skuStr);
originalPriceList.add(originalPrice);
productResponse.setPrice(fullPrice);
productResponse.setSalePrice(fullPrice + "-" + fullPrice);
//////////////////////////////////// 获取原始价 END //////////////////////////////////
}
}
productResponse.setProductPropSet(productPropSet);
productResponse.setPlatform("Coach");
productResponse.setPromotionList(promotionList);
productResponse.setOriginalPriceList(originalPriceList);
productResponse.setItemInfo(itemInfo);
productResponse.setDynStock(dynStock);
return productResponse;
}
}
\ No newline at end of file
package com.example.afrishop_v3.bis.impl;
/**
* Converse 数据爬虫
*
* @author 爱酱油不爱醋
*/
public class ConverseSpider {
// public static void main(String[] args) throws Exception {
// String targetUrl = "https://m.converse.com.cn/inventory/168131C110";
// String content = HttpClientUtil.getContentByUrl(targetUrl, PlatformEnum.ZARAHOME.getValue());
// System.err.println(content);
// }
}
package com.example.afrishop_v3.bis.impl;
import com.example.afrishop_v3.bis.IItemSpider;
import net.sf.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
/**
* Eifini(伊芙丽) 数据爬虫
* TODO 未完成
* @author 爱酱油不爱醋
*/
@Component("eifiniSpider")
public class EifiniSpider implements IItemSpider {
private static Logger logger = LoggerFactory.getLogger(EifiniSpider.class);
/**
* Eifini(伊芙丽) 数据爬虫
* @param targetUrl 接收的商品详情路径
* @return 格式化与翻译后的 Json 数据
*/
@Override
public JSONObject captureItem(String targetUrl) throws InterruptedException, IOException, ExecutionException, URISyntaxException, TimeoutException {
return null;
}
}
package com.example.afrishop_v3.bis.impl;
import com.example.afrishop_v3.bis.IItemSpider;
import net.sf.json.JSONObject;
import org.springframework.stereotype.Component;
/**
* 空的数据爬虫
*
* @author G
*/
@Component("emptyItemSpider")
public class EmptyItemSpider implements IItemSpider {
@Override
public JSONObject captureItem(String targetUrl) {
JSONObject resultMap=new JSONObject();
resultMap.put("code","-1");
resultMap.put("message","找不到此类网址的数据爬虫!");
return resultMap;
}
}
package com.example.afrishop_v3.bis.impl;
import com.example.afrishop_v3.bis.IItemSpider;
import com.example.afrishop_v3.enums.PlatformEnum;
import com.example.afrishop_v3.util.HttpClientUtil;
import com.example.afrishop_v3.util.JsoupUtil;
import com.example.afrishop_v3.util.TranslateHelper;
import com.example.afrishop_v3.vo.*;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import static com.example.afrishop_v3.util.SpiderUtil.exchangeRate;
/**
* Esprit(思捷) 数据爬虫
*
* @author 爱酱油不爱醋
*/
@Component("espritSpider")
public class EspritSpider implements IItemSpider {
private static Logger logger = LoggerFactory.getLogger(PullandbearSpider.class);
/**
* Esprit(思捷) 数据爬虫
*
* @param targetUrl 接收的商品详情路径
* @return 格式化与翻译后的 Json 数据
*/
@Override
public JSONObject captureItem(String targetUrl) throws InterruptedException, IOException, ExecutionException, URISyntaxException, TimeoutException {
String content = HttpClientUtil.getContentByUrl(targetUrl, PlatformEnum.ESPRIT.getValue());
JSONObject dataMap = JsoupUtil.getItemDetailByName(content, "window.__INITIAL_STATE__");
ProductResponse productResponse = formatProductResponse(dataMap);
JSONObject resultObj = JSONObject.fromObject(productResponse);
TranslateHelper.translateProductResponse(resultObj);
return resultObj;
}
/**
* 格式化返回数据
*
* @param dataMap 主要的Json数据
* @return 格式化后的数据
*/
private ProductResponse formatProductResponse(JSONObject dataMap) {
// 声明封装类
ProductResponse productResponse = new ProductResponse();
// 含有商品的属性,设置为true
productResponse.setPropFlag(true);
// 库存信息,如果没有可使用的库存信息则默认为999
DynStock dynStock = new DynStock();
dynStock.setSellableQuantity(9999);
List<ProductSkuStock> productSkuStockList = dynStock.getProductSkuStockList();
// 产品的原始价与优惠价
List<OriginalPrice> originalPriceList = new ArrayList<>();
List<ProductPromotion> promotionList = new ArrayList<>();
// 商品的属性,常用的商品属性为颜色与尺码
Map<String, Set<ProductProp>> productPropSet = new HashMap<>(16);
Set<ProductProp> propSet = new HashSet<>(16);
Set<ProductProp> sizePropSet = new HashSet<>(16);
productResponse.setStockFlag(true);
// 商品的基本属性
ItemInfo itemInfo = new ItemInfo();
// 取 product 下的 details 节点对象
JSONObject detailsObj = dataMap.getJSONObject("product").getJSONObject("details");
//////////////////////////////////// 获取商品基本信息 ////////////////////////////
itemInfo.setShopName("Esprit");
itemInfo.setShopUrl("https://www.esprit.cn");
itemInfo.setItemId(detailsObj.getString("code"));
itemInfo.setTitle(detailsObj.getString("title"));
//////////////////////////////////// 获取商品基本信息(图片下取)End /////////////////////////
// 获取商品的原始价
String fullPrice = detailsObj.getJSONObject("salePrice").getString("amount");
// TODO 转换汇率,目前商品单位是人民币
fullPrice = exchangeRate(fullPrice);
JSONArray values_0_Arr = detailsObj.getJSONArray("options").getJSONObject(0).getJSONArray("values");
JSONArray values_1_Arr = detailsObj.getJSONArray("options").getJSONObject(1).getJSONArray("values");
for (int i = 0; i < values_0_Arr.size(); i++) {
JSONObject values_0_Obj = values_0_Arr.getJSONObject(i);
//////////////////////////////////// 获取商品颜色属性 ////////////////////////////////////////////
String colorNo = values_0_Obj.getString("code");
String color = values_0_Obj.getString("displayName");
String imageUrl = values_0_Obj.getJSONArray("images").getJSONObject(0).getString("url");
if (i == 0) {
itemInfo.setPic(imageUrl);
}
ProductProp productPropColor = new ProductProp();
productPropColor.setPropId(colorNo);
productPropColor.setPropName(color);
productPropColor.setImage(imageUrl);
propSet.add(productPropColor);
if (productPropSet.get("颜色") == null) {
productPropSet.put("颜色", propSet);
} else {
Set<ProductProp> oldPropSet = productPropSet.get("颜色");
propSet.addAll(oldPropSet);
productPropSet.put("颜色", propSet);
}
//////////////////////////////////// 获取商品颜色属性END ////////////////////////////////////////////
///////////////////////// 获取商品尺码属性 //////////////////////////////////////////////////////////
for (int j = 0; j < values_1_Arr.size(); j++) {
JSONObject values_1_Obj = values_1_Arr.getJSONObject(j);
String sizeNo = values_1_Obj.getString("code");
String size = values_1_Obj.getString("displayName");
ProductProp productPropSize = new ProductProp();
productPropSize.setPropId(sizeNo);
productPropSize.setPropName(size);
sizePropSet.add(productPropSize);
if (productPropSet.get("尺码") == null) {
productPropSet.put("尺码", sizePropSet);
} else {
Set<ProductProp> oldPropSet = productPropSet.get("尺码");
sizePropSet.addAll(oldPropSet);
productPropSet.put("尺码", sizePropSet);
}
///////////////////////// 获取商品尺码属性 END/////////////////////////////////////////////////////
// 设置 skuStr
String skuStr = ";" + colorNo + ";" + sizeNo + ";";
//////////////////////////////////// 获取库存 ////////////////////////////////////////////
// 设置:商品包含库存信息
if (productSkuStockList == null) {
productSkuStockList = new ArrayList<>();
}
ProductSkuStock productSkuStock = new ProductSkuStock();
productSkuStock.setSkuStr(skuStr);
productSkuStock.setSellableQuantity(999);
productSkuStockList.add(productSkuStock);
dynStock.setProductSkuStockList(productSkuStockList);
//////////////////////////////////// 获取库存 END/////////////////////////////////////////
//////////////////////////////////// 获取原始价 //////////////////////////////////
OriginalPrice originalPrice = new OriginalPrice();
originalPrice.setSkuStr(skuStr);
originalPrice.setPrice(fullPrice);
originalPriceList.add(originalPrice);
productResponse.setPrice(fullPrice);
productResponse.setSalePrice(fullPrice + "-" + fullPrice);
//////////////////////////////////// 获取原始价 END//////////////////////////////////
}
}
productResponse.setProductPropSet(productPropSet);
productResponse.setPlatform("Esprit");
productResponse.setPromotionList(promotionList);
productResponse.setOriginalPriceList(originalPriceList);
productResponse.setItemInfo(itemInfo);
productResponse.setDynStock(dynStock);
return productResponse;
}
}
package com.example.afrishop_v3.bis.impl;
import com.example.afrishop_v3.bis.IItemSpider;
import com.example.afrishop_v3.enums.PlatformEnum;
import com.example.afrishop_v3.util.*;
import com.example.afrishop_v3.vo.*;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
/**
* Fendi(芬迪) 数据爬虫
*
* @author 爱酱油不爱醋
*/
@Component("fendiSpider")
public class FendiSpider implements IItemSpider {
private static Logger logger = LoggerFactory.getLogger(ZaraSpider.class);
/**
* Fendi(芬迪) 数据爬虫
* @param targetUrl 接收的商品详情路径
* @return 格式化与翻译后的 Json 数据
*/
@Override
public JSONObject captureItem(String targetUrl) throws URISyntaxException, IOException, ExecutionException, InterruptedException, TimeoutException {
String content = HttpClientUtil.getContentByUrl(targetUrl, PlatformEnum.FENDI.getValue());
ProductResponse productResponse = formatProductResponse(content);
JSONObject resultObj = JSONObject.fromObject(productResponse);
TranslateHelper.translateProductResponse(resultObj);
return resultObj;
}
/**
* 格式化返回数据
*
* TODO 存在一个是否为 JSONObject 或 JSONArray 的判断
*
* @param content 主要的网页内容
* @return 格式化后的数据
*/
private ProductResponse formatProductResponse(String content) throws IOException, URISyntaxException {
// 声明封装类
ProductResponse productResponse = new ProductResponse();
// 含有商品的属性,设置为true
productResponse.setPropFlag(true);
// 库存信息,如果没有可使用的库存信息则默认为999
DynStock dynStock = new DynStock();
dynStock.setSellableQuantity(9999);
List<ProductSkuStock> productSkuStockList = dynStock.getProductSkuStockList();
// 产品的原始价与优惠价
List<OriginalPrice> originalPriceList = new ArrayList<>();
List<ProductPromotion> promotionList = new ArrayList<>();
// 商品的属性,常用的商品属性为颜色与尺码
Map<String, Set<ProductProp>> productPropSet = new HashMap<>(16);
Set<ProductProp> propSet = new HashSet<>(16);
Set<ProductProp> sizePropSet = new HashSet<>(16);
productResponse.setStockFlag(true);
// 商品的基本属性
ItemInfo itemInfo = new ItemInfo();
// 转换为 Document 对象
Document document = Jsoup.parse(content);
// 通过获取商品的 id 访问商品所有款式的接口
String pId = JsoupUtil.getScriptTagVariableContent(content, "window.productId");
String pUrl = "https://www.fendi.cn/api/rest/color?product_id=" + pId;
String pContent = HttpClientUtil.getContentByUrl(pUrl, PlatformEnum.FENDI.getValue());
pContent = XmlUtils.convertXmlIntoJSONObject(pContent);
JSONObject pUrlObj = JSONObject.fromObject(pContent);
//////////////////////////////////// 获取商品基本信息 //////////////////////////////////////////////////
itemInfo.setShopName("Fendi");
itemInfo.setShopUrl("https://www.fendi.cn/");
itemInfo.setItemId(pId);
itemInfo.setTitle(document.select("div[class=info__summary]").text().trim());
//////////////////////////////////// 获取商品基本信息End ///////////////////////////////////////////////
JSONArray dataArr = pUrlObj.getJSONObject("magento_api").getJSONObject("data").getJSONArray("data_item");
for (int i = 0; i < dataArr.size(); i++) {
JSONObject dataObj = dataArr.getJSONObject(i);
//////////////////////////////////// 获取商品颜色属性 //////////////////////////////////////////////////
// 获取每个款式的页面信息
pUrl = dataObj.getString("url");
content = HttpClientUtil.getContentByUrl(pUrl, PlatformEnum.FENDI.getValue());
String colorNo = dataObj.getString("id");
String imgUrl = dataObj.getString("image");
document = Jsoup.parse(content);
if (i == 0) {
itemInfo.setPic(imgUrl);
}
ProductProp productPropColor = new ProductProp();
productPropColor.setPropId(colorNo);
productPropColor.setPropName(document.select("div[class=info__summary]").text().trim());
productPropColor.setImage("http://" + imgUrl);
propSet.add(productPropColor);
if (productPropSet.get("颜色") == null) {
productPropSet.put("颜色", propSet);
} else {
Set<ProductProp> oldPropSet = productPropSet.get("颜色");
propSet.addAll(oldPropSet);
productPropSet.put("颜色", propSet);
}
//////////////////////////////////// 获取商品颜色属性 END ////////////////////////////////////////////
String fullPrice = JsoupUtil.getScriptTagVariableContent(content, "window.final_price_value");
fullPrice = SpiderUtil.exchangeRate(fullPrice);
JSONObject skuObj = JsoupUtil.getItemDetailByName(content, "window.spStockItems");
JSONObject sizeObj = JsoupUtil.getItemDetailByName(content, "window.spConfig");
JSONObject attributesObj = sizeObj.getJSONObject("attributes");
// 往下迭代一层
Iterator iterator = attributesObj.keys();
JSONArray optionsArr = new JSONArray();
while(iterator.hasNext()){
String key = (String) iterator.next();
String value = attributesObj.getString(key);
optionsArr = JSONObject.fromObject(value).getJSONArray("options");
}
for (int j = 0; j < optionsArr.size(); j++) {
JSONObject optionsObj = optionsArr.getJSONObject(j);
///////////////////////// 获取商品尺码属性 ////////////////////
ProductProp productPropSize = new ProductProp();
String sizeNo = optionsObj.getJSONArray("products").toString();
sizeNo = SpiderUtil.retainNumber(sizeNo);
String size = optionsObj.getString("label");
productPropSize.setPropName(size);
productPropSize.setPropId(sizeNo);
sizePropSet.add(productPropSize);
if (productPropSet.get("尺码") == null) {
productPropSet.put("尺码", sizePropSet);
} else {
Set<ProductProp> oldPropSet = productPropSet.get("尺码");
sizePropSet.addAll(oldPropSet);
productPropSet.put("尺码", sizePropSet);
}
///////////////////////// 获取商品尺码属性 END////////////////////
// 商品的库存id
String skuStr = ";" + colorNo + ";" + sizeNo + ";";
//////////////////////////////////// 获取库存 ////////////////////////////////////////////
// 设置:商品包含库存信息
ProductSkuStock productSkuStock = new ProductSkuStock();
if (productSkuStockList == null) {
productSkuStockList = new ArrayList<>();
}
// 获取库存数
int sellableQuantity = Integer.valueOf(skuObj.getJSONObject(sizeNo).getString("qty"));
productSkuStock.setSellableQuantity(sellableQuantity);
productSkuStock.setSkuStr(skuStr);
productSkuStockList.add(productSkuStock);
dynStock.setProductSkuStockList(productSkuStockList);
//////////////////////////////////// 获取库存 END///////////////////////////////////
//////////////////////////////////// 获取原始价 //////////////////////////////////
OriginalPrice originalPrice = new OriginalPrice();
originalPrice.setSkuStr(skuStr);
originalPrice.setPrice(fullPrice);
originalPriceList.add(originalPrice);
productResponse.setPrice(fullPrice);
productResponse.setSalePrice(fullPrice + "-" + fullPrice);
//////////////////////////////////// 获取原始价 END//////////////////////////////////
}
}
productResponse.setProductPropSet(productPropSet);
productResponse.setPlatform("Fendi");
productResponse.setPromotionList(promotionList);
productResponse.setOriginalPriceList(originalPriceList);
productResponse.setItemInfo(itemInfo);
productResponse.setDynStock(dynStock);
return productResponse;
}
}
\ No newline at end of file
package com.example.afrishop_v3.bis.impl;
import com.example.afrishop_v3.bis.IItemSpider;
import com.example.afrishop_v3.enums.PlatformEnum;
import com.example.afrishop_v3.vo.*;
import com.example.afrishop_v3.util.*;
import com.example.afrishop_v3.bis.IItemSpider;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import static com.example.afrishop_v3.util.SpiderUtil.exchangeRate;
/**
* Gap数据爬虫
*
* @author G
*/
@Component("gapItemSpider")
public class GapItemSpider implements IItemSpider {
private static Logger logger = LoggerFactory.getLogger(GapItemSpider.class);
/**
* GAP 商品详情页链接
*/
private static final String gapUrl="https://apicn.gap.cn/gap/store/product/list/searchProductByCondition.do";
/**
* 爬虫数据返回
* @param targetUrl 商品详情页路径
* @return
*/
@Override
public JSONObject captureItem(String targetUrl) throws IOException, InterruptedException, ExecutionException, TimeoutException {
JSONObject resultObj;
//获取链接中的商品spuCode
String itemId= getItemId(targetUrl);
Map<String,Object> paramMap=new HashMap<>();
JSONArray conditionList=new JSONArray();
JSONObject valueObj =new JSONObject();
JSONObject condition =new JSONObject();
valueObj.put("key","style");
valueObj.put("valueType","basic");
valueObj.put("value",new String [] {itemId});
conditionList.add(valueObj);
condition.put("conditionList",conditionList);
paramMap.put("data",condition);
//获取请求结果
String content = HttpClientUtil.sendPostWithBodyParameter(gapUrl,paramMap);
resultObj=JSONObject.fromObject(content);
if(resultObj.getBoolean("success")) {
//格式化为封装数据
ProductResponse productResponse = formatGapProductResponse(resultObj.getJSONObject("data"));
resultObj=JSONObject.fromObject(productResponse);
//翻译
TranslateHelper.translateProductResponse(resultObj);
}
return resultObj;
}
/**
* 获取商品链接的 id
* @param targetUrl
* @return
*/
private String getItemId(String targetUrl) {
String spuCode=targetUrl.substring(targetUrl.lastIndexOf("/")+1);
int firstUnder=spuCode.indexOf("_");
int lastUnder=spuCode.lastIndexOf("_");
return spuCode.substring(firstUnder+1,lastUnder);
}
/**
* 格式化 gap 返回数据
*
* @param dataMap
* @return
*/
private ProductResponse formatGapProductResponse(JSONObject dataMap) {
ProductResponse productResponse = new ProductResponse();
//原始价
List<OriginalPrice> originalPriceList = new ArrayList<>();
//促销价格
List<ProductPromotion> promotionList = new ArrayList<>();
Map<String, Set<ProductProp>> productPropSet = new HashMap<>();
JSONArray productList = dataMap.getJSONArray("productList");
//商品信息
ItemInfo itemInfo = new ItemInfo();
for (int index = 0; index < productList.size(); index++) {
JSONObject propObj = productList.getJSONObject(index);
//////////////////获取价格//////////////////
JSONArray skuList = propObj.getJSONArray("skuList");
for (int i = 0; i < skuList.size(); i++) {
JSONObject skuValue = skuList.getJSONObject(i);
JSONArray attrSaleList = skuValue.getJSONArray("attrSaleList");
String skuStr = ";";
for (int m = 0; m < attrSaleList.size(); m++) {
JSONObject attrSale = attrSaleList.getJSONObject(m);
JSONArray attributeValueList = attrSale.getJSONArray("attributeValueList");
skuStr = skuStr + attributeValueList.getJSONObject(0).getString("code") + ";";
}
//原始价格
OriginalPrice originalPrice = new OriginalPrice();
originalPrice.setSkuStr(skuStr);
String listPrice = skuValue.getString("listPrice");
//转换汇率
listPrice = exchangeRate(listPrice);
originalPrice.setPrice(listPrice);
originalPriceList.add(originalPrice);
//促销价格
if (StringUtils.isNotBlank(skuValue.getString("salePrice"))) {
String salePrice = skuValue.getString("salePrice");
//转换汇率
salePrice = exchangeRate(salePrice);
productResponse.setPromotionFlag(true);
ProductPromotion productPromotion = new ProductPromotion();
productPromotion.setSkuStr(skuStr);
productPromotion.setPrice(salePrice);
promotionList.add(productPromotion);
}
}
//////////////////获取价格 END//////////////////
//////////////////获取商品属性//////////////////
JSONArray attrSaleList = propObj.getJSONArray("attrSaleList");
for (int i = 0; i < attrSaleList.size(); i++) {
JSONArray attributeValueList = attrSaleList.getJSONObject(i).getJSONArray("attributeValueList");
//商品属性
Set<ProductProp> propSet = new HashSet<>();
for (int j = 0; j < attributeValueList.size(); j++) {
ProductProp productProp = new ProductProp();
//获取图片,拿第一张
if (attributeValueList.getJSONObject(j).get("itemAttributeValueImageList") != null && !"null".equalsIgnoreCase(attributeValueList.getJSONObject(j).getString("itemAttributeValueImageList"))) {
JSONArray itemAttributeValueImageList = attributeValueList.getJSONObject(j).getJSONArray("itemAttributeValueImageList");
productProp.setImage(itemAttributeValueImageList.getJSONObject(0).getString("picUrl"));
}
productProp.setPropName(attributeValueList.getJSONObject(j).getString("attributeValueName"));
productProp.setPropId(attributeValueList.getJSONObject(j).getString("code"));
propSet.add(productProp);
}
String attributeFrontName = attrSaleList.getJSONObject(i).getString("attributeFrontName");
if (productPropSet.get(attributeFrontName) == null) {
productPropSet.put(attributeFrontName, propSet);
} else {
Set<ProductProp> oldPropSet = productPropSet.get(attributeFrontName);
propSet.addAll(oldPropSet);
productPropSet.put(attributeFrontName, propSet);
}
}
//////////////////获取商品属性 END//////////////////
itemInfo.setItemId(propObj.getString("style"));
if (propObj.get("itemImageList") != null && !"null".equalsIgnoreCase(propObj.getString("itemImageList"))) {
JSONArray itemImageList = propObj.getJSONArray("itemImageList");
if (!itemImageList.isEmpty()) {
String pic = itemImageList.getJSONObject(0).getString("picUrl");
//取第一张当作主图
itemInfo.setPic(pic);
}
}
itemInfo.setShopName(PlatformEnum.GAP.getLabel());
itemInfo.setShopUrl("https://www.gap.cn/");
itemInfo.setTitle(propObj.getString("title"));
}
String minPrice = dataMap.getString("minPrice");
String maxPrice = dataMap.getString("maxPrice");
//转换汇率
minPrice = exchangeRate(minPrice);
maxPrice = exchangeRate(maxPrice);
//一口价
productResponse.setPrice(minPrice + "-" + maxPrice);
//一口价
productResponse.setSalePrice(minPrice + "-" + maxPrice);
//没有库存信息 需要另外获取
productResponse.setStockFlag(false);
//有商品属性
productResponse.setPropFlag(true);
productResponse.setOriginalPriceList(originalPriceList);
productResponse.setPromotionList(promotionList);
productResponse.setItemInfo(itemInfo);
productResponse.setPlatform(PlatformEnum.GAP.getValue());
productResponse.setProductPropSet(productPropSet);
return productResponse;
}
}
package com.example.afrishop_v3.bis.impl;
import com.example.afrishop_v3.bis.IItemSpider;
import com.example.afrishop_v3.enums.PlatformEnum;
import com.example.afrishop_v3.util.HttpClientUtil;
import com.example.afrishop_v3.util.TranslateHelper;
import com.example.afrishop_v3.vo.*;
import net.sf.json.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static com.example.afrishop_v3.util.SpiderUtil.exchangeRate;
/**
* H&M 数据爬虫
*
* @author 爱酱油不爱醋
*/
@Component("hmSpider")
public class HmSpider implements IItemSpider {
private static Logger logger = LoggerFactory.getLogger(UniqloSpider.class);
/**
* H&M 数据格式化
*
* @param targetUrl
* @return
*/
@Override
public JSONObject captureItem(String targetUrl) throws URISyntaxException, IOException, ExecutionException, InterruptedException, TimeoutException {
Pattern pattern = Pattern.compile("\\d+");
Matcher matcher = pattern.matcher(targetUrl);
matcher.find();
targetUrl = "https://www.hm.com.cn/en_cn/" + matcher.group() + ".html";
String content = HttpClientUtil.getContentByUrl(targetUrl, PlatformEnum.HM.getValue());
ProductResponse productResponse = formatProductResponse(content);
JSONObject resultObj = JSONObject.fromObject(productResponse);
TranslateHelper.translateProductResponse(resultObj);
return resultObj;
}
/**
* 格式化返回数据
* TODO 存在把不在页面上显示的颜色的尺码也算了进去
*
* @param content 页面数据
* @return 格式化后的数据
*/
public static ProductResponse formatProductResponse(String content) throws IOException, URISyntaxException {
Document document = Jsoup.parse(content);
// 声明封装类
ProductResponse productResponse = new ProductResponse();
// 含有商品的属性,设置为true
productResponse.setPropFlag(true);
// 库存信息,如果没有可使用的库存信息则默认为999
DynStock dynStock = new DynStock();
dynStock.setSellableQuantity(9999);
List<ProductSkuStock> productSkuStockList = dynStock.getProductSkuStockList();
// 产品的原始价与优惠价
List<OriginalPrice> originalPriceList = new ArrayList<>();
List<ProductPromotion> promotionList = new ArrayList<>();
// 商品的属性,常用的商品属性为颜色与尺码
Map<String, Set<ProductProp>> productPropSet = new HashMap<>(16);
Set<ProductProp> propSet = new HashSet<>(16);
Set<ProductProp> sizePropSet = new HashSet<>(16);
productResponse.setStockFlag(false);
// 商品的基本属性
ItemInfo itemInfo = new ItemInfo();
//////////////////////////////////// 获取商品基本信息 ////////////////////////////
itemInfo.setShopName("H&M");
itemInfo.setShopUrl("https://www.hm.com.cn/");
itemInfo.setItemId(document.select("div[class=product-info-main]").select("a").attr("data-product-id"));
itemInfo.setTitle(document.select("meta[name=title]").attr("content"));
//////////////////////////////////// 获取商品基本信息(图片下取)End /////////////////////////
// 获取原始价
String fullPrice = document.select("meta[property=product:price:amount]").attr("content");
// TODO 转换汇率,目前商品单位是人民币
fullPrice = exchangeRate(fullPrice);
//////////////////////////////////// 获取商品颜色属性 ////////////////////////////////////////////
// 取页面的数据
Elements colorEle = document.select("div[id=article-list-owl]").select("div");
List<String> urlList = new ArrayList<>();
for (Element element : colorEle) {
if (!StringUtils.isEmpty(element.attr("data-product-url"))) {
// 获取其他商品的链接
urlList.add(element.attr("data-product-url"));
}
}
for (String url : urlList) {
content = HttpClientUtil.getContentByUrl(url, PlatformEnum.HM.getValue());
document = Jsoup.parse(content);
colorEle = document.select("span[class=current-article-title]");
String color = colorEle.attr("data-title");
String imgUrl = document.select("meta[property=og:image]").attr("content");
itemInfo.setPic(imgUrl);
ProductProp productPropColor = new ProductProp();
productPropColor.setPropId(color);
productPropColor.setPropName(color);
productPropColor.setImage(imgUrl);
propSet.add(productPropColor);
if (productPropSet.get("颜色") == null) {
productPropSet.put("颜色", propSet);
} else {
Set<ProductProp> oldPropSet = productPropSet.get("颜色");
propSet.addAll(oldPropSet);
productPropSet.put("颜色", propSet);
}
//////////////////////////////////// 获取商品颜色属性 END ////////////////////////////////////////////
///////////////////////// 获取商品尺码属性 ///////////////////////////////////////////////////////////
Elements sizeEles = document.select("div[class=picker-content]").select("div[class=size-option ]").select("span[class=variant-size-value]");
for (Element sizeEle : sizeEles) {
String size = sizeEle.text();
ProductProp productPropSize = new ProductProp();
productPropSize.setPropId(size);
productPropSize.setPropName(size);
sizePropSet.add(productPropSize);
if (productPropSet.get("尺码") == null) {
productPropSet.put("尺码", sizePropSet);
} else {
Set<ProductProp> oldPropSet = productPropSet.get("尺码");
sizePropSet.addAll(oldPropSet);
productPropSet.put("尺码", sizePropSet);
}
///////////////////////// 获取商品尺码属性END //////////////////////////////////////////////////////
// 设置 skuStr
String skuStr = ";" + color + ";" + size + ";";
//////////////////////////////////// 获取库存 ////////////////////////////////////////////
if (productSkuStockList == null) {
productSkuStockList = new ArrayList<>();
}
ProductSkuStock productSkuStock = new ProductSkuStock();
productSkuStock.setSkuStr(skuStr);
productSkuStock.setSellableQuantity(999);
productSkuStockList.add(productSkuStock);
dynStock.setProductSkuStockList(productSkuStockList);
//////////////////////////////////// 获取库存 END/////////////////////////////////////////
//////////////////////////////////// 获取原始价 //////////////////////////////////
OriginalPrice originalPrice = new OriginalPrice();
originalPrice.setSkuStr(skuStr);
originalPrice.setPrice(fullPrice);
originalPriceList.add(originalPrice);
productResponse.setPrice(fullPrice);
productResponse.setSalePrice(fullPrice + "-" + fullPrice);
//////////////////////////////////// 获取原始价 END//////////////////////////////////
}
}
productResponse.setProductPropSet(productPropSet);
productResponse.setPlatform("H&M");
productResponse.setPromotionList(promotionList);
productResponse.setOriginalPriceList(originalPriceList);
productResponse.setItemInfo(itemInfo);
productResponse.setDynStock(dynStock);
return productResponse;
}
}
package com.example.afrishop_v3.bis.impl;
import com.example.afrishop_v3.bis.IItemSpider;
import com.example.afrishop_v3.enums.PlatformEnum;
import com.example.afrishop_v3.vo.*;
import com.example.afrishop_v3.util.*;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import static com.example.afrishop_v3.util.SpiderUtil.exchangeRate;
/**
* Levi(李维斯)
*
* @author 爱酱油不爱醋
*/
@Component("leviSpider")
public class LeviSpider implements IItemSpider {
private static Logger logger = LoggerFactory.getLogger(PullandbearSpider.class);
/**
* Levi(李维斯) 数据爬虫
* @param targetUrl 接收的商品详情路径
* @return 格式化与翻译后的 Json 数据
*/
@Override
public JSONObject captureItem(String targetUrl) throws InterruptedException, IOException, ExecutionException, URISyntaxException, TimeoutException {
String content = HttpClientUtil.getContentByUrl(targetUrl, PlatformEnum.LEVI.getValue());
JSONObject dataMap = JsoupUtil.getItemDetailByName(content, "window.__INITIAL_STATE__");
ProductResponse productResponse = formatProductResponse(dataMap);
if (productResponse.getItemInfo() == null) {
JSONObject notSpiderObj = new JSONObject();
notSpiderObj.put("message", "未找到此网站的数据爬虫!");
return notSpiderObj;
}
JSONObject resultObj = JSONObject.fromObject(productResponse);
TranslateHelper.translateProductResponse(resultObj);
return resultObj;
}
/**
* 格式化返回数据
* @param dataMap 主要的Json数据
* @return 格式化后的数据
*/
private ProductResponse formatProductResponse(JSONObject dataMap) {
// 声明封装类
ProductResponse productResponse = new ProductResponse();
// 含有商品的属性,设置为true
productResponse.setPropFlag(true);
// 库存信息,如果没有可使用的库存信息则默认为999
DynStock dynStock = new DynStock();
dynStock.setSellableQuantity(9999);
List<ProductSkuStock> productSkuStockList = dynStock.getProductSkuStockList();
// 产品的原始价与优惠价
List<OriginalPrice> originalPriceList = new ArrayList<>();
List<ProductPromotion> promotionList = new ArrayList<>();
// 商品的属性,常用的商品属性为颜色与尺码
Map<String, Set<ProductProp>> productPropSet = new HashMap<>(16);
Set<ProductProp> propSet = new HashSet<>(16);
Set<ProductProp> sizePropSet = new HashSet<>(16);
productResponse.setStockFlag(true);
// 商品的基本属性
ItemInfo itemInfo = new ItemInfo();
// 取 product 下的 details 节点对象
JSONObject detailsObj = dataMap.getJSONObject("product").getJSONObject("details");
// 判断如果不是商品详情页读取数据,则返回
if (!detailsObj.containsKey("code")) {
return productResponse;
}
// 获取商品的原始价
String fullPrice = detailsObj.getJSONObject("salePrice").getString("amount");
// TODO 转换汇率,目前商品单位是人民币
fullPrice = exchangeRate(fullPrice);
//////////////////////////////////// 获取商品基本信息 ////////////////////////////
itemInfo.setShopName("Levi");
itemInfo.setShopUrl("https://www.levi.com");
itemInfo.setItemId(detailsObj.getString("code"));
itemInfo.setTitle(detailsObj.getString("title"));
//////////////////////////////////// 获取商品基本信息(图片下取)End /////////////////////////
JSONArray values_0_Arr = detailsObj.getJSONArray("options").getJSONObject(0).getJSONArray("values");
JSONArray values_1_Arr = detailsObj.getJSONArray("options").getJSONObject(1).getJSONArray("values");
//////////////////////////////////// 获取商品颜色属性 ////////////////////////////////////////////
// 取 options 的0位的 value 节点数组
for (int i = 0; i < values_0_Arr.size(); i++) {
JSONObject values_0_Obj = values_0_Arr.getJSONObject(i);
String colorNo = values_0_Obj.getString("code");
String color = values_0_Obj.getString("displayName");
String imageUrl = values_0_Obj.getJSONArray("images").getJSONObject(0).getString("url");
if (i == 0) {
itemInfo.setPic(imageUrl);
}
ProductProp productPropColor = new ProductProp();
productPropColor.setPropId(colorNo);
productPropColor.setPropName(color);
productPropColor.setImage(imageUrl);
propSet.add(productPropColor);
if (productPropSet.get("颜色") == null) {
productPropSet.put("颜色", propSet);
} else {
Set<ProductProp> oldPropSet = productPropSet.get("颜色");
propSet.addAll(oldPropSet);
productPropSet.put("颜色", propSet);
}
//////////////////////////////////// 获取商品颜色属性 END ////////////////////////////////////////////
///////////////////////// 获取商品尺码属性 ////////////////////////////////////////////////////////////////
// 取 options 的 1 位的 value 节点数组
for (int j = 0; j < values_1_Arr.size(); j++) {
JSONObject values_1_Obj = values_1_Arr.getJSONObject(j);
String sizeNo = values_1_Obj.getString("code");
String size = values_1_Obj.getString("displayName");
ProductProp productPropSize = new ProductProp();
productPropSize.setPropId(sizeNo);
productPropSize.setPropName(size);
sizePropSet.add(productPropSize);
if (productPropSet.get("尺码") == null) {
productPropSet.put("尺码", sizePropSet);
} else {
Set<ProductProp> oldPropSet = productPropSet.get("尺码");
sizePropSet.addAll(oldPropSet);
productPropSet.put("尺码", sizePropSet);
}
///////////////////////// 获取商品尺码属性 END/////////////////////////////////////////////////////
// 设置 skuStr
String skuStr = ";" + colorNo + ";" + sizeNo + ";";
//////////////////////////////////// 获取库存 ////////////////////////////////////////////
if (productSkuStockList == null) {
productSkuStockList = new ArrayList<>();
}
ProductSkuStock productSkuStock = new ProductSkuStock();
productSkuStock.setSkuStr(skuStr);
productSkuStock.setSellableQuantity(999);
productSkuStockList.add(productSkuStock);
dynStock.setProductSkuStockList(productSkuStockList);
//////////////////////////////////// 获取库存 END/////////////////////////////////////////
//////////////////////////////////// 获取原始价 //////////////////////////////////
OriginalPrice originalPrice = new OriginalPrice();
originalPrice.setSkuStr(skuStr);
originalPrice.setPrice(fullPrice);
originalPriceList.add(originalPrice);
productResponse.setPrice(fullPrice);
productResponse.setSalePrice(fullPrice + "-" + fullPrice);
//////////////////////////////////// 获取原始价 END//////////////////////////////////
}
}
productResponse.setProductPropSet(productPropSet);
productResponse.setPlatform("Levi");
productResponse.setPromotionList(promotionList);
productResponse.setOriginalPriceList(originalPriceList);
productResponse.setItemInfo(itemInfo);
productResponse.setDynStock(dynStock);
return productResponse;
}
}
\ No newline at end of file
package com.example.afrishop_v3.bis.impl;
import com.example.afrishop_v3.bis.IItemSpider;
import net.sf.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
/**
* Lily 数据爬虫
*
* TODO 数据已分析,难度较大,延后处理
*
* @author 爱酱油不爱醋
*/
@Component("lilySpider")
public class LilySpider implements IItemSpider {
private static Logger logger = LoggerFactory.getLogger(PullandbearSpider.class);
/**
* Lily 商品详情页 Url
*/
private static final String ADIDAS_URL="http://www.lily.sh.cn/webapp/wcs/stores/servlet/lilystore";
/**
* Lily 数据爬虫
* @param targetUrl 接收的商品详情路径
* @return 格式化与翻译后的 Json 数据
*/
@Override
public JSONObject captureItem(String targetUrl) throws InterruptedException, IOException, ExecutionException, URISyntaxException, TimeoutException {
return null;
}
// public static void main(String[] args) throws Exception {
// String targetUrl = "http://www.lily.sh.cn/webapp/wcs/stores/servlet/lilystore/24003/276409";
// String content = HttpClientUtil.getContentByUrl(targetUrl, PlatformEnum.LILY.getValue());
// Document document = Jsoup.parse(content);
//
// String str = document.select("input[id=skus]").attr("value");
// }
}
package com.example.afrishop_v3.bis.impl;
import com.example.afrishop_v3.bis.IItemSpider;
import com.example.afrishop_v3.enums.PlatformEnum;
import com.example.afrishop_v3.vo.*;
import com.example.afrishop_v3.util.*;
import net.sf.json.JSONObject;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import static com.example.afrishop_v3.util.SpiderUtil.exchangeRate;
/**
* LouisVuitton(路易威登LV) 数据爬虫
*
* @author 爱酱油不爱醋
*/
@Component("louisVuittonSpider")
public class LouisVuittonSpider implements IItemSpider {
private static Logger logger = LoggerFactory.getLogger(PullandbearSpider.class);
/**
* LouisVuitton(路易威登LV) 数据爬虫
*
* @param targetUrl 接收的商品详情路径
* @return 格式化与翻译后的 Json 数据
*/
@Override
public JSONObject captureItem(String targetUrl) throws InterruptedException, IOException, ExecutionException, URISyntaxException, TimeoutException {
String content = HttpClientUtil.getContentByUrl(targetUrl, PlatformEnum.FENDI.getValue());
ProductResponse productResponse = formatProductResponse(content);
JSONObject resultObj = JSONObject.fromObject(productResponse);
TranslateHelper.translateProductResponse(resultObj);
return resultObj;
}
/**
* 格式化返回数据
*
* @param content 主要的网页内容
* @return 格式化后的数据
*/
private ProductResponse formatProductResponse(String content) {
// 声明封装类
ProductResponse productResponse = new ProductResponse();
// 含有商品的属性,设置为true
productResponse.setPropFlag(true);
// 库存信息,如果没有可使用的库存信息则默认为999
DynStock dynStock = new DynStock();
dynStock.setSellableQuantity(9999);
List<ProductSkuStock> productSkuStockList = dynStock.getProductSkuStockList();
// 产品的原始价与优惠价
List<OriginalPrice> originalPriceList = new ArrayList<>();
List<ProductPromotion> promotionList = new ArrayList<>();
// 商品的属性,常用的商品属性为颜色与尺码
Map<String, Set<ProductProp>> productPropSet = new HashMap<>(16);
Set<ProductProp> propSet = new HashSet<>(16);
Set<ProductProp> sizePropSet = new HashSet<>(16);
productResponse.setStockFlag(true);
// 商品的基本属性
ItemInfo itemInfo = new ItemInfo();
Document document = Jsoup.parse(content);
Elements skuEle = document.select("div[id=infoProductBlock]");
// 获取商品的 id
String pId = skuEle.select("span[class=sku]").text();
// 获取该商品的一张图片
String imageUrl = document.select("li[id=productSheetSlideshowItem_0]").select("img").attr("src");
String[] spilt = imageUrl.split("[?]");
imageUrl = spilt[0];
// 获取价格
String fullPrice = document.select("div[class=productAction]").select("span[class=priceValuePurchaseLayer]").text();
fullPrice = SpiderUtil.retainNumber(fullPrice);
fullPrice = exchangeRate(fullPrice);
//////////////////////////////////// 获取商品基本信息 ////////////////////////////
itemInfo.setShopName("LouisVuitton");
itemInfo.setShopUrl("https://inside.chanel.com/");
itemInfo.setItemId(pId);
itemInfo.setTitle(skuEle.select("h1[class=productName]").text());
itemInfo.setPic(imageUrl);
//////////////////////////////////// 获取商品基本信息End /////////////////////////
///////////////////////// 获取商品颜色属性 ////////////////////////////////////////////////////////////////
// TODO 此处还需要加颜色判断
String colorNo = pId;
ProductProp productPropColor = new ProductProp();
productPropColor.setPropId(pId);
productPropColor.setPropName(pId);
productPropColor.setImage(imageUrl);
propSet.add(productPropColor);
if (productPropSet.get("颜色") == null) {
productPropSet.put("颜色", propSet);
} else {
Set<ProductProp> oldPropSet = productPropSet.get("颜色");
propSet.addAll(oldPropSet);
productPropSet.put("颜色", propSet);
}
///////////////////////// 获取商品颜色属性End ////////////////////////////////////////////////////////////////
Elements sizeEle = skuEle.select("div[class=topPanelContent sizesPanel js-tracking]").select("ul[id=size]").select("li");
for (Element element : sizeEle) {
String sizeNo = element.attr("data-ona");
String size = element.select("span").text();
///////////////////////// 获取商品尺码属性 END/////////////////////////////////////////////////////
ProductProp productPropSize = new ProductProp();
productPropSize.setPropId(sizeNo);
productPropSize.setPropName(size);
sizePropSet.add(productPropSize);
if (productPropSet.get("尺码") == null) {
productPropSet.put("尺码", sizePropSet);
} else {
Set<ProductProp> oldPropSet = productPropSet.get("尺码");
sizePropSet.addAll(oldPropSet);
productPropSet.put("尺码", sizePropSet);
}
///////////////////////// 获取商品尺码属性 END/////////////////////////////////////////////////////
//////////////////////////////////// 获取库存/////////////////////////////////////////
// 设置 skuStr
String skuStr = ";" + colorNo + ";" + sizeNo + ";";
if (productSkuStockList == null) {
productSkuStockList = new ArrayList<>();
}
ProductSkuStock productSkuStock = new ProductSkuStock();
productSkuStock.setSellableQuantity(999);
productSkuStock.setSkuStr(skuStr);
productSkuStockList.add(productSkuStock);
dynStock.setProductSkuStockList(productSkuStockList);
//////////////////////////////////// 获取库存 END/////////////////////////////////////////
//////////////////////////////////// 获取原始价 //////////////////////////////////
OriginalPrice originalPrice = new OriginalPrice();
originalPrice.setSkuStr(skuStr);
originalPrice.setPrice(fullPrice);
originalPriceList.add(originalPrice);
productResponse.setPrice(fullPrice);
productResponse.setSalePrice(fullPrice + "-" + fullPrice);
//////////////////////////////////// 获取原始价 END //////////////////////////////////
}
productResponse.setProductPropSet(productPropSet);
productResponse.setPlatform("LouisVuitton");
productResponse.setPromotionList(promotionList);
productResponse.setOriginalPriceList(originalPriceList);
productResponse.setItemInfo(itemInfo);
productResponse.setDynStock(dynStock);
return productResponse;
}
}
\ No newline at end of file
package com.example.afrishop_v3.bis.impl;
import com.example.afrishop_v3.bis.IItemSpider;
import com.example.afrishop_v3.enums.PlatformEnum;
import com.example.afrishop_v3.vo.*;
import com.example.afrishop_v3.util.*;
import net.sf.json.JSONObject;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
/**
* MajeSpider 数据爬虫
*
* @author 爱酱油不爱醋
*/
@Component("majeSpider")
public class MajeSpider implements IItemSpider {
private static Logger logger = LoggerFactory.getLogger(MajeSpider.class);
/**
* Maje 数据爬虫
* @param targetUrl 接收的商品详情路径
* @return 格式化与翻译后的 Json 数据
*/
@Override
public JSONObject captureItem(String targetUrl) throws URISyntaxException, IOException, ExecutionException, InterruptedException, TimeoutException {
String content = HttpClientUtil.getContentByUrl(targetUrl, PlatformEnum.MAJE.getValue());
ProductResponse productResponse = formatProductResponse(content);
JSONObject resultObj = JSONObject.fromObject(productResponse);
TranslateHelper.translateProductResponse(resultObj);
return resultObj;
}
/**
* 格式化返回数据
* @param content 主要的页面数据
* @return 格式化后的数据
*/
public static ProductResponse formatProductResponse(String content) {
// 声明封装类
ProductResponse productResponse = new ProductResponse();
// 含有商品的属性,设置为true
productResponse.setPropFlag(true);
// 库存信息,如果没有可使用的库存信息则默认为999
DynStock dynStock = new DynStock();
dynStock.setSellableQuantity(9999);
List<ProductSkuStock> productSkuStockList = dynStock.getProductSkuStockList();
// 产品的原始价与优惠价
List<OriginalPrice> originalPriceList = new ArrayList<>();
List<ProductPromotion> promotionList = new ArrayList<>();
// 商品的属性,常用的商品属性为颜色与尺码
Map<String, Set<ProductProp>> productPropSet = new HashMap<>(16);
Set<ProductProp> propSet = new HashSet<>(16);
Set<ProductProp> sizePropSet = new HashSet<>(16);
productResponse.setStockFlag(true);
// 商品的基本属性
ItemInfo itemInfo = new ItemInfo();
Document document = Jsoup.parse(content);
//////////////////////////////////// 获取商品基本信息 ////////////////////////////
itemInfo.setItemId(document.select("span[class=breadcrumb-last]").text());
itemInfo.setShopName("Maje");
itemInfo.setShopUrl("https://www.maje.cn/");
itemInfo.setTitle(document.select("meta[property=og:title]").attr("content"));
//////////////////////////////////// 获取商品基本信息End /////////////////////////
String fullPrice = document.select("meta[property=product:price:amount]").attr("content");
fullPrice = SpiderUtil.exchangeRate(fullPrice);
Elements pContentEle = document.select("div[id=product-content]").select("ul[class=dropdown-content]");
Elements colorsEle = pContentEle.select("ul[class=swatches Color]").select("a");
//////////////////////////////////// 获取商品颜色属性 ////////////////////////////
for (int i = 0; i < colorsEle.size(); i++) {
String dataIgimg = colorsEle.get(i).attr("data-lgimg");
JSONObject dataIgimgObj = JSONObject.fromObject(dataIgimg);
String colorNo = colorsEle.get(i).attr("data-variationparameter");
String color = colorsEle.get(i).attr("title");
String imgUrl = dataIgimgObj.getString("url");
if (i == 0) {
itemInfo.setPic(imgUrl);
}
ProductProp productPropColor = new ProductProp();
productPropColor.setPropId(colorNo);
productPropColor.setPropName(color);
productPropColor.setImage(imgUrl);
propSet.add(productPropColor);
if (productPropSet.get("颜色") == null) {
productPropSet.put("颜色", propSet);
} else {
Set<ProductProp> oldPropSet = productPropSet.get("颜色");
propSet.addAll(oldPropSet);
productPropSet.put("颜色", propSet);
}
//////////////////////////////////// 获取商品颜色属性 END ////////////////////////////////////////
///////////////////////// 获取商品尺码属性 ///////////////////////////////////////////////////////
Elements sizesEle = pContentEle.select("ul[class=swatches size]").select("a");
for (Element sizeEle : sizesEle) {
String sizeNo = sizeEle.attr("data-variationparameter");
String size = sizeEle.attr("title");
ProductProp productPropSize = new ProductProp();
productPropSize.setPropId(sizeNo);
productPropSize.setPropName(size);
sizePropSet.add(productPropSize);
if (productPropSet.get("尺码") == null) {
productPropSet.put("尺码", sizePropSet);
} else {
Set<ProductProp> oldPropSet = productPropSet.get("尺码");
sizePropSet.addAll(oldPropSet);
productPropSet.put("尺码", sizePropSet);
}
///////////////////////// 获取商品尺码属性 END///////////////////////////////////////////////////
//////////////////////////////////// 获取库存与原始价 ////////////////////////////////////////////
String skuStr = ";" + colorNo + ";" + sizeNo + ";";
if (productSkuStockList == null) {
productSkuStockList = new ArrayList<>();
}
ProductSkuStock productSkuStock = new ProductSkuStock();
productSkuStock.setSkuStr(skuStr);
productSkuStock.setSellableQuantity(999);
if (size.length() < 3) {
productSkuStockList.add(productSkuStock);
}
dynStock.setProductSkuStockList(productSkuStockList);
OriginalPrice originalPrice = new OriginalPrice();
originalPrice.setSkuStr(skuStr);
originalPrice.setPrice(fullPrice);
if (size.length() < 3) {
originalPriceList.add(originalPrice);
}
productResponse.setPrice(fullPrice);
productResponse.setSalePrice(fullPrice + "-" + fullPrice);
//////////////////////////////////// 获取库存与原始价 END///////////////////////////////
}
}
productResponse.setProductPropSet(productPropSet);
productResponse.setPlatform("Maje");
productResponse.setPromotionList(promotionList);
productResponse.setOriginalPriceList(originalPriceList);
productResponse.setItemInfo(itemInfo);
productResponse.setDynStock(dynStock);
return productResponse;
}
}
package com.example.afrishop_v3.bis.impl;
import com.example.afrishop_v3.bis.IItemSpider;
import com.example.afrishop_v3.enums.PlatformEnum;
import com.example.afrishop_v3.vo.*;
import com.example.afrishop_v3.util.*;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.URISyntaxException;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
/**
* Massimo Dutti 数据爬虫
*
* @author 爱酱油不爱醋
*/
@Component("massimoduttiSpider")
public class MassimoduttiSpider implements IItemSpider {
private static Logger logger = LoggerFactory.getLogger(ZaraSpider.class);
/**
* Massimo Dutti 数据爬虫
* @param targetUrl 接收的商品详情路径
* @return 格式化与翻译后的 Json 数据
*/
@Override
public JSONObject captureItem(String targetUrl) throws URISyntaxException, IOException, ExecutionException, InterruptedException, TimeoutException {
// 截取链接中商品的 id
String[] split = targetUrl.split(".html");
String pUrl = split[0];
int pChar = pUrl.lastIndexOf("p");
String pId = pUrl.substring(pChar + 1);
String dataUrl = "https://www.massimodutti.cn/itxrest/2/catalog/store/35009478/30359500/category/0/product/" + pId + "/detail?languageId=-7&appId=1";
String content = HttpClientUtil.getContentByUrl(dataUrl, PlatformEnum.MASSIMODUTTI.getValue());
JSONObject resultObj = JSONObject.fromObject(content);
ProductResponse productResponse = formatProductResponse(resultObj, pId);
resultObj = JSONObject.fromObject(productResponse);
TranslateHelper.translateProductResponse(resultObj);
return resultObj;
}
/**
* 格式化返回数据
* @param dataMap 主要的 json 数据
* @param pId 商品链接的 id
* @return 格式化后的数据
*/
private ProductResponse formatProductResponse(JSONObject dataMap, String pId) {
// 声明封装类
ProductResponse productResponse = new ProductResponse();
// 含有商品的属性,设置为true
productResponse.setPropFlag(true);
// 库存信息,如果没有可使用的库存信息则默认为999
DynStock dynStock = new DynStock();
dynStock.setSellableQuantity(9999);
List<ProductSkuStock> productSkuStockList = dynStock.getProductSkuStockList();
// 产品的原始价与优惠价
List<OriginalPrice> originalPriceList = new ArrayList<>();
List<ProductPromotion> promotionList = new ArrayList<>();
// 商品的属性,常用的商品属性为颜色与尺码
Map<String, Set<ProductProp>> productPropSet = new HashMap<>(16);
Set<ProductProp> propSetColor = new HashSet<>(16);
Set<ProductProp> sizePropSetSize = new HashSet<>(16);
productResponse.setStockFlag(true);
// 商品的基本属性
ItemInfo itemInfo = new ItemInfo();
//////////////////////////////////// 获取商品基本信息 ////////////////////////////////////////////
itemInfo.setShopName("MassimoDutti");
itemInfo.setShopUrl("https://www.massimodutti.cn/cn/");
itemInfo.setItemId(pId);
itemInfo.setTitle(dataMap.getString("name"));
//////////////////////////////////// 获取商品基本信息End(图片下取) ////////////////////////////////////////////
// 取 detail 节点对象
JSONObject detailObj = dataMap.getJSONObject("detail");
// 取 colors 节点数组
JSONArray colorsArr = detailObj.getJSONArray("colors");
for (int i = 0; i < colorsArr.size(); i++) {
JSONObject colorsObj = colorsArr.getJSONObject(i);
JSONObject imageObj = colorsObj.getJSONObject("image");
String imageUrl = "https://static.massimodutti.cn/3/photos"
+ imageObj.getString("url")
+ "_2_5_16.jpg?t="
+ imageObj.getString("timestamp");
if (i == 0) {
itemInfo.setPic(imageUrl);
}
//////////////////////////////////// 获取商品颜色属性 ////////////////////////////////////////////
String colorNo = colorsObj.getString("id");
String color = colorsObj.getString("name");
ProductProp productPropColor = new ProductProp();
productPropColor.setPropId(colorNo);
productPropColor.setPropName(color);
productPropColor.setImage(imageUrl);
propSetColor.add(productPropColor);
if (productPropSet.get("颜色") == null) {
productPropSet.put("颜色", propSetColor);
} else {
Set<ProductProp> oldPropSet = productPropSet.get("颜色");
propSetColor.addAll(oldPropSet);
productPropSet.put("颜色", propSetColor);
}
//////////////////////////////////// 获取商品颜色属性 END ////////////////////////////////////////////
///////////////////////// 获取商品尺码属性 ////////////////////
// 取 sizes 节点对象
JSONArray sizesArr = colorsObj.getJSONArray("sizes");
for (int j = 0; j < sizesArr.size(); j++) {
JSONObject sizesObj = sizesArr.getJSONObject(j);
String sizeNo = sizesObj.getString("sku");
String size = sizesObj.getString("name");
ProductProp productPropSize = new ProductProp();
productPropSize.setPropName(size);
productPropSize.setPropId(sizeNo);
sizePropSetSize.add(productPropSize);
if (productPropSet.get("尺码") == null) {
productPropSet.put("尺码", sizePropSetSize);
} else {
Set<ProductProp> oldPropSet = productPropSet.get("尺码");
sizePropSetSize.addAll(oldPropSet);
productPropSet.put("尺码", sizePropSetSize);
}
///////////////////////// 获取商品尺码属性 END////////////////////
// 库存 id
String skuStr = ";" + colorNo + ";" + sizeNo;
//////////////////////////////////// 获取库存 ////////////////////////////////////////////
// 设置:商品包含库存信息
if (productSkuStockList == null) {
productSkuStockList = new ArrayList<>();
}
ProductSkuStock productSkuStock = new ProductSkuStock();
productSkuStock.setSkuStr(skuStr);
productSkuStock.setSellableQuantity(999);
productSkuStockList.add(productSkuStock);
dynStock.setProductSkuStockList(productSkuStockList);
//////////////////////////////////// 获取库存 END/////////////////////////////////////////
//////////////////////////////////// 获取原始价 //////////////////////////////////
String fullPrice = sizesObj.getString("price");
BigDecimal priceOld = new BigDecimal(fullPrice);
BigDecimal div = new BigDecimal("100");
BigDecimal priceNew = priceOld.divide(div, 2, BigDecimal.ROUND_HALF_UP);
fullPrice = SpiderUtil.exchangeRate(priceNew.toString());
OriginalPrice originalPrice = new OriginalPrice();
originalPrice.setSkuStr(skuStr);
originalPrice.setPrice(fullPrice);
originalPriceList.add(originalPrice);
productResponse.setPrice(fullPrice);
productResponse.setSalePrice(fullPrice + "-" + fullPrice);
//////////////////////////////////// 获取原始价 END//////////////////////////////////
}
}
// 按照一下顺序进行 json 数据的填充
productResponse.setProductPropSet(productPropSet);
productResponse.setPlatform("MassimoDutti");
productResponse.setPromotionList(promotionList);
productResponse.setOriginalPriceList(originalPriceList);
productResponse.setItemInfo(itemInfo);
productResponse.setDynStock(dynStock);
return productResponse;
}
}
package com.example.afrishop_v3.bis.impl;
import com.example.afrishop_v3.bis.IItemSpider;
import com.example.afrishop_v3.enums.PlatformEnum;
import com.example.afrishop_v3.vo.*;
import com.example.afrishop_v3.util.*;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import static com.example.afrishop_v3.util.SpiderUtil.exchangeRate;
/**
* MO&Co. 数据爬虫
*
* @author 爱酱油不爱醋
*/
@Component("mocoSpider")
public class MocoSpider implements IItemSpider {
private static Logger logger = LoggerFactory.getLogger(ZaraSpider.class);
/**
* MO&Co. 数据爬虫
*
* @param targetUrl 接收的商品详情路径
* @return 格式化与翻译后的 Json 数据
*/
@Override
public JSONObject captureItem(String targetUrl) throws URISyntaxException, IOException, ExecutionException, InterruptedException, TimeoutException {
// 截取链接中的商品id
String[] spilt = targetUrl.split("/p/");
String pId = spilt[1];
targetUrl = "https://www.moco.com/moco/zh/ajax/variant/" + pId;
// 通过接口获取主要商品的内容
String content = HttpClientUtil.getContentByUrl(targetUrl, PlatformEnum.MOCO.getValue());
JSONObject resultObj = JSONObject.fromObject(content);
// 格式化数据
ProductResponse productResponse = formatProductResponse(resultObj, pId);
resultObj = JSONObject.fromObject(productResponse);
// 翻译数据
TranslateHelper.translateProductResponse(resultObj);
return resultObj;
}
/**
* 格式化返回数据
*
* @param dataMap 主要的 Json 内容
* @param pId 截取的商品 id
* @return 格式化后的数据
*/
private ProductResponse formatProductResponse(JSONObject dataMap, String pId) {
// 声明封装类
ProductResponse productResponse = new ProductResponse();
// 含有商品的属性,设置为true
productResponse.setPropFlag(true);
// 库存信息,如果没有可使用的库存信息则默认为999
DynStock dynStock = new DynStock();
dynStock.setSellableQuantity(9999);
List<ProductSkuStock> productSkuStockList = dynStock.getProductSkuStockList();
// 产品的原始价与优惠价
List<OriginalPrice> originalPriceList = new ArrayList<>();
List<ProductPromotion> promotionList = new ArrayList<>();
// 商品的属性,常用的商品属性为颜色与尺码
Map<String, Set<ProductProp>> productPropSet = new HashMap<>(16);
Set<ProductProp> propSet = new HashSet<>(16);
Set<ProductProp> sizePropSet = new HashSet<>(16);
productResponse.setStockFlag(false);
// 商品的基本属性
ItemInfo itemInfo = new ItemInfo();
// 取 productData 对象节点
JSONObject productDataObj = dataMap.getJSONObject("productData");
//////////////////////////////////// 获取商品基本信息 ////////////////////////////////////////////
itemInfo.setShopName("MO&Co.");
itemInfo.setShopUrl("https://en.mo-co.com/");
itemInfo.setItemId(pId);
itemInfo.setTitle(productDataObj.getString("name"));
//////////////////////////////////// 获取商品基本信息End(图片下取) ////////////////////////////////////////////
JSONArray options_1_Arr = productDataObj.getJSONArray("baseOptions").getJSONObject(1).getJSONArray("options");
JSONArray options_0_Arr = productDataObj.getJSONArray("baseOptions").getJSONObject(0).getJSONArray("options");
//////////////////////////////////// 获取商品颜色属性 ////////////////////////////////////////////
for (int i = 0; i < options_1_Arr.size(); i++) {
JSONObject options_1_Obj = options_1_Arr.getJSONObject(i);
// 获取图片的路径
String[] spiltImg = options_1_Obj.getJSONArray("variantOptionQualifiers")
.getJSONObject(0).getJSONObject("image").getString("url").split("_other_");
String colorNo = options_1_Obj.getString("epoColorCode");
String color = options_1_Obj.getString("epoColorName");
String imageUrl = "https://mallimg.moco.com/" + pId + "_list_" + spiltImg[1];
if (i == 0) {
itemInfo.setPic(imageUrl);
}
ProductProp productPropColor = new ProductProp();
productPropColor.setPropId(colorNo);
productPropColor.setPropName(color);
productPropColor.setImage(imageUrl);
propSet.add(productPropColor);
if (productPropSet.get("颜色") == null) {
productPropSet.put("颜色", propSet);
} else {
Set<ProductProp> oldPropSet = productPropSet.get("颜色");
propSet.addAll(oldPropSet);
productPropSet.put("颜色", propSet);
}
//////////////////////////////////// 获取商品颜色属性 END ////////////////////////////////////////////
///////////////////////// 获取商品尺码属性 ///////////////////////////////////////////////////////////
for (int j = 0; j < options_0_Arr.size(); j++) {
JSONObject options_0_Obj = options_0_Arr.getJSONObject(j);
String sizeNo = options_0_Obj.getString("epoSizeCode");
String size = options_0_Obj.getString("epoSizeName") + options_0_Obj.getString("sizeDescription");
ProductProp productPropSize = new ProductProp();
productPropSize.setPropId(sizeNo);
productPropSize.setPropName(size);
sizePropSet.add(productPropSize);
if (productPropSet.get("尺码") == null) {
productPropSet.put("尺码", sizePropSet);
} else {
Set<ProductProp> oldPropSet = productPropSet.get("尺码");
sizePropSet.addAll(oldPropSet);
productPropSet.put("尺码", sizePropSet);
}
///////////////////////// 获取商品尺码属性 END/////////////////////////////////////////////////////
// 设置 skuStr
String skuStr = ";" + colorNo + ";" + sizeNo + ";";
//////////////////////////////////// 获取库存 ////////////////////////////////////////////
// 设置:商品包含库存信息
if (productSkuStockList == null) {
productSkuStockList = new ArrayList<>();
}
ProductSkuStock productSkuStock = new ProductSkuStock();
productSkuStock.setSkuStr(skuStr);
productSkuStock.setSellableQuantity(999);
productSkuStockList.add(productSkuStock);
dynStock.setProductSkuStockList(productSkuStockList);
//////////////////////////////////// 获取库存 END/////////////////////////////////////////
//////////////////////////////////// 获取原始价 //////////////////////////////////
String fullPrice = productDataObj.getJSONObject("price").getString("value");
fullPrice = exchangeRate(fullPrice);
OriginalPrice originalPrice = new OriginalPrice();
originalPrice.setSkuStr(skuStr);
originalPrice.setPrice(fullPrice);
originalPriceList.add(originalPrice);
productResponse.setPrice(fullPrice);
productResponse.setSalePrice(fullPrice + "-" + fullPrice);
//////////////////////////////////// 获取原始价 END//////////////////////////////////
}
}
productResponse.setProductPropSet(productPropSet);
productResponse.setPlatform("MO&Co.");
productResponse.setPromotionList(promotionList);
productResponse.setOriginalPriceList(originalPriceList);
productResponse.setItemInfo(itemInfo);
productResponse.setDynStock(dynStock);
return productResponse;
}
}
package com.example.afrishop_v3.bis.impl;
import com.example.afrishop_v3.util.*;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.URISyntaxException;
/**
* 网络接口调用
*
* @author G
*/
public class NetWorkSpider {
/**
* 调用和讯网上的汇率接口 http://webforex.hermes.hexun.com/forex/quotelist?code=FOREXUSDX,
*
* FOREXUSDCNY,FOREXEURUSD,FOREXUSDJPY,FOREXGBPUSD,FOREXUSDCAD,FOREXUSDCHF,
* FOREXAUDUSD,FOREXGBPJPY,FOREXXAUUSD&column=Price,Code,Name,UpdownRate,PriceWeight'
*/
private static final String exchangeRateUrl = "http://webforex.hermes.hexun.com/forex/quotelist?";
/**
* 从和讯网获取汇率
* @param code 暂支持单个币种传入,后续可以增加
* @return
*/
public static BigDecimal getRateFromHexun(String code) throws IOException, URISyntaxException {
String apiUrl=exchangeRateUrl+"code="+code+"&column=Price,Code,Name,UpdownRate,PriceWeight";
String dataUrl=HttpClientUtil.getContentByUrl(apiUrl,"");
int firstBrackets=dataUrl.indexOf("(");
int lastBrackets=dataUrl.lastIndexOf(")");
String jsonStr=dataUrl.substring(firstBrackets+1,lastBrackets);
JsonObject rateJson = new JsonParser().parse(jsonStr).getAsJsonObject();
JsonArray dataArray0= rateJson.getAsJsonArray("Data");
JsonArray dataArray1= (JsonArray) dataArray0.get(0);
JsonArray dataArray2= (JsonArray) dataArray1.get(0);
int price=dataArray2.get(0).getAsInt();
int priceWeight=dataArray2.get(4).getAsInt();
BigDecimal priceDecimal = BigDecimal.valueOf(price);
BigDecimal weightDecimal = BigDecimal.valueOf(priceWeight);
return priceDecimal.divide(weightDecimal);
}
}
package com.example.afrishop_v3.bis.impl;
import com.example.afrishop_v3.bis.IItemSpider;
import com.example.afrishop_v3.bo.KeyConstant;
import com.example.afrishop_v3.enums.PlatformEnum;
import com.example.afrishop_v3.util.HttpClientUtil;
import com.example.afrishop_v3.util.JsoupUtil;
import com.example.afrishop_v3.util.TranslateHelper;
import com.example.afrishop_v3.vo.*;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import static com.example.afrishop_v3.util.SpiderUtil.exchangeRate;
/**
* nike数据爬虫
*
* @author G
*/
@Component("nikeItemSpider")
public class NikeItemSpider implements IItemSpider {
private static Logger logger = LoggerFactory.getLogger(NikeItemSpider.class);
@Override
public JSONObject captureItem(String targetUrl) throws URISyntaxException, IOException, InterruptedException, ExecutionException, TimeoutException {
JSONObject resultObj;
//获取url中的网页内容 >
String content = HttpClientUtil.getContentByUrl(targetUrl, PlatformEnum.NIKE.getValue());
//获取商品相关信息,详情放在<script> 标签的 window.INITIAL_REDUX_STATE 变量中
resultObj = JsoupUtil.getItemDetailByName(content, "window.INITIAL_REDUX_STATE");
//格式化为封装数据
ProductResponse productResponse = formatNikeProductResponse(resultObj);
resultObj = JSONObject.fromObject(productResponse);
//翻译
TranslateHelper.translateProductResponse(resultObj);
return resultObj;
}
/**
* 格式化 nike 返回数据
*
* @param dataMap
* @return
*/
private ProductResponse formatNikeProductResponse(JSONObject dataMap) {
ProductResponse productResponse = new ProductResponse();
//nike 基本是 颜色、尺码属性
Map<String, Set<ProductProp>> productPropSet = new HashMap<>(16);
//原始价
List<OriginalPrice> originalPriceList = new ArrayList<>();
//促销价格
List<ProductPromotion> promotionList = new ArrayList<>();
//库存
DynStock dynStock = new DynStock();
//其实数据没有包含确切的库存数,这里默认给足量的库存
dynStock.setSellableQuantity(9999);
//商品基本信息
ItemInfo itemInfo = new ItemInfo();
JSONObject threadObj = dataMap.getJSONObject("Threads");
JSONObject productsObj = threadObj.getJSONObject("products");
Set es = productsObj.entrySet();
Iterator it = es.iterator();
while (it.hasNext()) {
Map.Entry<String, JSONObject> entry = (Map.Entry) it.next();
String skuStr = ";";
String modelCode = entry.getKey();
skuStr = skuStr + modelCode + ";";
JSONObject itemDetail = entry.getValue();
////////////////////////////////////获取价格和商品属性////////////////////////////////////////////
String fullPrice = itemDetail.getString("fullPrice");
//转换汇率
fullPrice = exchangeRate(fullPrice);
String currentPrice = itemDetail.getString("currentPrice");
//转换汇率
currentPrice = exchangeRate(currentPrice);
productResponse.setPrice(fullPrice);
JSONArray skusArr = itemDetail.getJSONArray("skus");
//获取商品尺码属性,同时记录下skuid和尺码关系
Map<String, String> sizeSkuIdMapping = new HashMap<>(16);
for (int i = 0; i < skusArr.size(); i++) {
String skuId = skusArr.getJSONObject(i).getString("skuId");
/////////////////////////获取商品尺码属性////////////////////
//商品属性
Set<ProductProp> sizePropSet = new HashSet<>();
ProductProp productProp = new ProductProp();
String localizedSize = skusArr.getJSONObject(i).getString("localizedSize");
String localizedSizePrefix = skusArr.getJSONObject(i).getString("localizedSizePrefix");
//因为尺码一样的时候skuid却不一样,这里只能赋予一个propid,否则后面去重不了
String customizeId = KeyConstant.CUSTOMIZE_ID + localizedSize + localizedSizePrefix;
sizeSkuIdMapping.put(skuId, customizeId);
productProp.setPropId(customizeId);
productProp.setPropName(localizedSizePrefix + " " + localizedSize);
sizePropSet.add(productProp);
if (productPropSet.get("尺码") == null) {
productPropSet.put("尺码", sizePropSet);
} else {
Set<ProductProp> oldPropSet = productPropSet.get("尺码");
sizePropSet.addAll(oldPropSet);
productPropSet.put("尺码", sizePropSet);
}
/////////////////////////获取商品尺码属性 END////////////////////
}
////////////////////////////////////获取价格//////////////////////////////////
for (int i = 0; i < skusArr.size(); i++) {
String skuId = skusArr.getJSONObject(i).getString("skuId");
String customizeId = sizeSkuIdMapping.get(skuId);
OriginalPrice originalPrice = new OriginalPrice();
originalPrice.setSkuStr(skuStr + customizeId + ";");
originalPrice.setPrice(fullPrice);
originalPriceList.add(originalPrice);
if (itemDetail.getBoolean("discounted")) {
productResponse.setPromotionFlag(true);
productResponse.setSalePrice(currentPrice);
ProductPromotion productPromotion = new ProductPromotion();
productPromotion.setSkuStr(skuStr + customizeId + ";");
productPromotion.setPrice(fullPrice);
promotionList.add(productPromotion);
}
}
////////////////////////////////////获取价格 END//////////////////////////////////
/////////////////////////////////////获取价格和商品属性 END////////////////////////////////////////////
////////////////////////////////////获取库存 ////////////////////////////////////////////
productResponse.setStockFlag(true);
List<ProductSkuStock> productSkuStockList = dynStock.getProductSkuStockList();
if (productSkuStockList == null) {
productSkuStockList = new ArrayList<>();
}
JSONArray availableSkusArr = itemDetail.getJSONArray("availableSkus");
for (int i = 0; i < availableSkusArr.size(); i++) {
String skuId = availableSkusArr.getJSONObject(i).getString("skuId");
String customizeId = sizeSkuIdMapping.get(skuId);
ProductSkuStock productSkuStock = new ProductSkuStock();
productSkuStock.setSellableQuantity(999);
productSkuStock.setSkuStr(skuStr + customizeId + ";");
productSkuStockList.add(productSkuStock);
}
dynStock.setProductSkuStockList(productSkuStockList);
////////////////////////////////////获取库存 END////////////////////////////////////////////
////////////////////////////////////获取商品颜色属性////////////////////////////////////////////
//商品属性
Set<ProductProp> propSet = new HashSet<>();
ProductProp productProp = new ProductProp();
String colorDescription = itemDetail.getString("colorDescription");
String firstImageUrl = itemDetail.getString("firstImageUrl");
productProp.setPropId(modelCode);
productProp.setPropName(colorDescription);
productProp.setImage(firstImageUrl);
propSet.add(productProp);
if (productPropSet.get("颜色") == null) {
productPropSet.put("颜色", propSet);
} else {
Set<ProductProp> oldPropSet = productPropSet.get("颜色");
propSet.addAll(oldPropSet);
productPropSet.put("颜色", propSet);
}
////////////////////////////////////获取商品属性 END////////////////////////////////////////////
}
JSONObject globalObj = dataMap.getJSONObject("global");
JSONObject metaTagsObj = globalObj.getJSONObject("metaTags");
JSONArray metaArr = metaTagsObj.getJSONArray("meta");
for (int i = 0; i < metaArr.size(); i++) {
if (metaArr.getJSONObject(i).get("property") != null) {
String propertyValue = metaArr.getJSONObject(i).getString("property");
if ("og:title".equalsIgnoreCase(propertyValue)) {
itemInfo.setTitle(metaArr.getJSONObject(i).getString("content"));
}
if ("og:image".equalsIgnoreCase(propertyValue)) {
itemInfo.setPic(metaArr.getJSONObject(i).getString("content"));
}
}
}
itemInfo.setShopUrl("https://www.nike.com/cn/");
itemInfo.setShopName(PlatformEnum.NIKE.getLabel());
productResponse.setPropFlag(true);
productResponse.setProductPropSet(productPropSet);
productResponse.setPlatform(PlatformEnum.NIKE.getValue());
productResponse.setPromotionList(promotionList);
productResponse.setOriginalPriceList(originalPriceList);
productResponse.setItemInfo(itemInfo);
productResponse.setDynStock(dynStock);
return productResponse;
}
}
package com.example.afrishop_v3.bis.impl;
import com.example.afrishop_v3.bis.IItemSpider;
import com.example.afrishop_v3.enums.PlatformEnum;
import com.example.afrishop_v3.vo.*;
import com.example.afrishop_v3.util.*;
import net.sf.json.JSONObject;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
/**
* OchirlySpider 数据爬虫
* TODO 存在"暂时无货"的判断
* @author 爱酱油不爱醋
*/
@Component("ochirlySpider")
public class OchirlySpider implements IItemSpider {
private static Logger logger = LoggerFactory.getLogger(ZaraSpider.class);
/**
* 爬虫数据返回
* @param targetUrl 接收的商品详情路径
* @return 格式化与翻译后的 Json 数据
* @see
*/
@Override
public JSONObject captureItem(String targetUrl) throws URISyntaxException, IOException, ExecutionException, InterruptedException, TimeoutException {
String content = HttpClientUtil.getContentByUrl(targetUrl, PlatformEnum.UNDERARMOUR.getValue());
ProductResponse productResponse = formatProductResponse(content);
JSONObject resultObj = JSONObject.fromObject(productResponse);
TranslateHelper.translateProductResponse(resultObj);
return resultObj;
}
/**
* 格式化返回数据
* @param content 主要的页面数据
* @return 格式化后的数据
*/
private ProductResponse formatProductResponse(String content) {
// 声明封装类
ProductResponse productResponse = new ProductResponse();
// 含有商品的属性,设置为true
productResponse.setPropFlag(true);
// 库存信息,如果没有可使用的库存信息则默认为999
DynStock dynStock = new DynStock();
dynStock.setSellableQuantity(9999);
List<ProductSkuStock> productSkuStockList = dynStock.getProductSkuStockList();
// 产品的原始价与优惠价
List<OriginalPrice> originalPriceList = new ArrayList<>();
List<ProductPromotion> promotionList = new ArrayList<>();
// 商品的属性,常用的商品属性为颜色与尺码
Map<String, Set<ProductProp>> productPropSet = new HashMap<>(16);
Set<ProductProp> propSet = new HashSet<>(16);
Set<ProductProp> sizePropSet = new HashSet<>(16);
productResponse.setStockFlag(true);
// 商品的基本属性
ItemInfo itemInfo = new ItemInfo();
Document document = Jsoup.parse(content);
// 获取标题
Elements detailEle = document.select("div[class=detail]").select("div[class=desc]");
String pTitle = detailEle.select("h5").text();
// 获取价格
Elements priceEle = detailEle.select("p[class=price]");
String fullPrice = priceEle.attr("data-list-price");
// 获取颜色id与图片
Elements colorEle = document.select("div[class=color]").select("ul[class=clearfix]");
List<String> imgUrlList = colorEle.select("a").eachAttr("href");
List<String> pColorNoList = new ArrayList<>();
for (int i = 0; i < imgUrlList.size(); i++) {
String hrefStr = imgUrlList.get(i);
if (hrefStr.contains("/p/mobile/")) {
String[] spilt = hrefStr.split("/mobile/");
pColorNoList.add(spilt[1].replaceAll(".shtml", ""));
} else {
pColorNoList.add(0, priceEle.attr("data-sku"));
}
}
List<String> pColorList = new ArrayList<>();
pColorList.addAll(pColorNoList);
List<String> pImgList = colorEle.select("img").eachAttr("src");
// 获取尺码
Elements sizeEle = document.select("div[class=size]").select("div[class=size_contain]").select("li");
List<String> pSizeList = new ArrayList<>();
List<String> pSizeNoList = new ArrayList<>();
for (Element element : sizeEle) {
if (element.hasAttr("data-size-id")) {
pSizeList.add(element.text());
pSizeNoList.add(element.attr("data-size-id"));
}
}
//////////////////////////////////// 获取商品基本信息 ////////////////////////////
itemInfo.setShopName("Ochirly");
itemInfo.setShopUrl("www.ochirly.com");
itemInfo.setItemId(detailEle.select("p[class=price]").attr("data-sku"));
itemInfo.setTitle(pTitle);
itemInfo.setPic(pImgList.get(0));
//////////////////////////////////// 获取商品基本信息End /////////////////////////
//////////////////////////////////// 获取商品颜色属性 ////////////////////////////
for (int i = 0; i < pColorList.size(); i++) {
String colorNo = pColorList.get(i);
String color = pColorNoList.get(i);
String imgUrl = pImgList.get(i);
ProductProp productPropColor = new ProductProp();
productPropColor.setPropName(colorNo);
productPropColor.setPropId(color);
productPropColor.setImage(imgUrl);
propSet.add(productPropColor);
if (productPropSet.get("颜色") == null) {
productPropSet.put("颜色", propSet);
} else {
Set<ProductProp> oldPropSet = productPropSet.get("颜色");
propSet.addAll(oldPropSet);
productPropSet.put("颜色", propSet);
}
///////////////////////// 获取商品尺码属性 ////////////////////
for (int j = 0; j < pSizeList.size(); j++) {
String sizeNo = pSizeNoList.get(j);
String size = pSizeList.get(j);
ProductProp productPropSize = new ProductProp();
productPropSize.setPropId(sizeNo);
productPropSize.setPropName(size);
sizePropSet.add(productPropSize);
if (productPropSet.get("尺码") == null) {
productPropSet.put("尺码", sizePropSet);
} else {
Set<ProductProp> oldPropSet = productPropSet.get("尺码");
sizePropSet.addAll(oldPropSet);
productPropSet.put("尺码", sizePropSet);
}
///////////////////////// 获取商品尺码属性 END////////////////////
// 设置库存id
String skuStr = ";" + colorNo + ";" + sizeNo + ";";
if (productSkuStockList == null) {
productSkuStockList = new ArrayList<>();
}
ProductSkuStock productSkuStock = new ProductSkuStock();
productSkuStock.setSellableQuantity(999);
productSkuStock.setSkuStr(skuStr);
productSkuStockList.add(productSkuStock);
dynStock.setProductSkuStockList(productSkuStockList);
// TODO 转换汇率,目前商品单位是人民币
String originalFullPrice = SpiderUtil.exchangeRate(fullPrice);
OriginalPrice originalPrice = new OriginalPrice();
originalPrice.setSkuStr(skuStr);
originalPrice.setPrice(originalFullPrice);
originalPriceList.add(originalPrice);
productResponse.setPrice(originalFullPrice);
productResponse.setSalePrice(originalFullPrice + "-" + originalFullPrice);
}
}
//////////////////////////////////// 获取商品颜色属性 END ////////////////////////////////////////////
productResponse.setProductPropSet(productPropSet);
productResponse.setPlatform("Ochirly");
productResponse.setPromotionList(promotionList);
productResponse.setOriginalPriceList(originalPriceList);
productResponse.setItemInfo(itemInfo);
productResponse.setDynStock(dynStock);
return productResponse;
}
}
\ No newline at end of file
package com.example.afrishop_v3.bis.impl;
import com.example.afrishop_v3.bis.IItemSpider;
import com.example.afrishop_v3.enums.PlatformEnum;
import com.example.afrishop_v3.vo.*;
import com.example.afrishop_v3.util.*;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.URISyntaxException;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
/**
* Oysho 数据爬虫
* TODO 抓取不到商品详情页的链接
* @author 爱酱油不爱醋
*/
@Component("oyshoSpider")
public class OyshoSpider implements IItemSpider {
private static Logger logger = LoggerFactory.getLogger(EifiniSpider.class);
/**
* Oysho 数据爬虫
* @param targetUrl 接收的商品详情路径
* @return 格式化与翻译后的 Json 数据
*/
@Override
public JSONObject captureItem(String targetUrl) throws InterruptedException, IOException, ExecutionException, URISyntaxException, TimeoutException {
String[] spilt = targetUrl.split("origenId=");
String pId = spilt[1];
targetUrl = "https://www.oysho.cn/itxrest/2/catalog/store/65009628/60361118/category/0/product/" + pId + "/detail";
String content = HttpClientUtil.getContentByUrl(targetUrl, PlatformEnum.OYSHO.getValue());
ProductResponse productResponse = formatProductResponse(content, pId);
JSONObject resultObj = JSONObject.fromObject(productResponse);
TranslateHelper.translateProductResponse(resultObj);
return resultObj;
}
/**
* 格式化返回数据
*
* @param content 主要的页面数据
* @param pId 截取链接中的商品 id
* @return 格式化后的数据
*/
private ProductResponse formatProductResponse(String content, String pId) {
// 声明封装类
ProductResponse productResponse = new ProductResponse();
// 含有商品的属性,设置为true
productResponse.setPropFlag(true);
// 库存信息,如果没有可使用的库存信息则默认为999
DynStock dynStock = new DynStock();
dynStock.setSellableQuantity(9999);
List<ProductSkuStock> productSkuStockList = dynStock.getProductSkuStockList();
// 产品的原始价与优惠价
List<OriginalPrice> originalPriceList = new ArrayList<>();
List<ProductPromotion> promotionList = new ArrayList<>();
// 商品的属性,常用的商品属性为颜色与尺码
Map<String, Set<ProductProp>> productPropSet = new HashMap<>(16);
Set<ProductProp> propSet = new HashSet<>(16);
Set<ProductProp> sizePropSet = new HashSet<>(16);
productResponse.setStockFlag(true);
// 商品的基本属性
ItemInfo itemInfo = new ItemInfo();
JSONObject dataMap = JSONObject.fromObject(content);
//////////////////////////////////// 获取商品基本信息 ////////////////////////////
itemInfo.setItemId(pId);
itemInfo.setShopName("Oysho");
itemInfo.setShopUrl("https://www.oysho.cn/");
itemInfo.setTitle(dataMap.getString("name"));
//////////////////////////////////// 获取商品基本信息End /////////////////////////
// color 数组节点在接口传递的 json 中会存在不同的情况
JSONArray colorArr;
if (dataMap.getJSONArray("bundleProductSummaries").size() != 0) {
colorArr = dataMap.getJSONArray("bundleProductSummaries").getJSONObject(0).getJSONObject("detail").getJSONArray("colors");
} else {
colorArr = dataMap.getJSONObject("detail").getJSONArray("colors");
}
//////////////////////////////////// 获取商品颜色属性 ////////////////////////////
for (int i = 0; i < colorArr.size(); i++) {
JSONObject colorObj = colorArr.getJSONObject(i);
String colorNo = colorObj.getString("id");
String color = colorObj.getString("name");
// 处理图片路径
JSONObject imageObj = colorObj.getJSONObject("image");
String imgUrl = "https://static.oysho.cn/6/photos2"
+ imageObj.getString("url") + ".jpg?t=" + imageObj.getString("timestamp");
if (i == 0) {
itemInfo.setPic(imgUrl);
}
ProductProp productPropColor = new ProductProp();
productPropColor.setPropId(colorNo);
productPropColor.setPropName(color);
productPropColor.setImage(imgUrl);
propSet.add(productPropColor);
if (productPropSet.get("颜色") == null) {
productPropSet.put("颜色", propSet);
} else {
Set<ProductProp> oldPropSet = productPropSet.get("颜色");
propSet.addAll(oldPropSet);
productPropSet.put("颜色", propSet);
}
//////////////////////////////////// 获取商品颜色属性 END ////////////////////////////////////////
///////////////////////// 获取商品尺码属性 ///////////////////////////////////////////////////////
JSONArray sizesArr = colorObj.getJSONArray("sizes");
for (int j = 0; j < sizesArr.size(); j++) {
JSONObject sizesObj = sizesArr.getJSONObject(j);
String sizeNo = sizesObj.getString("sku");
String size = sizesObj.getString("name");
ProductProp productPropSize = new ProductProp();
productPropSize.setPropId(sizeNo);
productPropSize.setPropName(size);
sizePropSet.add(productPropSize);
if (productPropSet.get("尺码") == null) {
productPropSet.put("尺码", sizePropSet);
} else {
Set<ProductProp> oldPropSet = productPropSet.get("尺码");
sizePropSet.addAll(oldPropSet);
productPropSet.put("尺码", sizePropSet);
}
///////////////////////// 获取商品尺码属性 END///////////////////////////////////////////////////
//////////////////////////////////// 获取库存与原始价 ////////////////////////////////////////////
String skuStr = ";" + colorNo + ";" + sizeNo + ";";
String fullPrice = sizesObj.getString("price");
BigDecimal priceOld = new BigDecimal(fullPrice);
BigDecimal div = new BigDecimal("100");
fullPrice = priceOld.divide(div, 2, BigDecimal.ROUND_DOWN).toString();
String originalFullPrice = SpiderUtil.exchangeRate(fullPrice);
if (productSkuStockList == null) {
productSkuStockList = new ArrayList<>();
}
ProductSkuStock productSkuStock = new ProductSkuStock();
productSkuStock.setSkuStr(skuStr);
productSkuStock.setSellableQuantity(999);
productSkuStockList.add(productSkuStock);
dynStock.setProductSkuStockList(productSkuStockList);
OriginalPrice originalPrice = new OriginalPrice();
originalPrice.setSkuStr(skuStr);
originalPrice.setPrice(originalFullPrice);
originalPriceList.add(originalPrice);
productResponse.setPrice(originalFullPrice);
productResponse.setSalePrice(originalFullPrice + "-" + originalFullPrice);
//////////////////////////////////// 获取库存与原始价 END///////////////////////////////
}
}
productResponse.setProductPropSet(productPropSet);
productResponse.setPlatform("Oysho");
productResponse.setPromotionList(promotionList);
productResponse.setOriginalPriceList(originalPriceList);
productResponse.setItemInfo(itemInfo);
productResponse.setDynStock(dynStock);
return productResponse;
}
}
package com.example.afrishop_v3.bis.impl;
import com.example.afrishop_v3.bis.IItemSpider;
import com.example.afrishop_v3.enums.PlatformEnum;
import com.example.afrishop_v3.vo.*;
import com.example.afrishop_v3.util.*;
import net.sf.json.JSONObject;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
/**
* Prada(普拉达) 数据爬虫
*
* @author 爱酱油不爱醋
*/
@Component("pradaSpider")
public class PradaSpider implements IItemSpider {
private static Logger logger = LoggerFactory.getLogger(ZaraSpider.class);
/**
* Prada(普拉达) 数据爬虫
* @param targetUrl 接收的商品详情路径
* @return 格式化与翻译后的 Json 数据
*/
@Override
public JSONObject captureItem(String targetUrl) throws URISyntaxException, IOException, ExecutionException, InterruptedException, TimeoutException {
String content = HttpClientUtil.getContentByUrl(targetUrl, PlatformEnum.PRADA.getValue());
ProductResponse productResponse = formatProductResponse(content);
JSONObject resultObj = JSONObject.fromObject(productResponse);
TranslateHelper.translateProductResponse(resultObj);
return resultObj;
}
/**
* 格式化返回数据
*
* TODO 存在无法爬取数据的问题
*
* @param content 主要的页面数据
* @return 格式化后的数据
*/
private ProductResponse formatProductResponse(String content) {
// 声明封装类
ProductResponse productResponse = new ProductResponse();
// 含有商品的属性,设置为true
productResponse.setPropFlag(true);
// 库存信息,如果没有可使用的库存信息则默认为999
DynStock dynStock = new DynStock();
dynStock.setSellableQuantity(9999);
List<ProductSkuStock> productSkuStockList = dynStock.getProductSkuStockList();
// 产品的原始价与优惠价
List<OriginalPrice> originalPriceList = new ArrayList<>();
List<ProductPromotion> promotionList = new ArrayList<>();
// 商品的属性,常用的商品属性为颜色与尺码
Map<String, Set<ProductProp>> productPropSet = new HashMap<>(16);
Set<ProductProp> propSet = new HashSet<>(16);
Set<ProductProp> sizePropSet = new HashSet<>(16);
productResponse.setStockFlag(true);
// 商品的基本属性
ItemInfo itemInfo = new ItemInfo();
// 解析为 Document 对象
Document document = Jsoup.parse(content);
Elements pdpNameEle = document.select("div[class=col-xs-12 col-sm-12 pdp-name]");
// 获取价格
String fullPrice = pdpNameEle.select("p[class=pdp-price]").text();
fullPrice = SpiderUtil.retainNumber(fullPrice);
fullPrice = SpiderUtil.exchangeRate(fullPrice);
//////////////////////////////////// 获取商品基本信息 //////////////////////////////////////////////////
itemInfo.setShopName("Prada");
itemInfo.setShopUrl("https://www.prada.com/");
itemInfo.setItemId(pdpNameEle.select("div[class=pdp-sku]").text());
itemInfo.setTitle(pdpNameEle.select("h1").text());
//////////////////////////////////// 获取商品基本信息End ///////////////////////////////////////////////
//////////////////////////////////// 获取商品颜色属性 //////////////////////////////////////////////////
Elements colorEle = document.select("div[class=stiky-style-images]").select("a");
Elements sizeEle = document.select("div[class=product-size]").select("ul").select("li");
itemInfo.setPic(colorEle.select("img[class=img-style selected]").attr("src"));
for (Element colorElement : colorEle) {
String colorNo = colorElement.attr("data-part-number");
String imgUrl = colorElement.select("img").attr("src");
ProductProp productPropColor = new ProductProp();
productPropColor.setPropName(colorNo);
productPropColor.setPropId(colorNo);
productPropColor.setImage(imgUrl);
propSet.add(productPropColor);
if (productPropSet.get("颜色") == null) {
productPropSet.put("颜色", propSet);
} else {
Set<ProductProp> oldPropSet = productPropSet.get("颜色");
propSet.addAll(oldPropSet);
productPropSet.put("颜色", propSet);
}
//////////////////////////////////// 获取商品颜色属性 END ////////////////////////////////////////////
for (Element sizeElement : sizeEle) {
String sizeNo = sizeElement.select("input").attr("data-unique-id");
ProductProp productPropSize = new ProductProp();
productPropSize.setPropId(sizeNo);
productPropSize.setPropName(sizeElement.select("p[class=number]").text());
sizePropSet.add(productPropSize);
if (productPropSet.get("尺码") == null) {
productPropSet.put("尺码", sizePropSet);
} else {
Set<ProductProp> oldPropSet = productPropSet.get("尺码");
sizePropSet.addAll(oldPropSet);
productPropSet.put("尺码", sizePropSet);
}
//////////////////////////////////// 获取库存与原始价 ////////////////////////////////////////////
// 设置库存id
String skuStr = ";" + colorNo + ";" + sizeNo + ";";
// 设置:商品包含库存信息
ProductSkuStock productSkuStock = new ProductSkuStock();
OriginalPrice originalPrice = new OriginalPrice();
if (productSkuStockList == null) {
productSkuStockList = new ArrayList<>();
}
productSkuStock.setSellableQuantity(999);
productSkuStock.setSkuStr(skuStr);
productSkuStockList.add(productSkuStock);
dynStock.setProductSkuStockList(productSkuStockList);
// TODO 转换汇率,目前商品单位是人民币
String originalFullPrice = fullPrice;
originalPrice.setPrice(originalFullPrice);
productResponse.setPrice(originalFullPrice);
productResponse.setSalePrice(originalFullPrice + "-" + originalFullPrice);
originalPrice.setSkuStr(skuStr);
originalPriceList.add(originalPrice);
//////////////////////////////////// 获取库存与原始价 END///////////////////////////////
}
}
productResponse.setProductPropSet(productPropSet);
productResponse.setPlatform("Prada");
productResponse.setPromotionList(promotionList);
productResponse.setOriginalPriceList(originalPriceList);
productResponse.setItemInfo(itemInfo);
productResponse.setDynStock(dynStock);
return productResponse;
}
}
package com.example.afrishop_v3.bis.impl;
import com.example.afrishop_v3.bis.IItemSpider;
import com.example.afrishop_v3.enums.PlatformEnum;
import com.example.afrishop_v3.vo.*;
import com.example.afrishop_v3.util.*;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.URISyntaxException;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
/**
* 西班牙年轻时尚品牌-PullAndBear 数据爬虫
*
* @author 爱酱油不爱醋
*/
@Component("pullandbearSpider")
public class PullandbearSpider implements IItemSpider {
private static Logger logger = LoggerFactory.getLogger(PullandbearSpider.class);
/**
* PullAndBear 数据爬虫
* @param targetUrl 接收的商品详情路径
* @return 格式化与翻译后的 Json 数据
*/
@Override
public JSONObject captureItem(String targetUrl) throws URISyntaxException, IOException, ExecutionException, InterruptedException, TimeoutException {
String pId = targetUrl.substring(targetUrl.lastIndexOf("p")+1, targetUrl.lastIndexOf(".html"));
targetUrl = "https://www.pullandbear.cn/itxrest/2/catalog/store/24009528/20309423/category/0/product/" + pId + "/detail?languageId=-7&appId=1";
String content = HttpClientUtil.getContentByUrl(targetUrl, PlatformEnum.PULLANDBEAR.getValue());
JSONObject resultJson = JSONObject.fromObject(content);
ProductResponse productResponse = formatProductResponse(resultJson, pId);
resultJson = JSONObject.fromObject(productResponse);
TranslateHelper.translateProductResponse(resultJson);
return resultJson;
}
/**
* 格式化 PullAndBear 返回数据
* @see com.diaoyun.zion.chinafrica.bis.impl.PullandbearSpider
* @param dataMap 主要的 json 数据
* @param pId 商品链接的 id
* @return 格式化后的数据
*/
private ProductResponse formatProductResponse(JSONObject dataMap, String pId) {
// 声明封装类
ProductResponse productResponse = new ProductResponse();
// 含有商品的属性,设置为true
productResponse.setPropFlag(true);
// 库存信息,如果没有可使用的库存信息则默认为999
DynStock dynStock = new DynStock();
dynStock.setSellableQuantity(9999);
List<ProductSkuStock> productSkuStockList = dynStock.getProductSkuStockList();
// 产品的原始价与优惠价
List<OriginalPrice> originalPriceList = new ArrayList<>();
List<ProductPromotion> promotionList = new ArrayList<>();
// 商品的属性,常用的商品属性为颜色与尺码
Map<String, Set<ProductProp>> productPropSet = new HashMap<>(16);
Set<ProductProp> propSetColor = new HashSet<>(16);
Set<ProductProp> sizePropSetSize = new HashSet<>(16);
productResponse.setStockFlag(false);
// 商品的基本属性
ItemInfo itemInfo = new ItemInfo();
// 取 bundleProductSummaries 的节点对象
JSONObject bundleProductSummariesObj = dataMap.getJSONArray("bundleProductSummaries").getJSONObject(0);
//////////////////////////////////// 获取商品基本信息 ////////////////////////////////////////////
itemInfo.setShopName("PullAndBear");
itemInfo.setShopUrl("https://www.pullandbear.cn/");
itemInfo.setItemId(pId);
itemInfo.setTitle(bundleProductSummariesObj.getString("name"));
//////////////////////////////////// 获取商品基本信息End(图片下取) ////////////////////////////////////////////
// 取 colors 数组节点
JSONArray colorsArr = bundleProductSummariesObj.getJSONObject("detail").getJSONArray("colors");
productResponse.setStockFlag(true);
for (int i = 0; i < colorsArr.size(); i++) {
JSONObject colorsObj = colorsArr.getJSONObject(i);
//////////////////////////////////// 获取商品颜色与图片属性 ////////////////////////////////////////////
JSONObject imageObj = colorsObj.getJSONObject("image");
String colorNo = colorsObj.getString("id");
String color = colorsObj.getString("name");
String imageUrl = "https://static.pullandbear.cn/2/photos/"
+ imageObj.getString("url")
+ "_2_1_8.jpg?t="
+ imageObj.getString("timestamp");
if (i == 0) {
itemInfo.setPic(imageUrl);
}
ProductProp productPropColor = new ProductProp();
productPropColor.setPropId(colorNo);
productPropColor.setPropName(color);
productPropColor.setImage(imageUrl);
propSetColor.add(productPropColor);
if (productPropSet.get("颜色") == null) {
productPropSet.put("颜色", propSetColor);
} else {
Set<ProductProp> oldPropSet = productPropSet.get("颜色");
propSetColor.addAll(oldPropSet);
productPropSet.put("颜色", propSetColor);
}
//////////////////////////////////// 获取商品颜色与图片属性 END ////////////////////////////////////////////
// 取 siezes 对象数组
JSONArray sizesArr = colorsObj.getJSONArray("sizes");
for (int j = 0; j < sizesArr.size(); j++) {
JSONObject sizesObj = sizesArr.getJSONObject(j);
///////////////////////// 获取商品尺码属性 ////////////////////
// String sizeNo = sizesObj.getString("sku");
String size = sizesObj.getString("name");
ProductProp productPropSize = new ProductProp();
productPropSize.setPropName(size);
productPropSize.setPropId(size);
sizePropSetSize.add(productPropSize);
if (productPropSet.get("尺码") == null) {
productPropSet.put("尺码", sizePropSetSize);
} else {
Set<ProductProp> oldPropSet = productPropSet.get("尺码");
sizePropSetSize.addAll(oldPropSet);
productPropSet.put("尺码", sizePropSetSize);
}
///////////////////////// 获取商品尺码属性 END////////////////////
// 商品的库存id
String skuStr = ";" + colorNo + ";" + size + ";";
//////////////////////////////////// 获取库存 ////////////////////////////////////////////
if (productSkuStockList == null) {
productSkuStockList = new ArrayList<>();
}
ProductSkuStock productSkuStock = new ProductSkuStock();
productSkuStock.setSkuStr(skuStr);
productSkuStock.setSellableQuantity(999);
productSkuStockList.add(productSkuStock);
//////////////////////////////////// 获取库存 END/////////////////////////////////////////
//////////////////////////////////// 获取原始价 //////////////////////////////////
// 获取商品的原始价
String fullPrice = sizesObj.getString("price");
BigDecimal priceOld = new BigDecimal(fullPrice);
BigDecimal div = new BigDecimal("100");
BigDecimal priceNew = priceOld.divide(div, 2, BigDecimal.ROUND_DOWN);
// TODO 转换汇率,目前商品单位是人民币
fullPrice = SpiderUtil.exchangeRate(priceNew.toString());
OriginalPrice originalPrice = new OriginalPrice();
originalPrice.setSkuStr(skuStr);
originalPrice.setPrice(fullPrice);
originalPriceList.add(originalPrice);
dynStock.setProductSkuStockList(productSkuStockList);
productResponse.setPrice(fullPrice);
productResponse.setSalePrice(fullPrice + "-" + fullPrice);
//////////////////////////////////// 获取原始价 END//////////////////////////////////
}
}
productResponse.setPropFlag(true);
productResponse.setProductPropSet(productPropSet);
productResponse.setPlatform("PullAndBear");
productResponse.setPromotionList(promotionList);
productResponse.setOriginalPriceList(originalPriceList);
productResponse.setItemInfo(itemInfo);
productResponse.setDynStock(dynStock);
return productResponse;
}
}
package com.example.afrishop_v3.bis.impl;
import com.example.afrishop_v3.bis.IItemSpider;
import com.example.afrishop_v3.enums.PlatformEnum;
import com.example.afrishop_v3.vo.*;
import com.example.afrishop_v3.util.*;
import net.sf.json.JSONObject;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
/**
* Revolve 数据爬虫
* TODO 许多商品获取不到数据,待优化
* @author 爱酱油不爱醋
*/
@Component("revolveSpider")
public class RevolveSpider implements IItemSpider {
private static Logger logger = LoggerFactory.getLogger(PullandbearSpider.class);
/**
* Revolve 数据爬虫
* @param targetUrl 接收的商品详情路径
* @return 格式化与翻译后的 Json 数据
*/
@Override
public JSONObject captureItem(String targetUrl) throws URISyntaxException, IOException, ExecutionException, InterruptedException, TimeoutException {
String content = HttpClientUtil.getContentByUrl(targetUrl, PlatformEnum.APPLE.getValue());
ProductResponse productResponse = formatProductResponse(content);
JSONObject resultObj = JSONObject.fromObject(productResponse);
TranslateHelper.translateProductResponse(resultObj);
return resultObj;
}
/**
* 格式化返回数据
* @param content 主要的网页内容
* @return 格式化后的数据
*/
private ProductResponse formatProductResponse(String content) {
// 声明封装类
ProductResponse productResponse = new ProductResponse();
// 含有商品的属性,设置为true
productResponse.setPropFlag(true);
// 库存信息,如果没有可使用的库存信息则默认为999
DynStock dynStock = new DynStock();
dynStock.setSellableQuantity(9999);
List<ProductSkuStock> productSkuStockList = dynStock.getProductSkuStockList();
// 产品的原始价与优惠价
List<OriginalPrice> originalPriceList = new ArrayList<>();
List<ProductPromotion> promotionList = new ArrayList<>();
// 商品的属性,常用的商品属性为颜色与尺码
Map<String, Set<ProductProp>> productPropSet = new HashMap<>(16);
Set<ProductProp> propSet = new HashSet<>(16);
Set<ProductProp> sizePropSet = new HashSet<>(16);
productResponse.setStockFlag(true);
// 商品的基本属性
ItemInfo itemInfo = new ItemInfo();
// 转换为 Document 对象
Document document = Jsoup.parse(content);
//////////////////////////////////// 获取商品基本信息 //////////////////////////////////////////////////
itemInfo.setItemId(document.select("input[id=productCode]").attr("value"));
itemInfo.setShopName("Revolve");
itemInfo.setShopUrl("http://www.revolve.com");
itemInfo.setTitle(document.select("meta[property=og:title]").attr("content"));
//////////////////////////////////// 获取商品基本信息End ///////////////////////////////////////////////
Elements colorsEle = document.select("fieldset[aria-labelledby=color-sr-text]")
.select("ul[id=product-swatches]").select("li");
Elements sizesEle = document.select("div[class=product-sizes product-sections]")
.select("ul[id=size-ul]").select("li").select("input");
String fullPrice = document.select("meta[property=wanelo:product:price]").attr("content");
// 判断货币类型
if (!"USD".equals(document.select("meta[property=wanelo:product:price:currency]").attr("content"))) {
fullPrice = SpiderUtil.exchangeRate(fullPrice);
}
for (Element colorEle : colorsEle) {
String colorNo = colorEle.attr("data-swatch-code");
String color = colorEle.select("img").attr("alt");
String imgUrl = colorEle.select("img").attr("src");
ProductProp productPropColor = new ProductProp();
productPropColor.setPropId(colorNo);
productPropColor.setPropName(color);
productPropColor.setImage(imgUrl);
propSet.add(productPropColor);
if (productPropSet.get("颜色") == null) {
productPropSet.put("颜色", propSet);
} else {
Set<ProductProp> oldPropSet = productPropSet.get("颜色");
propSet.addAll(oldPropSet);
productPropSet.put("颜色", propSet);
}
for (Element sizeEle : sizesEle) {
String sizeNo = sizeEle.attr("value");
String size = sizeEle.attr("data-size");
ProductProp productPropSize = new ProductProp();
productPropSize.setPropId(sizeNo);
productPropSize.setPropName(size);
sizePropSet.add(productPropSize);
if (productPropSet.get("尺码") == null) {
productPropSet.put("尺码", sizePropSet);
} else {
Set<ProductProp> oldPropSet = productPropSet.get("尺码");
sizePropSet.addAll(oldPropSet);
productPropSet.put("尺码", sizePropSet);
}
///////////////////////// 获取商品尺码属性 END////////////////////
// 商品的库存id
String skuStr = ";" + colorNo + ";" + sizeNo + ";";
//////////////////////////////////// 获取库存 ////////////////////////////////////////////
// 设置:商品包含库存信息
if (productSkuStockList == null) {
productSkuStockList = new ArrayList<>();
}
// 获取库存数
int sellableQuantity = Integer.valueOf(sizeEle.attr("data-qty"));
ProductSkuStock productSkuStock = new ProductSkuStock();
productSkuStock.setSkuStr(skuStr);
productSkuStock.setSellableQuantity(sellableQuantity);
productSkuStockList.add(productSkuStock);
dynStock.setProductSkuStockList(productSkuStockList);
//////////////////////////////////// 获取库存 END///////////////////////////////////
//////////////////////////////////// 获取原始价 //////////////////////////////////
OriginalPrice originalPrice = new OriginalPrice();
// TODO 转换汇率,目前商品单位是人民币
originalPrice.setSkuStr(skuStr);
originalPrice.setPrice(fullPrice);
originalPriceList.add(originalPrice);
productResponse.setPrice(fullPrice);
productResponse.setSalePrice(fullPrice + "-" + fullPrice);
//////////////////////////////////// 获取原始价 END//////////////////////////////////
}
}
productResponse.setProductPropSet(productPropSet);
productResponse.setPlatform("Revolve");
productResponse.setPromotionList(promotionList);
productResponse.setOriginalPriceList(originalPriceList);
productResponse.setItemInfo(itemInfo);
productResponse.setDynStock(dynStock);
return productResponse;
}
}
package com.example.afrishop_v3.bis.impl;
import com.example.afrishop_v3.bis.IItemSpider;
import com.example.afrishop_v3.enums.PlatformEnum;
import com.example.afrishop_v3.vo.*;
import com.example.afrishop_v3.util.*;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.URISyntaxException;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import static com.example.afrishop_v3.util.SpiderUtil.exchangeRate;
/**
* Stradivarius 数据爬虫
*
* @author 爱酱油不爱醋
*/
@Component("stradivariusSpider")
public class StradivariusSpider implements IItemSpider {
/**
* Stradivarius 数据爬虫
* @param targetUrl 接收的商品详情路径
* @return 格式化与翻译后的 Json 数据
*/
@Override
public JSONObject captureItem(String targetUrl) throws URISyntaxException, IOException, ExecutionException, InterruptedException, TimeoutException {
String[] spilt = targetUrl.split("p");
spilt = spilt[2].split(".html");
String pId = spilt[0];
targetUrl = "https://www.stradivarius.cn/itxrest/2/catalog/store/55009578/50331061/category/0/product/" + pId + "/detail";
String content = HttpClientUtil.getContentByUrl(targetUrl, PlatformEnum.STRADIVARIUS.getValue());
JSONObject resultObj = JSONObject.fromObject(content);
ProductResponse productResponse = formatProductResponse(resultObj, pId);
resultObj = JSONObject.fromObject(productResponse);
TranslateHelper.translateProductResponse(resultObj);
return resultObj;
}
/**
* 格式化返回数据
* @param dataMap 主要的 Json 数据
* @param pId 商品 id
* @return 格式化后的数据
*/
private ProductResponse formatProductResponse(JSONObject dataMap, String pId) {
// 声明封装类
ProductResponse productResponse = new ProductResponse();
// 含有商品的属性,设置为true
productResponse.setPropFlag(true);
// 库存信息,如果没有可使用的库存信息则默认为999
DynStock dynStock = new DynStock();
dynStock.setSellableQuantity(9999);
List<ProductSkuStock> productSkuStockList = dynStock.getProductSkuStockList();
// 产品的原始价与优惠价
List<OriginalPrice> originalPriceList = new ArrayList<>();
List<ProductPromotion> promotionList = new ArrayList<>();
// 商品的属性,常用的商品属性为颜色与尺码
Map<String, Set<ProductProp>> productPropSet = new HashMap<>(16);
Set<ProductProp> propSet = new HashSet<>(16);
Set<ProductProp> sizePropSet = new HashSet<>(16);
productResponse.setStockFlag(true);
// 商品的基本属性
ItemInfo itemInfo = new ItemInfo();
// 取 detail 节点对象
JSONObject detailObj = dataMap.getJSONObject("detail");
//////////////////////////////////// 获取商品基本信息 ////////////////////////////
itemInfo.setItemId(pId);
itemInfo.setShopName("Stradivarius");
itemInfo.setShopUrl("https://www.stradivarius.cn/");
itemInfo.setTitle(detailObj.getString("description"));
//////////////////////////////////// 获取商品基本信息End /////////////////////////
//////////////////////////////////// 获取商品颜色属性 ////////////////////////////
// 取 colors 节点数组
JSONArray colorsArr = detailObj.getJSONArray("colors");
for (int i = 0; i < colorsArr.size(); i++) {
JSONObject colorsObj = colorsArr.getJSONObject(i);
String colorNo = colorsObj.getString("id");
String color = colorsObj.getString("name");
String imgUrl = "https://static.stradivarius.cn/5/photos3"
+ colorsObj.getJSONObject("image").getString("url")
+"_6_1_4.jpg?t="
+ colorsObj.getJSONObject("image").getString("timestamp");
if (i == 0) {
itemInfo.setPic(imgUrl);
}
ProductProp productPropColor = new ProductProp();
productPropColor.setPropId(colorNo);
productPropColor.setPropName(color);
productPropColor.setImage(imgUrl);
propSet.add(productPropColor);
if (productPropSet.get("颜色") == null) {
productPropSet.put("颜色", propSet);
} else {
Set<ProductProp> oldPropSet = productPropSet.get("颜色");
propSet.addAll(oldPropSet);
productPropSet.put("颜色", propSet);
}
//////////////////////////////////// 获取商品颜色属性 END ////////////////////////////////////////
///////////////////////// 获取商品尺码属性 ///////////////////////////////////////////////////////
// 取每个 colors 的 sizes 对象数组
JSONArray sizesArr = colorsObj.getJSONArray("sizes");
for (int j = 0; j < sizesArr.size(); j++) {
JSONObject sizesObj = sizesArr.getJSONObject(j);
String sizeNo = sizesObj.getString("sku");
String size = sizesObj.getString("name");
ProductProp productPropSize = new ProductProp();
productPropSize.setPropId(sizeNo);
productPropSize.setPropName(size);
sizePropSet.add(productPropSize);
if (productPropSet.get("尺码") == null) {
productPropSet.put("尺码", sizePropSet);
} else {
Set<ProductProp> oldPropSet = productPropSet.get("尺码");
sizePropSet.addAll(oldPropSet);
productPropSet.put("尺码", sizePropSet);
}
///////////////////////// 获取商品尺码属性 END///////////////////////////////////////////////////
//////////////////////////////////// 获取库存与原始价 ////////////////////////////////////////////
// 设置库存id
String skuStr = ";" + colorNo + ";" + sizeNo + ";";
if (productSkuStockList == null) {
productSkuStockList = new ArrayList<>();
}
ProductSkuStock productSkuStock = new ProductSkuStock();
productSkuStock.setSkuStr(skuStr);
productSkuStock.setSellableQuantity(999);
productSkuStockList.add(productSkuStock);
dynStock.setProductSkuStockList(productSkuStockList);
// 获取商品的原始价
String fullPrice = sizesObj.getString("price");
BigDecimal priceOld = new BigDecimal(fullPrice);
BigDecimal div = new BigDecimal("100");
fullPrice = priceOld.divide(div, 2, BigDecimal.ROUND_DOWN).toString();
// TODO 转换汇率,目前商品单位是人民币
String originalFullPrice = exchangeRate(fullPrice);
OriginalPrice originalPrice = new OriginalPrice();
originalPrice.setPrice(originalFullPrice);
originalPrice.setSkuStr(skuStr);
originalPriceList.add(originalPrice);
productResponse.setPrice(originalFullPrice);
productResponse.setSalePrice(originalFullPrice + "-" + originalFullPrice);
//////////////////////////////////// 获取库存与原始价 END///////////////////////////////
}
}
productResponse.setProductPropSet(productPropSet);
productResponse.setPlatform("Stradivarius");
productResponse.setPromotionList(promotionList);
productResponse.setOriginalPriceList(originalPriceList);
productResponse.setItemInfo(itemInfo);
productResponse.setDynStock(dynStock);
return productResponse;
}
}
package com.example.afrishop_v3.bis.impl;
import com.stripe.Stripe;
import com.stripe.exception.StripeException;
import com.stripe.model.Charge;
import java.util.HashMap;
import java.util.Map;
/**
* stripe支付相关方法
*/
public class StripePay {
/**
* 发起支付,默认使用美元支付
* @param amount 货币的最小单位,比如美元,传入1000,就是1000美分,10美元
* @param sk
* @param token
* @return
*/
public static Charge createCharge(Integer amount, String sk, String token) throws StripeException {
Stripe.apiKey = sk;
Map<String, Object> chargeParams = new HashMap<>(16);
chargeParams.put("amount", amount);
chargeParams.put("currency", "usd");
// 会出现在付款后页面
/** chargeParams.put("description", "Charge for jenny.rosen@example.com");*/
chargeParams.put("source",token);
return Charge.create(chargeParams);
}
}
package com.example.afrishop_v3.bis.impl;
import com.example.afrishop_v3.bis.IItemSpider;
import com.example.afrishop_v3.enums.PlatformEnum;
import com.example.afrishop_v3.util.HttpClientUtil;
import com.example.afrishop_v3.util.JsoupUtil;
import com.example.afrishop_v3.util.TranslateHelper;
import com.example.afrishop_v3.util.ValidateUtils;
import net.sf.json.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.text.StringEscapeUtils;
import org.apache.http.message.BasicHeader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
/**
* 淘宝网数据爬虫
*/
@Component("tbItemSpider")
public class TbItemSpider implements IItemSpider {
private static Logger logger = LoggerFactory.getLogger(TbItemSpider.class);
/**
* 淘宝商品详情页链接
*/
private static final String taobaoUrl="https://item.taobao.com/item.htm?";
@Override
public JSONObject captureItem(String targetUrl) throws URISyntaxException, IOException, ExecutionException, InterruptedException, TimeoutException {
//主要是判断淘宝的url是手机端还是PC端,如果是手机端,那么还需要提取相关参数,组成新的url;还有去除链接中一些会引起请求错误的参数
targetUrl=processUrl(targetUrl);
List<Map<String, Object>> futureList= new ArrayList<>();
//获取url中的网页内容
String content = HttpClientUtil.getContentByUrl(targetUrl,PlatformEnum.TB.getValue());
//获取商品相关信息,比如详情url
Map<String,String> infoMap= JsoupUtil.getTbItemDetail(content);
String usableSibUrl="https:"+infoMap.get("sibUrl");
//解析商品sku信息
Map<String,Object> propMap=JsoupUtil.getPropMap(content);
if(propMap.get("hasSku")==null||(boolean)propMap.get("hasSku")) {
//调用腾讯ai,翻译规格
translateProp(futureList,propMap);
}
/* ****************获取商品详情******************* */
//删除需要登录的模块
usableSibUrl=deleteLoginModule(usableSibUrl);
//需要加入头部
BasicHeader basicHeader=new BasicHeader("referer", targetUrl);
String sibContent = HttpClientUtil.getContentByUrl(usableSibUrl,basicHeader);
//unicode 解码
sibContent= StringEscapeUtils.unescapeJava(sibContent);
//logger.info(sibMap.toString());
//从请求结果中获取Cookie,此时的Cookie已经带有登录信息了
//CookieStore store = httpClientContext.getCookieStore();
/*Long c=System.currentTimeMillis();
logger.info("获取详情时间(毫秒):"+(c-b));*/
//等待翻译结果
TranslateHelper.waitForResult(futureList);
//关闭线程池 不能关闭,否则下次调用不了
//taskLimitSemaphore.shutdown();
/* Long d=System.currentTimeMillis();
logger.info("翻译时间(毫秒):"+(d-c));
logger.info("爬取数据总共耗费时间(毫秒):"+(d-a));*/
JSONObject returnJson= JSONObject.fromObject(sibContent);
returnJson.put("Jprop",propMap);
returnJson.put("itemProp",infoMap);
returnJson.put("platform", PlatformEnum.TB.getValue());
return returnJson;
}
/**
* 翻译规格属性
* @param propMap 规格属性MAP
* @throws ExecutionException
* @throws InterruptedException
*/
private void translateProp(List<Map<String, Object>> futureList,Map<String, Object> propMap) {
/*腾讯翻译*/
for(Map.Entry<String,Object>entry : propMap.entrySet()) {
String key=entry.getKey();
Map <String,Object> value= (Map<String, Object>) entry.getValue();
//翻译属性名
if(ValidateUtils.isContainChinese(key)) {
TranslateHelper.translateText(futureList,value,key);
}
//翻译sku title
if(value!=null&&value.size()>0) {
translateTitle(futureList,value);
}
}
}
/**
* 翻译规格说明
* @param skuMap
* @throws ExecutionException
* @throws InterruptedException
*/
private void translateTitle(List<Map<String, Object>> futureList,Map<String, Object> skuMap) {
for(Map.Entry<String,Object>entry : skuMap.entrySet()) {
String key=entry.getKey();
if(entry.getValue() instanceof Map) {
Map<String, Object> value = (Map<String, Object>) entry.getValue();
String title = (String) value.get("title");
if (StringUtils.isNotBlank(title)) {
//翻译属性名
if (ValidateUtils.isContainChinese(title)) {
TranslateHelper.translateText(futureList,value,title);
//value.put("translate", translate);
}
}
}
}
}
/**
* 去除需要登录或者不需要返回的参数
* @param usableSibUrl
* @return
*/
private String deleteLoginModule(String usableSibUrl) {
usableSibUrl=usableSibUrl.replaceAll("couponActivity,","");
usableSibUrl=usableSibUrl.replaceAll("soldQuantity,","");
usableSibUrl=usableSibUrl.replaceAll("tradeContract,","");
usableSibUrl=usableSibUrl.replaceAll("upp,","");
// TODO 运费格式有问题,暂去除
usableSibUrl=usableSibUrl.replaceAll("deliveryFee,","");
usableSibUrl=usableSibUrl.replaceAll("delivery,","");
return usableSibUrl;
}
/**
* 主要是提取相关参数,组成新的url
*
* @param targetUrl
* @return
*/
private String processUrl(String targetUrl) throws URISyntaxException, MalformedURLException {
String newUrl=taobaoUrl;
//if(targetUrl.contains("h5.m.taobao.com")) {
Map<String,String> paramMap=HttpClientUtil.getParamMap(targetUrl);
//目前淘宝需要四个参数 spm id scm pvid
//引起错误的 参数 ali_refid
StringBuffer paramBuffer=new StringBuffer();
for(Map.Entry<String,String> entry:paramMap.entrySet()) {
if("ali_refid".equals(entry.getKey())||"track_params".equals(entry.getKey())||"utparam".equals(entry.getKey())
||"rmdChannelCode".equals(entry.getKey())||"locate".equals(entry.getKey())) {
} else {
paramBuffer.append(entry.getKey()+"="+entry.getValue()+"&");
}
}
return newUrl+paramBuffer.toString();
}
}
package com.example.afrishop_v3.bis.impl;
import com.example.afrishop_v3.bis.IItemSpider;
import com.example.afrishop_v3.enums.PlatformEnum;
import com.example.afrishop_v3.util.HttpClientUtil;
import com.example.afrishop_v3.util.JsoupUtil;
import com.example.afrishop_v3.util.TranslateHelper;
import com.example.afrishop_v3.util.ValidateUtils;
import net.sf.json.JSONArray;
import net.sf.json.JSONNull;
import net.sf.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
/**
* 天猫数据爬虫
*
* @author G
*/
@Component("tmItemSpider")
public class TmItemSpider implements IItemSpider {
private static Logger logger = LoggerFactory.getLogger(TmItemSpider.class);
/**
* 天猫商品详情页链接
*/
private static final String tmallUrl="https://detail.m.tmall.com/item.htm?";
@Override
public JSONObject captureItem(String targetUrl) throws URISyntaxException, IOException, ExecutionException, InterruptedException, TimeoutException {
//主要获取id参数,组成新链接
//targetUrl=processUrl(targetUrl);
List<Map<String, Object>> futureList= new ArrayList<>();
//获取url中的网页内容
String content = HttpClientUtil.getContentByUrl(targetUrl,PlatformEnum.TM.getValue());
//获取商品详情 观察数据可发现商品数据在 _DATA_Detail 变量中
JSONObject infoMap= JsoupUtil.getItemDetailByName(content,"_DATA_Detail");
JSONObject skuBaseMap= (JSONObject) infoMap.get("skuBase");
if(!(skuBaseMap.get("props") instanceof JSONNull)) {
JSONArray propsArray= (JSONArray) skuBaseMap.get("props");
for(int i=0;i<propsArray.size();i++) {
JSONObject propMap=propsArray.getJSONObject(i);
String propName= (String) propMap.get("name");
JSONArray valueArray=propMap.getJSONArray("values");
//翻译属性名
if(ValidateUtils.isContainChinese(propName)) {
TranslateHelper.translateText(futureList,propMap,propName);
}
//翻译sku title
if(valueArray!=null&&valueArray.size()>0) {
for(int j=0;j<valueArray.size();j++) {
JSONObject valueMap=valueArray.getJSONObject(j);
if(valueMap!=null&&valueMap.size()>0) {
String skuName= (String) valueMap.get("name");
//翻译属性名
if(ValidateUtils.isContainChinese(skuName)) {
TranslateHelper.translateText(futureList,valueMap,skuName);
}
}
}
}
}
}
//等待翻译结果
TranslateHelper.waitForResult(futureList);
//只取其中部分信息 TODO 后续可以继续封装
JSONObject returnJson=new JSONObject();
returnJson.put("seller",infoMap.get("seller"));
returnJson.put("item",infoMap.get("item"));
returnJson.put("mock",infoMap.get("mock"));
returnJson.put("skuBase",infoMap.get("skuBase"));
returnJson.put("platform", PlatformEnum.TM.getValue());
return returnJson;
}
}
package com.example.afrishop_v3.bo;
/**
* 获取商品详情封装参数
*/
public class DetailParamVo {
//目标url
private String targetUrl;
public String getTargetUrl() {
return targetUrl;
}
public void setTargetUrl(String targetUrl) {
this.targetUrl = targetUrl;
}
}
......@@ -36,6 +36,12 @@ public class TbCfHomePageEntityController {
return new Result<>(all);
}
@GetMapping("/store")
public Result getStores( @RequestParam(required = false,defaultValue = "1") Integer pageNum, @RequestParam(defaultValue = "10",required = false) Integer pageSize) {
return new Result<>(storeRepository.findAll(PageRequest.of(pageNum,pageSize)));
}
@GetMapping("/home/middleColumn")
public Result getMiddleColumn( @RequestParam(value = "limit", defaultValue = "4") Integer limit){
Result result = new Result<>();
......
......@@ -58,7 +58,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
http.cors().and().csrf().disable()
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests().antMatchers("/api/auth/**","/itemStation/**","/startPage/**","/home/**").permitAll()
.authorizeRequests().antMatchers("/api/auth/**","/itemStation/**","/startPage/**","/home/**","/spider/**","/store/**").permitAll()
.antMatchers("/api/test/**").permitAll()
.anyRequest().authenticated();
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论