重构评论

This commit is contained in:
Van0313
2025-05-02 20:39:46 +08:00
parent 5d89d84aa5
commit a9f247bf62
7 changed files with 169 additions and 357 deletions

View File

@@ -0,0 +1,50 @@
package cn.van.business.model.pl;
import jakarta.persistence.*;
import lombok.Data;
import java.time.LocalDateTime;
/**
* @author Leo
* @version 1.0
* @create 2025/6/4
* @description评论实体类
*/
@Entity
@Table(name = "comments")
@Data
public class Comment {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "product_id", nullable = false, columnDefinition = "TEXT")
private String productId;
@Column(name = "user_name", columnDefinition = "TEXT")
private String userName;
@Lob
@Column(name = "comment_text")
private String commentText;
@Column(name = "comment_id", length = 64, unique = true)
private String commentId;
@Column(name = "picture_urls", columnDefinition = "TEXT")
private String pictureUrls;
@Column(name = "created_at")
private LocalDateTime createdAt;
@Column(name = "comment_date")
private LocalDateTime commentDate;
@Column(name = "is_use")
private Integer isUse;
// Getters and Setters
}

View File

@@ -0,0 +1,20 @@
package cn.van.business.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import cn.van.business.model.pl.Comment;
import java.util.List;
/**
* @author Leo
* @version 1.0
* @create 2025/5/2 19:16
* @description评论数据访问层接口
*/
@Repository
public interface CommentRepository extends JpaRepository<Comment, Integer> {
List<Comment> findByProductIdAndIsUseNotAndPictureUrlsIsNotNull(String productId, Integer isUse);
}

View File

