提交 e768cea5 authored 作者: 梁业锦's avatar 梁业锦 💬

添加了基于本项目的爬虫文档;已完成Zara与优衣库的爬虫格式化;优衣库存在缺陷,

暂且不可用
上级 d2f65e7c
...@@ -8,6 +8,11 @@ ...@@ -8,6 +8,11 @@
* 自定义的一些配置,比如邮箱、stripe账号、腾讯ai相关的配置等等 * 自定义的一些配置,比如邮箱、stripe账号、腾讯ai相关的配置等等
3. logback-spring.xml 3. logback-spring.xml
* 日志配置文件 * 日志配置文件
# 爬虫规范及文档
[爬虫文档链接](../doc/SpiderSpecification.md)
# 项目层次结构 # 项目层次结构
项目大致分为两个包和相关的资源文件,两个包分别是com.diaoyun.zion.master和com.diaoyun.zion.chinafrica。 项目大致分为两个包和相关的资源文件,两个包分别是com.diaoyun.zion.master和com.diaoyun.zion.chinafrica。
1. master这个包下面放的是项目通用的类,比如项目模块配置类、异常处理、spring security相关的东西。 1. master这个包下面放的是项目通用的类,比如项目模块配置类、异常处理、spring security相关的东西。
......
差异被折叠。
...@@ -21,7 +21,6 @@ public class NikeItemSpider implements IItemSpider { ...@@ -21,7 +21,6 @@ public class NikeItemSpider implements IItemSpider {
private static Logger logger = LoggerFactory.getLogger(NikeItemSpider.class); private static Logger logger = LoggerFactory.getLogger(NikeItemSpider.class);
@Override @Override
public JSONObject captureItem(String targetUrl) throws URISyntaxException, IOException, InterruptedException, ExecutionException, TimeoutException { public JSONObject captureItem(String targetUrl) throws URISyntaxException, IOException, InterruptedException, ExecutionException, TimeoutException {
JSONObject resultObj; JSONObject resultObj;
......
...@@ -17,8 +17,6 @@ import java.util.concurrent.TimeoutException; ...@@ -17,8 +17,6 @@ import java.util.concurrent.TimeoutException;
/** /**
* 西班牙年轻时尚品牌-pullandbear 数据爬虫 * 西班牙年轻时尚品牌-pullandbear 数据爬虫
* *
* TODO 图片路径未处理
* 图片路径为:
*/ */
@Component("pullandbearSpider") @Component("pullandbearSpider")
public class PullandbearSpider implements IItemSpider { public class PullandbearSpider implements IItemSpider {
......
...@@ -2,7 +2,10 @@ package com.diaoyun.zion.chinafrica.bis.impl; ...@@ -2,7 +2,10 @@ package com.diaoyun.zion.chinafrica.bis.impl;
import com.diaoyun.zion.chinafrica.bis.IItemSpider; import com.diaoyun.zion.chinafrica.bis.IItemSpider;
import com.diaoyun.zion.chinafrica.enums.PlatformEnum; import com.diaoyun.zion.chinafrica.enums.PlatformEnum;
import com.diaoyun.zion.chinafrica.vo.ProductResponse;
import com.diaoyun.zion.master.util.HttpClientUtil; import com.diaoyun.zion.master.util.HttpClientUtil;
import com.diaoyun.zion.master.util.SpiderUtil;
import com.diaoyun.zion.master.util.TranslateHelper;
import net.sf.json.JSONArray; import net.sf.json.JSONArray;
import net.sf.json.JSONObject; import net.sf.json.JSONObject;
import org.slf4j.Logger; import org.slf4j.Logger;
...@@ -17,8 +20,9 @@ import java.util.concurrent.TimeoutException; ...@@ -17,8 +20,9 @@ import java.util.concurrent.TimeoutException;
/** /**
* 优衣库数据爬虫 * 优衣库数据爬虫
* *
* TODO 图片路径未处理 * 图片路径为:"https://www.uniqlo.cn/hmall/test/" + 商品id + "/sku/561/" + 商品图片id + ".jpg"
* 图片路径为:"https://www.uniqlo.cn/hmall/test/" + 商品id + "/sku/40/" + 商品图片id + ".jpg" *
* @author 爱酱油不爱醋
*/ */
@Component("uniqloSpider") @Component("uniqloSpider")
public class UniqloSpider implements IItemSpider { public class UniqloSpider implements IItemSpider {
...@@ -37,18 +41,13 @@ public class UniqloSpider implements IItemSpider { ...@@ -37,18 +41,13 @@ public class UniqloSpider implements IItemSpider {
// 获取网页内容 // 获取网页内容
String content = HttpClientUtil.getContentByUrl(targetUrl, PlatformEnum.UNIQLO.getValue()); String content = HttpClientUtil.getContentByUrl(targetUrl, PlatformEnum.UNIQLO.getValue());
// 转换为 json // 转换为 json
JSONObject json = JSONObject.fromObject(content); JSONObject resultJson = JSONObject.fromObject(content);
// 商品id // 按照封装规范封装商品数据
String pName = json.getJSONObject("summary").getString("name"); ProductResponse productResponse = SpiderUtil.formatUniqloProductResponse(resultJson, pId);
// 商品价格 resultJson = JSONObject.fromObject(productResponse);
String pPrice = json.getJSONObject("summary").getString("originPrice"); // 翻译
// 格式化数据 TranslateHelper.translateProductResponse(resultJson);
JSONArray rowsJson = json.getJSONArray("rows"); return resultJson;
JSONObject returnJson = new JSONObject();
returnJson.put("name", pName);
returnJson.put("price", pPrice);
returnJson.elementOpt("data", rowsJson);
return returnJson;
} }
} }
...@@ -22,7 +22,8 @@ import java.util.concurrent.TimeoutException; ...@@ -22,7 +22,8 @@ import java.util.concurrent.TimeoutException;
/** /**
* Zara西班牙时尚品牌数据爬虫 * Zara西班牙时尚品牌数据爬虫
* TODO 数据未处理完全 *
* @author 爱酱油不爱醋
*/ */
@Component("zaraSpider") @Component("zaraSpider")
public class ZaraSpider implements IItemSpider { public class ZaraSpider implements IItemSpider {
...@@ -37,76 +38,14 @@ public class ZaraSpider implements IItemSpider { ...@@ -37,76 +38,14 @@ public class ZaraSpider implements IItemSpider {
// 获取url中的网页内容 // 获取url中的网页内容
String content = HttpClientUtil.getContentByUrl(targetUrl, PlatformEnum.ZARA.getValue()); String content = HttpClientUtil.getContentByUrl(targetUrl, PlatformEnum.ZARA.getValue());
// 截取主要的 Json 内容 // 截取主要的 Json 内容
resultObj = JsoupUtil.getZara(content); resultObj = JsoupUtil.getZaraJsonData(content);
ProductResponse productResponse = SpiderUtil.formatNikeProductResponse(resultObj); // 按照封装规范封装商品数据
ProductResponse productResponse = SpiderUtil.formatZaraProductResponse(resultObj);
// 将封装数据转换为 json 数据
resultObj = JSONObject.fromObject(productResponse); resultObj = JSONObject.fromObject(productResponse);
//翻译 // 翻译
TranslateHelper.translateProductResponse(resultObj); TranslateHelper.translateProductResponse(resultObj);
return resultObj; return resultObj;
} }
/**
* 根据首位字符串内容进行截取
* @param jsonStr
* @param startStr 起始字符串
* @param lastStr 结尾字符串(不包含)
* @return
*/
private static String getDataJson(String jsonStr, String startStr, String lastStr) {
int startIndex = jsonStr.indexOf(startStr);
int lastIndex = jsonStr.lastIndexOf(lastStr);
return jsonStr.substring(startIndex, lastIndex);
}
public static void main(String[] args) throws IOException, URISyntaxException {
// URL链接
String targetUrl = "https://www.zara.cn/cn/zh/%E5%BA%9C%E7%BB%B8%E9%95%BF%E7%89%88%E8%A1%AC%E8%A1%AB-p08053157.html?v1=31979171&v2=1319321";
// 获取网页内容
String content = HttpClientUtil.getContentByUrl(targetUrl, PlatformEnum.ZARA.getValue());
// 截取主要的商品数据
int labelHeadIndex = content.indexOf("dataLayer");
int labelTailIndex = content.lastIndexOf(";window.zara.viewPayload");
String abv = content.substring(labelHeadIndex, labelTailIndex).replace("dataLayer = ", "");
System.err.println(abv);
// 转换为 Json 格式
JSONObject json = JSONObject.fromObject(abv);
// System.err.println(json);
// product 对象节点
JSONObject responseData = json.getJSONObject("product");
// System.err.println(responseData);
// detail 对象节点
JSONObject details = responseData.getJSONObject("detail");
// System.err.println(details);
// colors 数组节点
JSONArray colorsArray = details.getJSONArray("colors");
Map<Integer, JSONObject> colorMap = new HashMap<>();
for (int i = 0; i < colorsArray.size(); i++) {
colorMap.put(i, colorsArray.getJSONObject(i));
}
System.out.println(colorMap);
// TODO 取出颜色属性
// sizes 数组节点
Map<Integer, JSONObject> sizesMap = new HashMap<>();
for(Map.Entry<Integer, JSONObject> entry : colorMap.entrySet()){
// 遍历出每个 colors 对象节点
JSONObject colors = entry.getValue();
JSONArray sizesArray = colors.getJSONArray("sizes");
for (int i = 0; i < sizesArray.size(); i++) {
sizesMap.put(i, sizesArray.getJSONObject(i));
}
}
System.out.println(sizesMap);
// TODO 取出价格和尺码属性
// TODO 取出图片属性(图片实体类未知)
}
} }
...@@ -29,10 +29,12 @@ public enum PlatformEnum implements EnumItemable<PlatformEnum> { ...@@ -29,10 +29,12 @@ public enum PlatformEnum implements EnumItemable<PlatformEnum> {
this.value = value; this.value = value;
} }
@Override
public String getLabel() { public String getLabel() {
return this.label; return this.label;
} }
@Override
public String getValue() { public String getValue() {
return this.value; return this.value;
} }
......
...@@ -6,6 +6,7 @@ import java.util.List; ...@@ -6,6 +6,7 @@ import java.util.List;
* 库存 * 库存
*/ */
public class DynStock { public class DynStock {
//可用总的库存数 //可用总的库存数
private int sellableQuantity; private int sellableQuantity;
//sku对应的库存数 //sku对应的库存数
......
...@@ -47,11 +47,13 @@ public class ProductProp { ...@@ -47,11 +47,13 @@ public class ProductProp {
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if(obj==null) if (obj==null) {
return false; return false;
if(this==obj) }
if (this==obj) {
return true; return true;
if(obj instanceof ProductProp) { }
if (obj instanceof ProductProp) {
ProductProp productProp =(ProductProp) obj; ProductProp productProp =(ProductProp) obj;
if(productProp.propId.equals(this.propId)) { if(productProp.propId.equals(this.propId)) {
return true; return true;
......
...@@ -6,30 +6,54 @@ import java.util.Set; ...@@ -6,30 +6,54 @@ import java.util.Set;
/** /**
* 爬取数据后,返回页面的商品详情数据 * 爬取数据后,返回页面的商品详情数据
*
* @author G
*/ */
public class ProductResponse { public class ProductResponse {
//原始价格 有优惠的话还有优惠价 /**
* 原始价格 有优惠的话还有优惠价
*/
private List<OriginalPrice> originalPriceList; private List<OriginalPrice> originalPriceList;
//是否包促销价格 true 有促销价格,false\null没有促销价格 /**
* 是否包促销价格 true 有促销价格,false\null没有促销价格
*/
private boolean promotionFlag; private boolean promotionFlag;
//促销价格 /**
* 促销价格
*/
private List<ProductPromotion> promotionList; private List<ProductPromotion> promotionList;
//原价一口价,就是商品一开始展示的价格,比如多sku多价格的情况下展示 18.80-49.90 /**
* 原价一口价,就是商品一开始展示的价格,比如多sku多价格的情况下展示 18.80-49.90
*/
private String price; private String price;
//促销一口价 /**
* 促销一口价
*/
private String salePrice; private String salePrice;
//是否包含库存信息 有些商品没有库存信息,可以当作是有货 true 有库存信息,false没有 /**
* 是否包含库存信息 有些商品没有库存信息,可以当作是有货 true 有库存信息,false没有
*/
private boolean stockFlag; private boolean stockFlag;
//库存 /**
* 库存
*/
private DynStock dynStock; private DynStock dynStock;
//是否包含商品属性,有些商品没有属性 /**
* 是否包含商品属性,有些商品没有属性
*/
private boolean propFlag; private boolean propFlag;
//商品属性 颜色:红色,蓝色;尺码:S,l,M /**
* 商品属性 颜色:红色,蓝色;尺码:S,l,M
*/
private Map<String, Set<ProductProp>> productPropSet; private Map<String, Set<ProductProp>> productPropSet;
//商品信息 /**
* 商品信息
*/
private ItemInfo itemInfo; private ItemInfo itemInfo;
//商品来源平台 PlatformEnum /**
* 商品来源平台 PlatformEnum
*/
private String platform; private String platform;
......
package com.diaoyun.zion.master.util; package com.diaoyun.zion.master.util;
import com.diaoyun.zion.chinafrica.enums.PlatformEnum;
import net.sf.json.JSONObject; import net.sf.json.JSONObject;
import org.apache.commons.text.StringEscapeUtils; import org.apache.commons.text.StringEscapeUtils;
import org.jsoup.Jsoup; import org.jsoup.Jsoup;
...@@ -10,6 +11,8 @@ import org.jsoup.select.Elements; ...@@ -10,6 +11,8 @@ import org.jsoup.select.Elements;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
...@@ -18,8 +21,11 @@ import java.util.regex.Matcher; ...@@ -18,8 +21,11 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
public class JsoupUtil { public class JsoupUtil {
public static String unknow = "未知"; public static String unknow = "未知";
private static Logger logger = LoggerFactory.getLogger(JsoupUtil.class); private static Logger logger = LoggerFactory.getLogger(JsoupUtil.class);
/** /**
* 获取淘宝商品详情的信息 店铺id 名字 主图 sibUrl 等 * 获取淘宝商品详情的信息 店铺id 名字 主图 sibUrl 等
* *
...@@ -33,7 +39,8 @@ public class JsoupUtil { ...@@ -33,7 +39,8 @@ public class JsoupUtil {
String varArr[] = configGroup.split(";"); String varArr[] = configGroup.split(";");
for (String variable : varArr) { for (String variable : varArr) {
//获取g_config 变量 //获取g_config 变量
Pattern variablePattern = Pattern.compile("(g_config){1,1}\\s+={1,1}[\\s\\S]*"); // Regex for the value of the key // Regex for the value of the key
Pattern variablePattern = Pattern.compile("(g_config){1,1}\\s+={1,1}[\\s\\S]*");
Matcher varMatcher = variablePattern.matcher(variable); Matcher varMatcher = variablePattern.matcher(variable);
while (varMatcher.find()) { while (varMatcher.find()) {
String configStr = varMatcher.group(); String configStr = varMatcher.group();
...@@ -225,11 +232,11 @@ public class JsoupUtil { ...@@ -225,11 +232,11 @@ public class JsoupUtil {
} }
/** /**
* * 获取Zara爬虫的主要数据
* @param content * @param content
* @return * @return
*/ */
public static JSONObject getZara(String content) { public static JSONObject getZaraJsonData(String content) {
int labelHeadIndex = content.indexOf("dataLayer"); int labelHeadIndex = content.indexOf("dataLayer");
int labelTailIndex = content.lastIndexOf(";window.zara.viewPayload"); int labelTailIndex = content.lastIndexOf(";window.zara.viewPayload");
String abv = content.substring(labelHeadIndex, labelTailIndex).replace("dataLayer = ", ""); String abv = content.substring(labelHeadIndex, labelTailIndex).replace("dataLayer = ", "");
...@@ -237,7 +244,6 @@ public class JsoupUtil { ...@@ -237,7 +244,6 @@ public class JsoupUtil {
return dataMap; return dataMap;
} }
/** /**
* 根据script id获取内容 * 根据script id获取内容
* @param content * @param content
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论