此代码仅供个人学习、研究之用,请勿用于商业用途
移动采集
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.gargoylesoftware.htmlunit.*;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import com.gargoylesoftware.htmlunit.util.Cookie;
import com.gargoylesoftware.htmlunit.util.NameValuePair;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* cmcc
*
*/
@Service("cmccService")
public class CmccServiceImpl implements CmccService {
private static Pattern NUMBER_PATTERN = Pattern.compile("totalNum\":(.*?),");
protected Logger log = LoggerFactory.getLogger(getClass());
@Override
public String fetchLoginSms(String data, HttpServletRequest request) throws Exception {
JSONObject json = new JSONObject();
String decryptedData = RsaUtil.privateDecrypt(data, RsaUtil.getPrivateKey(RsaUtil.PRIVATE_KEY));
if (null == decryptedData && "".equals(decryptedData)) {
json.put("msg", "参数错误");
json.put("code", "0001");
json.put("data", "error");
return JSONObject.toJSONString(json);
}
JSONObject jsonData = JSONObject.parseObject(decryptedData);
String phone = jsonData.getString("phone");
if (phone == null) {
json.put("msg", "手机号码不能为空");
json.put("code", "0001");
json.put("data", "error");
return JSONObject.toJSONString(json);
}
String custId = jsonData.getString("custId");
if (custId == null) {
json.put("msg", "custId不能为空");
json.put("code", "0002");
json.put("data", "error");
return JSONObject.toJSONString(json);
}
return getLoginSms(phone, request, custId);
}
private String getLoginSms(String phone, HttpServletRequest request, String custId) throws Exception {
JSONObject json = new JSONObject();
WebClient webClient = new WebClient(BrowserVersion.CHROME);
webClient.getOptions().setCssEnabled(false);
webClient.getOptions().setUseInsecureSSL(true);
webClient.getOptions().setActiveXNative(false);
webClient.getOptions().setJavaScriptEnabled(true);
webClient.getOptions().setThrowExceptionOnScriptError(false);
webClient.getOptions().setThrowExceptionOnFailingStatusCode(false);
log.info("登录 用户 [{}] 开始获取登录验证码", phone);
Map<String, String> header = new HashMap(10);
header.put("Accept", "application/json, text/javascript, */*; q=0.01");
header.put("Referer", "https://login.10086.cn/login.html");
header.put("X-Requested-With", "XMLHttpRequest");
String url = "https://login.10086.cn/login.html";
WebRequest webRequest = new WebRequest(new URL(url), HttpMethod.GET);
webRequest.setAdditionalHeaders(header);
webClient.getPage(webRequest);
int retryCount = 1;
do {
if (retryCount > 1) {
Thread.sleep(60000);
}
log.info("登录 用户 [{}] 第 [{}] 次获取登录验证码中...", phone, retryCount);
List<NameValuePair> reqParam = new ArrayList();
reqParam.clear();
reqParam.add(new NameValuePair("userName", phone));
webRequest = new WebRequest(new URL("https://login.10086.cn/chkNumberAction.action"), HttpMethod.POST);
webRequest.setRequestParameters(reqParam);
TextPage sendSMS = webClient.getPage(webRequest);
log.info("登录 用户 [{}] 获取手机验证码第一步结果: [{}]", phone, sendSMS.getContent());
if ("true".equals(sendSMS.getContent())) {
log.info("登录 用户 [{}] 获取手机验证码第二步开始:", phone);
retryCount++;
json = getLoginSmsSecond(webClient, phone, request, custId);
} else {
json.put("msg", "发送验证码失败,请稍后再试!");
json.put("code", "0002");
json.put("data", "error");
return JSONObject.toJSONString(json);
}
} while (!"0000".equals(json.getString("code"))
&& !"0010".equals(json.getString("code"))
&& !"0011".equals(json.getString("code"))
&& !"1001".equals(json.getString("code"))
&& !"1010".equals(json.getString("code")));
return JSONObject.toJSONString(json);
}
private JSONObject getLoginSmsSecond(WebClient webClient, String phone, HttpServletRequest request, String custId) throws Exception {
JSONObject json = new JSONObject();
List<NameValuePair> reqParam = new ArrayList();
reqParam.add(new NameValuePair("userName", phone));
WebRequest webRequest = new WebRequest(new URL("https://login.10086.cn/loadToken.action"), HttpMethod.POST);
webRequest.setRequestParameters(reqParam);
Page codePage = webClient.getPage(webRequest);
JSONObject codePageJson = JSONObject.parseObject(codePage.getWebResponse().getContentAsString());
log.info("登录 用户 [{}] 获取手机验证码第二步结果: [{}]", phone, codePageJson);
if (!codePage.getWebResponse().getContentAsString().contains("\"code\":\"0000\",\"desc\":\"成功\"")) {
json.put("msg", "发送验证码失败,请重试");
json.put("code", "0003");
json.put("data", "error");
return json;
}
String tokenResult = codePageJson.getString("result");
return getLoginThird(webClient, phone, tokenResult, request, custId);
}
private JSONObject getLoginThird(WebClient webClient, String phone, String tokenResult, HttpServletRequest request, String custId) throws Exception {
JSONObject json = new JSONObject();
Map<String, String> header = new HashMap(10);
header.put("Content-Type", "application/x-www-form-url1encoded; charset=UTF-8");
header.put("Referer", "https://login.10086.cn/login.html?channelID=12034&backUrl=http%3A%2F%2Fservice.jx.10086.cn%2Fservice%2Fresources%2FindexNew.html");
WebRequest webRequest = new WebRequest(new URL("https://login.10086.cn/sendflag.htm?timestamp=" + System.currentTimeMillis()), HttpMethod.POST);
webRequest.setAdditionalHeaders(header);
webClient.getPage(webRequest);
Cookie cookie = webClient.getCookieManager().getCookie("sendflag");
if (null != cookie) {
String sendflag = cookie.getValue();
log.info("登录 用户 [{}] 获取Cookie: sendflag 成功: [{}]", phone, sendflag);
}
header.put("Xa-before", tokenResult);
header.put("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
List<NameValuePair> reqParam = new ArrayList();
reqParam.add(new NameValuePair("userName", phone));
reqParam.add(new NameValuePair("channelID", "12003"));
reqParam.add(new NameValuePair("type", "01"));
webRequest = new WebRequest(new URL("https://login.10086.cn/sendRandomCodeAction.action"), HttpMethod.POST);
webRequest.setRequestParameters(reqParam);
webRequest.setAdditionalHeaders(header);
Page resultPage = webClient.getPage(webRequest);
log.info("登录 用户 [{}] 获取验证码第三步结果: [{}]", phone, resultPage.getWebResponse().getContentAsString());
if ("1".equals(resultPage.getWebResponse().getContentAsString())) {
log.info("登录 用户 [{}] 获取登录验证码频繁,等待1分钟后重新发送!", phone);
json.put("msg", "对不起,短信随机码暂时不能发送,等待1分钟后重新发送!");
json.put("code", "0010");
json.put("data", "error");
return json;
} else if (resultPage.getWebResponse().getContentAsString().contains("0")) {
log.info("登录 用户 [{}] 短信验证码发送成功!", phone);
json.put("msg", "短信验证码发送成功");
json.put("code", "0000");
json.put("data", "success");
request.getSession().setAttribute(custId + "loginSms", webClient);
return json;
} else if (resultPage.getWebResponse().getContentAsString().contains("2")) {
log.info("登录 用户 [{}] 获取短信验证码次数到达上限,请24小时后再试", phone);
json.put("msg", "获取短信验证码次数到达上限,请24小时后再试!");
json.put("code", "0011");
json.put("data", "error");
return json;
} else if (resultPage.getWebResponse().getContentAsString().contains("6")) {
log.info("登录 用户 [{}] 获取短信验证码失败,官网响应为6,重试中...", phone);
json.put("msg", "获取短信验证码失败,官网响应为6,重试中!");
json.put("code", "0012");
json.put("data", "error");
return json;
} else if (resultPage.getWebResponse().getContentAsString().contains("error")){
log.info("登录 用户 [{}] 获取短信验证码失败,手机号码有误:[{}] ,请重试...", phone, resultPage.getWebResponse().getContentAsString());
json.put("msg", "获取短信验证码失败,手机号码有误");
json.put("code", "1001");
json.put("data", "error");
return json;
}else {
log.info("登录 用户 [{}] 获取短信验证码失败,系统异常:[{}] ,重试中...", phone, resultPage.getWebResponse().getContentAsString());
json.put("msg", "获取短信验证码失败,系统异常,重试中!");
json.put("code", "1000");
json.put("data", "error");
return json;
}
}
@Override
public String loginBySms(String data, HttpServletRequest request) throws Exception {
JSONObject json = new JSONObject();
String decryptedData = RsaUtil.privateDecrypt(data, RsaUtil.getPrivateKey(RsaUtil.PRIVATE_KEY));
if (decryptedData == null && "".equals(decryptedData)) {
json.put("msg", "参数不能为空");
json.put("code", "2000");
json.put("data", "error");
return JSONObject.toJSONString(json);
}
JSONObject jsonData = JSONObject.parseObject(decryptedData);
if (jsonData.getString("phone") == null) {
json.put("msg", "手机号不能为空!");
json.put("code", "2001");
json.put("data", "error");
}
if (jsonData.getString("smsCode") == null) {
json.put("msg", "短信验证码不能为空!");
json.put("code", "2001");
json.put("data", "error");
}
if (jsonData.getString("custId") == null) {
json.put("msg", "custId不能为空!");
json.put("code", "2001");
json.put("data", "error");
}
return JSONObject.toJSONString(cmccLogin(jsonData.getString("phone"), jsonData.getString("smsCode"), jsonData.getString("custId"), request));
}
private JSONObject cmccLogin(String phone, String smsCode, String custId, HttpServletRequest request) throws Exception {
WebClient webClient = (WebClient) request.getSession().getAttribute(custId + "loginSms");
Map<String, String> header = new HashMap(10);
List<NameValuePair> reqParam = new ArrayList();
JSONObject json = new JSONObject();
WebRequest webRequest = new WebRequest(new URL("https://login.10086.cn/login.htm"), HttpMethod.GET);
header.put("Accept", "application/json, text/javascript, */*; q=0.01");
header.put("Accept-Encoding", "gzip, deflate, br");
header.put("Accept-Language", "zh-CN,zh;q=0.9");
header.put("Connection", "keep-alive");
header.put("Host", "login.10086.cn");
header.put("Referer", "https://login.10086.cn/login.html");
header.put("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36");
header.put("X-Requested-With", "XMLHttpRequest");
webRequest.setAdditionalHeaders(header);
webRequest.setCharset(StandardCharsets.UTF_8);
reqParam.clear();
reqParam.add(new NameValuePair("accountType", "01"));
reqParam.add(new NameValuePair("account", phone));
reqParam.add(new NameValuePair("password", smsCode));
reqParam.add(new NameValuePair("pwdType", "02"));
reqParam.add(new NameValuePair("smsPwd", smsCode));
reqParam.add(new NameValuePair("inputCode", ""));
reqParam.add(new NameValuePair("backUrl", "http%3A%2F%2Fwww.10086.cn%2Froaming%2Fyewu%2Findex%2Fsn%2F%3FWT.mc_id%3DBD000GJMY_YEWU_GJC_1_190626"));
reqParam.add(new NameValuePair("rememberMe", "0"));
reqParam.add(new NameValuePair("channelID", "12034"));
reqParam.add(new NameValuePair("loginMode", "01"));
reqParam.add(new NameValuePair("protocol", "https%3A"));
reqParam.add(new NameValuePair("timestamp", String.valueOf(System.currentTimeMillis())));
webRequest.setRequestParameters(reqParam);
Page loginResultPage = null;
try {
loginResultPage = webClient.getPage(webRequest);
} catch (NullPointerException e) {
json.put("msg", "官网响应为空!");
json.put("code", "9999");
json.put("data", "error");
return json;
}
if (loginResultPage.getWebResponse().getContentAsString().contains("认证成功")) {
json.put("msg", "登录成功!");
json.put("code", "0000");
json.put("data", "success");
log.info("登录 用户 [{}] 登录成功,页面跳转中!", phone);
JSONObject info = JSONObject.parseObject(loginResultPage.getWebResponse().getContentAsString());
String artifact = info.getString("artifact");
jumpAfterSuccessLogin(webClient, artifact, custId, request);
log.info("登录 用户 [{}] 登录成功,跳转完成!", phone);
} else if (loginResultPage.getWebResponse().getContentAsString().contains("密码锁定")) {
json.put("msg", "登录失败,密码锁定!");
json.put("code", "2002");
json.put("data", "error");
log.info("登录 用户 [{}] 登录失败! 登录密码被锁定!", phone);
} else if (loginResultPage.getWebResponse().getContentAsString().contains("账号锁定")) {
json.put("msg", "登录失败,账号锁定!");
json.put("code", "2003");
json.put("data", "error");
log.info("登录 用户 [{}] 登录失败! 登录账号被锁定!", phone);
} else if (loginResultPage.getWebResponse().getContentAsString().contains("系统繁忙")) {
json.put("msg", "登录失败,官网系统繁忙!");
json.put("code", "2004");
json.put("data", "error");
log.info("登录 用户 [{}] 登录失败! 官网系统繁忙,请重试!", phone);
} else if (loginResultPage.getWebResponse().getContentAsString().contains("您的账户名与密码不匹配")) {
json.put("msg", "登录失败,您的账户名与密码不匹配!");
json.put("code", "2005");
json.put("data", "error");
log.info("用户 [{}] 登录失败! 账户名与密码不匹配!", phone);
} else if (loginResultPage.getWebResponse().getContentAsString().contains("短信随机码不正确或已过期")) {
json.put("msg", "登录失败,短信随机码不正确或已过期!");
json.put("code", "2006");
json.put("data", "error");
log.info("用户 [{}] 登录失败! 短信随机码不正确或已过期!", phone);
} else if (loginResultPage.getWebResponse().getContentAsString().contains("请您输入正确的密码")) {
json.put("msg", "登录失败,请您输入正确的密码!");
json.put("code", "2007");
json.put("data", "error");
log.info("登录 用户 [{}] 登录失败! 请您输入正确的密码!", phone);
} else {
json.put("msg", "登录失败,未知异常!");
json.put("code", "2008");
json.put("data", "error");
log.info("登录 用户 [{}] 登录失败! 未知异常: [{}]", phone, loginResultPage.getWebResponse().getContentAsString());
}
return json;
}
private void jumpAfterSuccessLogin(WebClient webClient, String artifact, String custId, HttpServletRequest request) throws Exception {
String url = "http://shop.10086.cn/i/v1/auth/getArtifact?backUrl=http%3A%2F%2Fshop.10086.cn%2Fi%2F&artifact=" + artifact;
WebRequest webRequest = new WebRequest(new URL(url), HttpMethod.GET);
webClient.getPage(webRequest);
log.info("用户登录成功,页面跳转中(1/3)...");
url = "https://login.10086.cn/SSOCheck.action?channelID=12003&backUrl=http://shop.10086.cn/i/?f=home";
webRequest = new WebRequest(new URL(url), HttpMethod.GET);
webClient.getPage(webRequest);
log.info("用户登录成功,页面跳转中(2/3)...");
url = "http://shop.10086.cn/i/?welcome=" + System.currentTimeMillis();
webRequest = new WebRequest(new URL(url), HttpMethod.GET);
webClient.getPage(webRequest);
log.info("用户登录成功,页面跳转中(3/3)...");
url = "http://shop.10086.cn/i/?f=billdetailqry";
webRequest = new WebRequest(new URL(url), HttpMethod.GET);
webClient.getPage(webRequest);
request.getSession().setAttribute(custId, webClient);
request.getSession().setAttribute(custId + "bill", webClient);
}
@Override
public String fetchXDBySms(String data, HttpServletRequest request) throws Exception {
JSONObject json = new JSONObject();
String decryptedData = RsaUtil.privateDecrypt(data, RsaUtil.getPrivateKey(RsaUtil.PRIVATE_KEY));
if (decryptedData == null && "".equals(decryptedData)) {
json.put("msg", "参数不能为空");
json.put("code", "2000");
json.put("data", "error");
return JSONObject.toJSONString(json);
}
JSONObject jsonData = JSONObject.parseObject(decryptedData);
if (jsonData.getString("phone") == null) {
json.put("msg", "手机号不能为空!");
json.put("code", "2001");
json.put("data", "error");
return JSONObject.toJSONString(json);
}
WebClient webClient = (WebClient) request.getSession().getAttribute(jsonData.getString("custId"));
if (null == webClient) {
json.put("msg", "非法请求!");
json.put("code", "9999");
json.put("data", "error");
return JSONObject.toJSONString(json);
}
Map<String, String> header = new HashMap(10);
header.put("Referer", "http://shop.10086.cn/i/?f=billdetailqry");
WebRequest webRequest = new WebRequest(new URL("http://shop.10086.cn/i/apps/serviceapps/billdetail/showvec.html"), HttpMethod.GET);
webRequest.setAdditionalHeaders(header);
webRequest.setCharset(StandardCharsets.UTF_8);
webClient.getPage(webRequest);
log.info("详单 用户 [{}] 获取详单验证码第一步完成", jsonData.getString("phone"));
log.info("详单 用户 [{}] 获取详单验证码前等待20秒,避免操作频繁", jsonData.getString("phone"));
for (int i = 0; i < 8; i++) {
Thread.sleep(1000);
}
log.info("详单 用户 [{}] 获取详单验证码第二步开始", jsonData.getString("phone"));
return JSONObject.toJSONString(fetchXDBySmsSecond(webClient, jsonData));
}
private JSONObject fetchXDBySmsSecond(WebClient webClient, JSONObject jsonData) throws Exception {
Map<String, String> header = new HashMap(10);
JSONObject json = new JSONObject();
int retryCount = 1;
Page sendSMSResult = null;
do {
log.info("详单 用户 [{}] 开始第 [{}] 次获取详单验证码", jsonData.getString("phone"), retryCount);
String url = String.format("https://shop.10086.cn/i/v1/fee/detbillrandomcodejsonp/%s?callback=jQuery011591518200914375_%s&_=%s",
jsonData.getString("phone"), System.currentTimeMillis(), System.currentTimeMillis());
header.clear();
header.put("Referer", "https://shop.10086.cn/i/?f=home&welcome=" + Calendar.getInstance().getTimeInMillis());
WebRequest webRequest = new WebRequest(new URL(url), HttpMethod.GET);
webRequest.setCharset(StandardCharsets.UTF_8);
webRequest.setAdditionalHeaders(header);
sendSMSResult = webClient.getPage(webRequest);
log.info("详单 用户 [{}] 第 [{}] 次获取详单验证码结果: [{}]", jsonData.getString("phone"),
retryCount, sendSMSResult.getWebResponse().getContentAsString());
retryCount++;
} while (retryCount >= 3 && sendSMSResult.getWebResponse().getContentAsString().contains("\"retMsg\":\"success\""));
if (sendSMSResult != null) {
if (sendSMSResult.getWebResponse().getContentAsString().contains("下发短信次数过多")) {
json.put("msg", "下发短信次数过多");
json.put("code", "3001");
json.put("data", "error");
log.info("详单 用户 [{}] 发送详单验证码失败,下发短信次数过多,请 [{}] 小时后再试!", jsonData.getString("phone"), "24");
} else if (sendSMSResult.getWebResponse().getContentAsString().contains("尊敬的用户,请勿在1分钟内重复下发短信")) {
json.put("msg", "请勿在1分钟内重复下发短信");
json.put("code", "3002");
json.put("data", "error");
log.info("详单 用户 [{}] 发送详单验证码失败,请勿在1分钟内重复下发短信,请稍后再试!", jsonData.getString("phone"));
} else if (sendSMSResult.getWebResponse().getContentAsString().contains("session信息为空,请先登录")) {
json.put("msg", "session信息为空,请先登录");
json.put("code", "3003");
json.put("data", "error");
log.info("详单 用户 [{}] 发送详单验证码失败,请先登录!", jsonData.getString("phone"));
} else if (sendSMSResult.getWebResponse().getContentAsString().contains("\"retMsg\":\"success\"")) {
json.put("msg", "详单短信验证码发送成功");
json.put("code", "0000");
json.put("data", "success");
log.info("详单 用户 [{}] 发送详单验证码成功!", jsonData.getString("phone"));
} else {
json.put("msg", "发送失败,未知异常");
json.put("code", "3004");
json.put("data", "error");
log.info("详单 用户 [{}] 发送详单验证码失败,异常原因: [{}]", jsonData.getString("phone"), sendSMSResult.getWebResponse().getContentAsString());
}
}
return json;
}
@Override
public String fetchImgCode(String dataStr, HttpServletRequest request) throws Exception {
JSONObject json = new JSONObject();
String decryptedData = RsaUtil.privateDecrypt(dataStr, RsaUtil.getPrivateKey(RsaUtil.PRIVATE_KEY));
if (decryptedData == null && "".equals(decryptedData)) {
json.put("msg", "参数错误");
json.put("code", "0001");
json.put("data", "error");
return JSONObject.toJSONString(json);
}
JSONObject jsonData = JSONObject.parseObject(decryptedData);
String custId = jsonData.getString("custId");
WebClient webClient = (WebClient) request.getSession().getAttribute(custId);
JSONObject data = new JSONObject();
Map<String, String> header = new HashMap(10);
header.put("Referer", "http://shop.10086.cn/i/?welcome=" + System.currentTimeMillis());
String imgUrl = "http://shop.10086.cn/i/authImg?t=" + Math.</