@@ -1,12 +1,17 @@
package cn.van.business.util;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.van.business.model.jd.OrderRow;
import cn.van.business.model.pl.Comment;
import cn.van.business.repository.CommentRepository;
import cn.van.business.repository.OrderRowRepository;
import cn.van.business.util.ds.DeepSeekClientUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jd.open.api.sdk.DefaultJdClient;
import com.jd.open.api.sdk.JdClient;
@@ -78,7 +83,8 @@ public class JDUtil {
private static final String ACCESS_TOKEN = "";
private static final Logger logger = LoggerFactory.getLogger(JDUtil.class);
private static final String INTERACTION_STATE_PREFIX = "interaction_state:";
private static final String COMMENT_TEMPLATES = "comment_templates:";
private static final String PRODUCT_TYPE_MAP_PREFIX = "product_type_map" ;
private static HashMap<String, String> productTypeMap = new HashMap<>();
private static final String COMMENT_TEMPLATES_DS = "我需要为我的商品模拟一些商品评论。你协助我生成3条评价内容京东商品评价的风格每条评价100字即可不需要太浮夸也不要太像ai生成尽量模拟真实客户评价不要提到以旧换新和国家补贴。我会为你提供其他真实用户的评论";
private static final long TIMEOUT_MINUTES = 2;
private static final String WENAN_FANAN_LQD = "提供方法自己下单\n" + "全程都是自己的账号下单\n" + "标价就是下单的到手价\n" + "本人有耐心,会一步一步提供教程\n" + "以后有什么质量问题都是用自己的账号走京东售后\n" + "\n" + "更新\n" + "\n" + "用你自己的账号下单\n" + "官方店铺 提供方法自己下单\n" + "——————————————————————————————————————————\n" + "同行可长久合作,可提供神级家电线报\n" + "\n" + "配合家电线报可以自己下单,不用找代购和代下,订单和利润都掌握在自己手中。\n" + "\n" + "一次入会永久使用,包含家电帮,雷神价,韭菜帮,河南&湖南帮,各种暗号帮后返等内部独家家电线报\n" + "\n" + "JD采销采购不定时发放独家优惠券\n" + "\n" + "基本上你能看到的京东家电低价都是从这些渠道里面出来。\n" + "\n" + "2025年家电项目新方向配合家电线报下单秒省1K+。";
@@ -105,6 +111,8 @@ public class JDUtil {
final WXUtil wxUtil;
private final StringRedisTemplate redisTemplate;
private final OrderRowRepository orderRowRepository;
private final CommentRepository commentRepository;
private final OrderUtil orderUtil;
private final DeepSeekClientUtil deepSeekClientUtil;
// 添加ObjectMapper来序列化和反序列化UserInteractionState
@@ -114,12 +122,14 @@ public class JDUtil {
// 构造函数中注入StringRedisTemplate
@Autowired
public JDUtil(StringRedisTemplate redisTemplate, OrderRowRepository orderRowRepository, WXUtil wxUtil, OrderUtil orderUtil, DeepSeekClientUtil deepSeekClientUtil) {
public JDUtil(StringRedisTemplate redisTemplate, OrderRowRepository orderRowRepository, WXUtil wxUtil, OrderUtil orderUtil, DeepSeekClientUtil deepSeekClientUtil, CommentRepository commentRepository) {
this.redisTemplate = redisTemplate;
this.orderRowRepository = orderRowRepository;
this.wxUtil = wxUtil;
this.orderUtil = orderUtil;
this.deepSeekClientUtil = deepSeekClientUtil;
this.commentRepository = commentRepository;
}
private List<OrderRow> filterOrdersByDate(List<OrderRow> orderRows, int daysBack) {
@@ -1577,7 +1587,7 @@ public class JDUtil {
return;
}
String remark = "";
if (!split[0].trim().replace("", "").isEmpty()){
if (!split[0].trim().replace("", "").isEmpty()) {
remark = split[0].trim().replace("{单}", "").replace("\n", "");
}
// 今天的日期
@@ -1612,10 +1622,8 @@ public class JDUtil {
for (int i = 0; i < num; i++) {
int currentCount = startCount + i;
String orderID = today + String.format("%03d", currentCount); // 格式化为三位数
// 每次使用原始模板进行替换,避免污染
String currentTemp = WENAN_D.replace("{单的备注}", remark).replace("{单号}", orderID).replace("{分销标记}", split[1]).replace("{链接}", split[3]).replace("{地址}", split[5]).replace("{型号}", split[2]).replaceAll("[|]", "");
// 发送订单信息到微信
wxUtil.sendTextMessage(fromWxid, currentTemp, 1, fromWxid, true);
}
@@ -1658,17 +1666,21 @@ public class JDUtil {
}
}
//getProductTypeMap 从redis中获取PRODUCT_TYPE_MAP_PREFIX
public void getProductTypeMap() {
String json = redisTemplate.opsForValue().get(PRODUCT_TYPE_MAP_PREFIX);
productTypeMap = JSON.parseObject(json, new TypeReference<Map<String, String>>() {
});
}
/**
* 处理生成评论流程中的用户交互
*/
private void handleCommentInteraction(String fromWxid, String message, UserInteractionState state) {
String superOrder = "";
try {
String[] split = message.replaceAll("\r", "").split("\n");
if (split.length != 0) {
message = split[0].trim().replace("\n", "");
for (int i = 1; i < split.length; i++) {
superOrder += split[i] + " ";
}
}
} catch (Exception e) {
@@ -1681,23 +1693,11 @@ public class JDUtil {
if (!"commentTypeSelection".equals(state.getCurrentField())) {
return;
}
// 根据用户输入生成对应的评论
switch (message) {
case "1":
generateComment(fromWxid, "1", superOrder);
break;
case "1+":
generateComment(fromWxid, "1+", superOrder.replace("+", ""));
break;
case "2":
generateComment(fromWxid, "2", superOrder);
break;
case "2+":
generateComment(fromWxid, "2+", superOrder.replace("+", ""));
break;
default:
wxUtil.sendTextMessage(fromWxid, "无效的选择,请回复 1 或 2", 1, fromWxid, false);
getProductTypeMap();
if (productTypeMap.containsKey(message)) {
generateComment(fromWxid, message);
} else {
wxUtil.sendTextMessage(fromWxid, "无效的选择,请回复 1 或 2", 1, fromWxid, false);
}
} catch (Exception e) {
@@ -1713,42 +1713,87 @@ public class JDUtil {
/**
* 生成评论内容
*/
private void generateComment(String fromWxid, String productType, String superOrder) {
if (productType.equals("1") || productType.equals("2")) {
wxUtil.sendTextMessage(fromWxid, "DS生成中等候过程请勿重复输入", 1, fromWxid, false);
// 这里可以调用缓存或AI生成文案目前先返回固定模板
//用redis的 list存放评论模板
List<String> commentTemplates = redisTemplate.opsForList().range(COMMENT_TEMPLATES + productType, 0, -1);
if (commentTemplates == null || commentTemplates.isEmpty()) {
wxUtil.sendTextMessage(fromWxid, "暂无评论模板,请先添加评论模板", 1, fromWxid, false);
private void generateComment(String fromWxid, String productType) {
wxUtil.sendTextMessage(fromWxid, "已接收到评论生成指令,等候过程请勿重复输入", 1, fromWxid, false);
// 获取产品ID
getProductTypeMap();
String product_id = productTypeMap.get(productType);
if (product_id == null || product_id.isEmpty()) {
wxUtil.sendTextMessage(fromWxid, "缺失对应的SKUID", 1, fromWxid, false);
return;
}
// 从数据库获取可用评论
List<Comment> availableComments = commentRepository.findByProductIdAndIsUseNotAndPictureUrlsIsNotNull(product_id, 1);
Comment commentToUse = null;
if (!availableComments.isEmpty()) {
// 随机选取一个未使用的评论
Collections.shuffle(availableComments);
commentToUse = availableComments.get(0);
} else {
// 没有本地评论,调用外部接口抓取
try {
String fetchUrl = "http://192.168.8.169:5000/fetch_comments?product_id=" + product_id;
// 用hutool发起post请求
HttpResponse response = HttpRequest.post(fetchUrl).execute();
logger.info("fetchUrl: {}", fetchUrl);
// code = 200 表示成功,-200 表示失败
if (response.getStatus() == 200) {
// ✅ 关键修改:重新从数据库中查询,而不是使用内存中的 fetchedComments
availableComments = commentRepository.findByProductIdAndIsUseNotAndPictureUrlsIsNotNull(product_id, 1);
if (!availableComments.isEmpty()) {
Collections.shuffle(availableComments);
commentToUse = availableComments.get(0);
}
} else if (response.getStatus() == -200) {
wxUtil.sendTextMessage(fromWxid, "暂时无法获取新的评论,请稍后再试", 1, fromWxid, false);
return;
}
} catch (Exception e) {
logger.error("调用外部接口获取评论失败", e);
wxUtil.sendTextMessage(fromWxid, "调用外部接口获取评论失败", 1, fromWxid, false);
return;
}
// 全部追加到成一个文本
StringBuilder comment = new StringBuilder();
int count = 0;
for (String commentTemplate : commentTemplates) {
count++;
comment.append(count).append(commentTemplate);
}
}
if (commentToUse == null) {
wxUtil.sendTextMessage(fromWxid, "没有找到可用的评论数据", 1, fromWxid, false);
return;
}
String deepSeekResponse = "ds响应失败";
try {
deepSeekResponse = deepSeekClientUtil.getDeepSeekResponse(COMMENT_TEMPLATES_DS + comment);
} catch (IOException e) {
logger.error("生成评论异常 - 用户: {}, ", fromWxid, e);
}
wxUtil.sendTextMessage(fromWxid, deepSeekResponse, 1, fromWxid, false);
// 重置状态
resetState(fromWxid, loadOrCreateState(INTERACTION_STATE_PREFIX + fromWxid));
} else {
if (!superOrder.isEmpty()) {
productType = productType.replace("+", "");
// 追加评论模板到redis
redisTemplate.opsForList().leftPush(COMMENT_TEMPLATES + productType, superOrder);
wxUtil.sendTextMessage(fromWxid, "评论模板添加成功", 1, fromWxid, false);
// 调用 DeepSeek 生成新的评论内容
String deepSeekPrompt = COMMENT_TEMPLATES_DS + commentToUse.getCommentText();
String deepSeekResponse;
try {
deepSeekResponse = deepSeekClientUtil.getDeepSeekResponse(deepSeekPrompt);
} catch (IOException e) {
logger.error("生成评论异常 - 用户: {}", fromWxid, e);
wxUtil.sendTextMessage(fromWxid, "评论生成失败,请重试", 1, fromWxid, false);
return;
}
// 发送生成的评论文本
wxUtil.sendTextMessage(fromWxid, deepSeekResponse, 1, fromWxid, false);
// 发送图片(如果有)
String pictureUrls = commentToUse.getPictureUrls();
if (pictureUrls != null && !pictureUrls.isEmpty()) {
String[] urls = pictureUrls.split(",");
for (String url : urls) {
wxUtil.sendImageMessage(fromWxid, url.trim()); // 假设 sendImageMessage 支持 URL
}
}
// 更新评论状态为已使用
commentToUse.setIsUse(1);
commentRepository.save(commentToUse);
// 重置状态
resetState(fromWxid, loadOrCreateState(INTERACTION_STATE_PREFIX + fromWxid));
}

View File

@@ -1,115 +0,0 @@
package cn.van.business.util.ds.pl;
/**
* @author Leo
* @version 1.0
* @create 2025/5/1 16:33
* @description
*/
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
public class FetchEquivalent {
private static final Logger logger = LoggerFactory.getLogger(FetchEquivalent.class);
public static void main(String[] args) {
String url = "https://api.m.jd.com/client.action";
// 关键参数,可根据需求动态调整
String appid = "pc-rate-qa";
String functionId = "getCommentListPage";
String spuId = "100104238904";
String sku = "100104238904";
int pageNum = 1;
int pageSize = 10;
String sortType = "5";
String h5st = "20250501163137742;gggwzzg93mhaqp39;01a47;tk03wd91c1d5f18nmJkCbdT3fAvSVSRvhgBegKk_JURNSt4iorNQ5bdUGcosuVPknJ2RSpEjzcPmpjpW5mMLWtm95dd2;67e4ba5594c53473cec3c2ac9d0f2bb45a27256c33aa0cf0c0fc53f5c3e61f5f;5.1;1746088294742;ri_uxFOm22ciAuLmOGLm9aHWMusmk_Mm1irS9poUBhbgHFHQ3R4VHlsm0msSIlsmOGuj6mrm0mMTLhImOuMsCmsVJZIi3ebV1O7WLdrg_uLi3Kbi3ebg1e7h9iIhLJbi8msm0msSo94VMZ4RMusmk_MmIVrV7O7WKNbWJl4h5WIh8abi2aYh7qIhJZog2arg7WLmOGLm7pIRAp4WMusmk_siOGLm6aHWMusmk_Mm72ciAaLRPZoTFV4X5OImOGLm4lsmOGujMqnZMtLibd4i9VLmOGLmBxoVApISMusmk_Mm8iLTFRJmOGLmItHmOuMsC6nmOG_iOGLm9qbRMlsmOusmk_si9uMgMubi5lImOusmOGuj26sm0mMi9aHWMusmOuMsCmsQf16XNhai9Zph7WacMuMgM64TK1YW8lsmOusmk_siOGLm2aHWMusmOuMsCurm0m8h5lImOusmOGuj5irm0mMh5lImOusmOGuj_uMgMabRMlsmOusmk_siOGLm6aHWMusmOuMsCibh8uMgMibRMlsmOusmk_Mm12ciAuLmOGLm9aHWMusmOuMsCurm0m8U3lsmOusmk_chOGLm79ImOusmOGuj_uMgM_ImOusmOGuj_uMgMe4RMusmOuMsztMgMeITJdnQJlsmOGujxtsmkmMi9abW6a4iIRri4mohPdIUMuMgMmrSMusmOuMsztMgMunSMusmk_Mm6WrQOCrh42YUXt8g_2si9usZgt8S3xoVAJ4ZMuMgMqYR7lsmOG_Q;ecdd8239ff33baed5b5b19f9167325c045d13be878c9c3812dd9bcbc630d6b84;tenjKJKT-JoRL1YRI9MT-J4S8ZIZ61YVF94WCeHTJJoTL9cQKxIWCeYU_tXW";
long t = System.currentTimeMillis();
String uuid = "1744804395425546198998";
// 参数校验
if (functionId == null || functionId.isEmpty() || appid == null || appid.isEmpty() || spuId == null || spuId.isEmpty() || sku == null || sku.isEmpty()) {
logger.error("关键参数不能为空");
return;
}
String body = String.format("appid=%s&body={\"requestSource\":\"pc\",\"shopComment\":0,\"sameComment\":0,\"channel\":null,\"extInfo\":{\"isQzc\":\"0\",\"spuId\":\"%s\",\"commentRate\":\"1\",\"needTopAlbum\":\"1\",\"bbtf\":\"\",\"userGroupComment\":\"1\"},\"num\":\"10\",\"pictureCommentType\":\"A\",\"scval\":null,\"shadowMainSku\":\"0\",\"shopType\":\"0\",\"firstCommentGuid\":\"e341be12da46b787bf5cd21a76ae3295\",\"sku\":\"%s\",\"category\":\"737;13297;1301\",\"shieldCurrentComment\":\"1\",\"pageSize\":\"%d\",\"isFirstRequest\":false,\"style\":\"0\",\"isCurrentSku\":false,\"sortType\":\"%s\",\"tagId\":\"\",\"tagType\":\"\",\"type\":\"4\",\"pageNum\":\"%d\"}&client=pc&clientVersion=1.0.0&functionId=%s&h5st=%s&loginType=3&t=%d&uuid=%s",
appid, spuId, sku, pageSize, sortType, pageNum, functionId, h5st, t, uuid);
Map<String, String> headers = new HashMap<>();
headers.put("accept", "application/json, text/plain, */*");
headers.put("accept-language", "zh-CN,zh;q=0.9,en;q=0.8");
headers.put("cache-control", "no-cache");
headers.put("content-type", "application/x-www-form-urlencoded");
headers.put("pragma", "no-cache");
headers.put("priority", "u=1, i");
headers.put("sec-ch-ua", "\"Chromium\";v=\"136\", \"Google Chrome\";v=\"136\", \"Not.A/Brand\";v=\"99\"");
headers.put("sec-ch-ua-mobile", "?0");
headers.put("sec-ch-ua-platform", "\"Windows\"");
headers.put("sec-fetch-dest", "empty");
headers.put("sec-fetch-mode", "cors");
headers.put("sec-fetch-site", "same-site");
headers.put("x-referer-page", "https://item.jd.com/100104238904.html");
headers.put("x-rp-client", "h5_1.0.0");
headers.put("referrer", "https://item.jd.com/");
headers.put("referrerPolicy", "strict-origin-when-cross-origin");
try {
URL obj = new URL(url);
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
// 设置请求方法
con.setRequestMethod("POST");
// 添加请求头
for (Map.Entry<String, String> entry : headers.entrySet()) {
con.setRequestProperty(entry.getKey(), entry.getValue());
}
// 允许输出流
con.setDoOutput(true);
// 写入请求体
try (DataOutputStream wr = new DataOutputStream(con.getOutputStream())) {
wr.writeBytes(body);
wr.flush();
}
int responseCode = con.getResponseCode();
logger.info("Response Code : " + responseCode);
if (responseCode == HttpURLConnection.HTTP_OK) {
try (BufferedReader in = new BufferedReader(
new InputStreamReader(con.getInputStream()))) {
String inputLine;
StringBuilder response = new StringBuilder();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
logger.info("Response Content : " + response.toString());
}
} else {
try (BufferedReader errorReader = new BufferedReader(
new InputStreamReader(con.getErrorStream()))) {
String errorLine;
StringBuilder errorResponse = new StringBuilder();
while ((errorLine = errorReader.readLine()) != null) {
errorResponse.append(errorLine);
}
logger.error("请求失败,响应码: " + responseCode + ",错误信息: " + errorResponse.toString());
}
}
} catch (IOException e) {
logger.error("请求过程中发生异常", e);
}
}
}

View File

@@ -1,78 +0,0 @@
package cn.van.business.util.ds.pl;
/**
* @author Leo
* @version 1.0
* @create 2025/4/30 19:16
* @description
*/
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
public class JDItemReviewCrawler {
private static final String API_URL = "https://api.jd.com/routerjson";
private static final String APP_KEY = "98e21c89ae5610240ec3f5f575f86a59";
private static final String APP_SECRET = "3dcb6b23a1104639ac433fd07adb6dfb";
public static void main(String[] args) throws IOException {
String itemId = "100075270739"; // 商品ID
String page = "1"; // 页码
String result = getItemReviews(itemId, page);
System.out.println(result);
}
public static String getItemReviews(String itemId, String page) throws IOException {
Map<String, String> params = new HashMap<>();
params.put("method", "jd.item.review.get");
params.put("app_key", APP_KEY);
params.put("v", "2.0");
params.put("format", "json");
params.put("sign_method", "md5");
params.put("timestamp", String.valueOf(System.currentTimeMillis()));
params.put("num_iid", itemId);
params.put("page", page);
String sign = generateSign(params, APP_SECRET);
params.put("sign", sign);
String url = buildRequestUrl(params);
return sendHttpGetRequest(url);
}
private static String generateSign(Map<String, String> params, String appSecret) throws IOException {
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, String> entry : params.entrySet()) {
sb.append(entry.getKey()).append(entry.getValue());
}
sb.append(appSecret);
return URLEncoder.encode(sb.toString(), StandardCharsets.UTF_8.name());
}
private static String buildRequestUrl(Map<String, String> params) throws IOException {
StringBuilder urlBuilder = new StringBuilder(API_URL);
urlBuilder.append("?");
for (Map.Entry<String, String> entry : params.entrySet()) {
urlBuilder.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
}
return urlBuilder.toString();
}
private static String sendHttpGetRequest(String url) throws IOException {
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
HttpGet httpGet = new HttpGet(url);
String result = httpClient.execute(httpGet, httpResponse -> EntityUtils.toString(httpResponse.getEntity()));
ObjectMapper objectMapper = new ObjectMapper();
JsonNode rootNode = objectMapper.readTree(result);
return rootNode.toString();
}
}
}

View File

@@ -1,109 +0,0 @@
package cn.van.business.util.ds.pl;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;
import java.util.HashMap;
public class SimpleCommentScraper {
private static final Logger logger = LoggerFactory.getLogger(SimpleCommentScraper.class);
private static final int SLEEP_TIME = 1000; // 休眠时间,单位:毫秒
private static final String JD_PROD_PIC_SAVE_PATH = "jd_prod_pic";
private static final int PAGE_RANGE = 1;
private static final String BIG_PAG_PATH = "//img30.360buyimg.com/shaidan/s616x405_jfs/";
private static final String TINY_PAG_PATH = "//img30.360buyimg.com/n0/s128x96_jfs/";
private static final Map<String, String> headers = new HashMap<>();
static {
headers.put("cookie", "shshshfpa=0e6670b1-47be-d3a7-049d-3c9daa179153-1691582935; shshshfpx=0e6670b1-47be-d3a7-049d-3c9daa179153-1691582935; jcap_dvzw_fp=AMQNEJZc35A3KmQ7fLb-4FSnB2SbuA9auLr22ALve7Qyx9JarjpZCIHN8NIz4Bl_IB7RVdQ3LaO4xSrC0YsR3g==; __jdu=1744804395425546198998; whwswswws=; warehistory=\"10076121538879,10076121538879,10076121538879,\"; autoOpenApp_downCloseDate_autoOpenApp_autoPromptly=1744804996891_1; autoOpenApp_downCloseDate_jd_independent_coupon_openapp=1744948913486_1; pt_st=1_NWSLixpIv7w0rF2ENYK3Jf9y6xeCZi7by-s-cZ_os-zspi7V1bGhPcAZ3w02h0KlZuRNO4sgikpci-xjqrABXbJ-y524iEqm9uq2V0mkVH2RqLEesj0chjJtg-tcF6UBnUVWtVOqIaHczH4Ksux0Hlvk5oBhTziEhk7vR2wnLPciQ-W46Lld2YFdN_RldDpP-zVCY0pvepwAP8h8Ji4aNM-AueIvKCFFdqUYBq0K; autoOpenApp_downCloseDate_auto=1744948934067_1800000; unpl=JF8EAL1nNSttDxhRB0wEExJFTApdWwgASR4HO24GVgoKHFYNEgJMEBh7XlVdWRRKEh9vbxRUXlNLXA4ZASsSEHtdVV9eC04WAGdvNWRdWUpVBR8FGRUWe15Ublw4SxEGam4EUV9QT1EGHwYeFRBDVFxWVDhKJwNnYDVUXFhJXAAeBBwUGEleVG5tCXsUAWthBWRfWEpVDRsAExMTexw6Xl8KTREAa29IVFtdTl0EHgATFhVIWVBbWghDHgtnbjVVbVs; PCSYCityID=CN_440000_440400_0; __jdv=95931165%7Cbaidu%7C-%7Corganic%7Cnot%20set%7C1745683529792; areaId=19; 3AB9D23F7A4B3CSS=jdd03S5H5QMW2J75PKHW4AFEYH4WL3LTTPLHA33OM55RXWWZHHN54YMZYWQVIP72VO6IQPERN7263IEW3QS2MCHMDXKAHOAAAAAMWQXDYBRYAAAAAC66XIXT2PW7RNEX; TrackID=1HV4we0cR8GOSM8bCj15ATZWJRCkRxt_zC9NsV07_Rw_Hpjbg27hW-EOoflSpUAwRiCF64Gv0rs2svV4zySkqmD2IGl3twHr85Kl7cz6UD04; thor=BD7A0187F5FD056EAF98728DE029360B7A8A0541C8F77CB45F7B0147C979FC4B63263DC7060C0A0E024D245FED98C39E1965497BF8A52DD2B804B7A43DC8E62AAFCCC8375C8F1DAFD06EB149963A9C059E6A5A3794ED7091F3030BB35714F349356967BE1C5BCF323F577F074EBAB2972C8AFCEA4E692A2AB838FE098D171E77577D42ED90A56C77C4C41BED4EDEE82EBE2C73DD4186579625DD374F4EB7C081; light_key=AASBKE7rOxgWQziEhC_QY6yaHACwW-20kQ1Dcwl6grswVJjfXVytbgQhtenpZa5NPqZ_cGo0; pinId=0M8ocQ7iEWaVVjS3qk-0cbV9-x-f3wj7; pin=jd_4963d6886b0f2; unick=jd_136704tjkx; ceshi3.com=201; _tp=3CK%2BmBvk2ojeH2NRIdd5njR3CccoiLr28y8aBChbZuU%3D; _pst=jd_4963d6886b0f2; mail_times=1%2C1; cn=37; umc_count=1; source=PC; platform=pc; 3AB9D23F7A4B3C9B=S5H5QMW2J75PKHW4AFEYH4WL3LTTPLHA33OM55RXWWZHHN54YMZYWQVIP72VO6IQPERN7263IEW3QS2MCHMDXKAHOA; token=ed9f1fe0e7b340ca631c803a236bea46,3,970000; jsavif=1; __jda=181111935.1744804395425546198998.1744804395.1745683529.1746001166.13; __jdb=181111935.5.1744804395425546198998|13.1746001166; __jdc=181111935; flash=3_y4qAJzSRoYzofvat3DYn_5Klmf98wlnb_Rfv-1RxzFYoUuB2ue9FJsma9Kg_PtrLc8D00wMqYgHYuvmQMG1DLgI0h-0u-g9CY33yr4S_VQWoWVsGCMQFF-X_lYW455Y34pydLsc45q6G13Fs3KZzzRMoONO9VhAnXvXn5HyJW36pUpWl4XA0wV**; shshshfpb=BApXSqdjBhvNAkN6htfk9E7ZUVeoR0SCJB9MZLhp89xJ1MkNSh4O2; ipLoc-djd=19-1609-41653-0; sdtoken=AAbEsBpEIOVjqTAKCQtvQu17hnR3nn92tx0xIv0BMmdNKx5EOYU9EjhDQyt4HcTnNd06jjQqdJS-xPUQBOfQ5bB2jxUBytH6hCZmvHMLyZ5w55ox8Q80a0chH_sopEs");
headers.put("referer", "https://item.jd.com/");
headers.put("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36 Edg/91.0.864.37");
}
public static void main(String[] args) {
getJDProdComment("10111812014432");
}
public static void getJDProdComment(String prod_skuId) {
for (int i = 0; i < PAGE_RANGE; i++) {
long t = System.currentTimeMillis();
String comments_url = "https://api.m.jd.com/?appid=item-v3&functionId=pc_club_productPageComments&client=pc&clientVersion=1.0.0"+"&t="+t+"9&loginType=3&uuid=181111935.16953916127351737253418.1695391613.1705847111.1705852812.35&productId=" + prod_skuId + "&score=0&sortType=5&page=" + i + "&pageSize=10&isShadowSku=0&fold=1&bbtf=&shield=";
try {
String response = sendRequest(comments_url);
if (response != null) {
JSONObject json_data = JSONObject.parseObject(response);
System.out.println(json_data);
if (i == 0) {
JSONObject productCommentSummary = json_data.getJSONObject("productCommentSummary");
System.out.println(prod_skuId + " " + productCommentSummary);
JSONArray hotCommentTagStatistics = json_data.getJSONArray("hotCommentTagStatistics");
System.out.println(prod_skuId + " " + hotCommentTagStatistics);
}
JSONArray comments = json_data.getJSONArray("comments");
if (comments != null && comments.size() > 0) {
for (int j = 0; j < comments.size(); j++) {
JSONObject comment = comments.getJSONObject(j);
String prod_comment_guid = comment.getString("guid");
String prod_comment_content = comment.getString("content");
String prod_comment = comment.toString();
JSONArray images = comment.getJSONArray("images");
if (images != null && images.size() > 0) {
for (int k = 0; k < images.size(); k++) {
JSONObject image = images.getJSONObject(k);
String imgUrl = image.getString("imgUrl");
logger.info("图片 {}", imgUrl);
Thread.sleep(SLEEP_TIME);
}
}
System.out.println(prod_comment_guid + " " + prod_skuId + " " + prod_comment_content + " " + prod_comment);
}
}
}
Thread.sleep(SLEEP_TIME);
} catch (Exception e) {
e.printStackTrace();
}
}
}
private static String sendRequest(String urlStr) throws IOException {
URL url = new URL(urlStr);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
for (Map.Entry<String, String> entry : headers.entrySet()) {
connection.setRequestProperty(entry.getKey(), entry.getValue());
}
int responseCode = connection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
StringBuilder response = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
response.append(line);
}
reader.close();
return response.toString();
}
return null;
}
public static void downloadfile(String downloadurl) {
logger.info("downloadurl{}", downloadurl);
}
}

View File

@@ -1 +0,0 @@
headers.put("cookie", "shshshfpa=0e6670b1-47be-d3a7-049d-3c9daa179153-1691582935; shshshfpx=0e6670b1-47be-d3a7-049d-3c9daa179153-1691582935; jcap_dvzw_fp=AMQNEJZc35A3KmQ7fLb-4FSnB2SbuA9auLr22ALve7Qyx9JarjpZCIHN8NIz4Bl_IB7RVdQ3LaO4xSrC0YsR3g==; __jdu=1744804395425546198998; whwswswws=; warehistory=\"10076121538879,10076121538879,10076121538879,\"; autoOpenApp_downCloseDate_autoOpenApp_autoPromptly=1744804996891_1; autoOpenApp_downCloseDate_jd_independent_coupon_openapp=1744948913486_1; pt_st=1_NWSLixpIv7w0rF2ENYK3Jf9y6xeCZi7by-s-cZ_os-zspi7V1bGhPcAZ3w02h0KlZuRNO4sgikpci-xjqrABXbJ-y524iEqm9uq2V0mkVH2RqLEesj0chjJtg-tcF6UBnUVWtVOqIaHczH4Ksux0Hlvk5oBhTziEhk7vR2wnLPciQ-W46Lld2YFdN_RldDpP-zVCY0pvepwAP8h8Ji4aNM-AueIvKCFFdqUYBq0K; autoOpenApp_downCloseDate_auto=1744948934067_1800000; unpl=JF8EAL1nNSttDxhRB0wEExJFTApdWwgASR4HO24GVgoKHFYNEgJMEBh7XlVdWRRKEh9vbxRUXlNLXA4ZASsSEHtdVV9eC04WAGdvNWRdWUpVBR8FGRUWe15Ublw4SxEGam4EUV9QT1EGHwYeFRBDVFxWVDhKJwNnYDVUXFhJXAAeBBwUGEleVG5tCXsUAWthBWRfWEpVDRsAExMTexw6Xl8KTREAa29IVFtdTl0EHgATFhVIWVBbWghDHgtnbjVVbVs; PCSYCityID=CN_440000_440400_0; __jdv=95931165%7Cbaidu%7C-%7Corganic%7Cnot%20set%7C1745683529792; areaId=19; 3AB9D23F7A4B3CSS=jdd03S5H5QMW2J75PKHW4AFEYH4WL3LTTPLHA33OM55RXWWZHHN54YMZYWQVIP72VO6IQPERN7263IEW3QS2MCHMDXKAHOAAAAAMWQXDYBRYAAAAAC66XIXT2PW7RNEX; TrackID=1HV4we0cR8GOSM8bCj15ATZWJRCkRxt_zC9NsV07_Rw_Hpjbg27hW-EOoflSpUAwRiCF64Gv0rs2svV4zySkqmD2IGl3twHr85Kl7cz6UD04; thor=BD7A0187F5FD056EAF98728DE029360B7A8A0541C8F77CB45F7B0147C979FC4B63263DC7060C0A0E024D245FED98C39E1965497BF8A52DD2B804B7A43DC8E62AAFCCC8375C8F1DAFD06EB149963A9C059E6A5A3794ED7091F3030BB35714F349356967BE1C5BCF323F577F074EBAB2972C8AFCEA4E692A2AB838FE098D171E77577D42ED90A56C77C4C41BED4EDEE82EBE2C73DD4186579625DD374F4EB7C081; light_key=AASBKE7rOxgWQziEhC_QY6yaHACwW-20kQ1Dcwl6grswVJjfXVytbgQhtenpZa5NPqZ_cGo0; pinId=0M8ocQ7iEWaVVjS3qk-0cbV9-x-f3wj7; pin=jd_4963d6886b0f2; unick=jd_136704tjkx; ceshi3.com=201; _tp=3CK%2BmBvk2ojeH2NRIdd5njR3CccoiLr28y8aBChbZuU%3D; _pst=jd_4963d6886b0f2; mail_times=1%2C1; cn=37; umc_count=1; source=PC; platform=pc; 3AB9D23F7A4B3C9B=S5H5QMW2J75PKHW4AFEYH4WL3LTTPLHA33OM55RXWWZHHN54YMZYWQVIP72VO6IQPERN7263IEW3QS2MCHMDXKAHOA; token=ed9f1fe0e7b340ca631c803a236bea46,3,970000; jsavif=1; __jda=181111935.1744804395425546198998.1744804395.1745683529.1746001166.13; __jdb=181111935.5.1744804395425546198998|13.1746001166; __jdc=181111935; flash=3_y4qAJzSRoYzofvat3DYn_5Klmf98wlnb_Rfv-1RxzFYoUuB2ue9FJsma9Kg_PtrLc8D00wMqYgHYuvmQMG1DLgI0h-0u-g9CY33yr4S_VQWoWVsGCMQFF-X_lYW455Y34pydLsc45q6G13Fs3KZzzRMoONO9VhAnXvXn5HyJW36pUpWl4XA0wV**; shshshfpb=BApXSqdjBhvNAkN6htfk9E7ZUVeoR0SCJB9MZLhp89xJ1MkNSh4O2; ipLoc-djd=19-1609-41653-0; sdtoken=AAbEsBpEIOVjqTAKCQtvQu17hnR3nn92tx0xIv0BMmdNKx5EOYU9EjhDQyt4HcTnNd06jjQqdJS-xPUQBOfQ5bB2jxUBytH6hCZmvHMLyZ5w55ox8Q80a0chH_sopEs");