测试用的,暂时同步
This commit is contained in:
1
conf/extra/indexJs.js
Normal file
1
conf/extra/indexJs.js
Normal file
File diff suppressed because one or more lines are too long
177
src/main/java/quant/rich/emoney/client/WebviewClient.java
Normal file
177
src/main/java/quant/rich/emoney/client/WebviewClient.java
Normal file
@@ -0,0 +1,177 @@
|
||||
package quant.rich.emoney.client;
|
||||
|
||||
import java.net.Proxy;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.microsoft.playwright.Browser;
|
||||
import com.microsoft.playwright.BrowserContext;
|
||||
import com.microsoft.playwright.BrowserType;
|
||||
import com.microsoft.playwright.Page;
|
||||
import com.microsoft.playwright.Playwright;
|
||||
import com.microsoft.playwright.Request;
|
||||
import com.microsoft.playwright.BrowserType.LaunchOptions;
|
||||
import com.microsoft.playwright.Route.ResumeOptions;
|
||||
import com.microsoft.playwright.options.HttpHeader;
|
||||
import com.microsoft.playwright.options.WaitUntilState;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
import quant.rich.emoney.component.LockByCaller;
|
||||
import quant.rich.emoney.entity.config.EmoneyRequestConfig;
|
||||
import quant.rich.emoney.entity.config.ProxyConfig;
|
||||
import quant.rich.emoney.util.SpringContextHolder;
|
||||
|
||||
public class WebviewClient {
|
||||
|
||||
private static Playwright playwright;
|
||||
private static boolean isReady = false;
|
||||
private static volatile ProxyConfig proxyConfig;
|
||||
private static volatile EmoneyRequestConfig emoneyRequestConfig;
|
||||
|
||||
static {
|
||||
try {
|
||||
playwright = Playwright.create();
|
||||
isReady = true;
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isReady() {
|
||||
return isReady;
|
||||
}
|
||||
|
||||
private static ProxyConfig getProxyConfig() {
|
||||
if (proxyConfig == null) {
|
||||
synchronized (WebviewClient.class) {
|
||||
if (proxyConfig == null) {
|
||||
proxyConfig = SpringContextHolder.getBean(ProxyConfig.class);
|
||||
}
|
||||
}
|
||||
}
|
||||
return proxyConfig;
|
||||
}
|
||||
|
||||
private static EmoneyRequestConfig getEmoneyRequestConfig() {
|
||||
if (emoneyRequestConfig == null) {
|
||||
synchronized (WebviewClient.class) {
|
||||
if (emoneyRequestConfig == null) {
|
||||
emoneyRequestConfig = SpringContextHolder.getBean(EmoneyRequestConfig.class);
|
||||
}
|
||||
}
|
||||
}
|
||||
return emoneyRequestConfig;
|
||||
}
|
||||
|
||||
@LockByCaller
|
||||
public static WebviewResponseWrapper getIndexDetailWrapper(String indexCode) {
|
||||
|
||||
String proxyUrl = getProxyConfig().getProxyUrl();
|
||||
LaunchOptions launchOptions = new BrowserType.LaunchOptions()
|
||||
.setHeadless(true);
|
||||
|
||||
// 设置代理
|
||||
if (StringUtils.isNotBlank(proxyUrl)) {
|
||||
launchOptions.setProxy(proxyUrl);
|
||||
}
|
||||
|
||||
Browser browser = playwright.chromium().launch(launchOptions);
|
||||
BrowserContext context = browser.newContext(new Browser.NewContextOptions()
|
||||
// 设置 Webview User-Agent
|
||||
.setUserAgent(getEmoneyRequestConfig().getWebviewUserAgent())
|
||||
// 设置是否忽略 HTTPS 证书
|
||||
.setIgnoreHTTPSErrors(getProxyConfig().getIgnoreHttpsVerification())
|
||||
);
|
||||
|
||||
// 设置全局请求头
|
||||
// 根据抓包获得,当前目标版本 5.8.1
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
headers.put("Upgrade-Insecure-Requests", "1");
|
||||
headers.put("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9");
|
||||
headers.put("X-Requested-With", "cn.emoney.emstock");
|
||||
headers.put("Sec-Fetch-Site", "none");
|
||||
headers.put("Sec-Fetch-Mode", "navigate");
|
||||
headers.put("Sec-Fetch-User", "?1");
|
||||
headers.put("Sec-Fetch-Dest", "document");
|
||||
headers.put("Accept-Encoding", "gzip, deflate");
|
||||
headers.put("Accept-Language", "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7");
|
||||
|
||||
context.setExtraHTTPHeaders(headers);
|
||||
context.route("**/*", route -> {
|
||||
// 清除 Playwright 添加的额外请求头
|
||||
Request request = route.request();
|
||||
List<HttpHeader> requestHeaderList = request.headersArray();
|
||||
Map<String, String> requestHeaders = new HashMap<>();
|
||||
for (HttpHeader header : requestHeaderList) {
|
||||
requestHeaders.put(header.name, header.value);
|
||||
}
|
||||
requestHeaders.remove("sec-ch-ua");
|
||||
requestHeaders.remove("sec-ch-ua-mobile");
|
||||
requestHeaders.remove("sec-ch-ua-platform");
|
||||
requestHeaders.remove("Cache-Control");
|
||||
requestHeaders.remove("Pragma");
|
||||
requestHeaders.remove("cache-control");
|
||||
requestHeaders.remove("pragma");
|
||||
|
||||
// 判断页面附属请求并进行个性化,以尽可能模仿原生 APP
|
||||
System.out.format("url: %s, requestType: %s\r\n", request.url(), request.resourceType());
|
||||
|
||||
String resourceType = request.resourceType();
|
||||
|
||||
if (!"document".equals(resourceType)) {
|
||||
// 非 document(html) 请求的
|
||||
requestHeaders.put("Sec-Fetch-Mode", "no-cors");
|
||||
requestHeaders.remove("Upgrade-Insecure-Requests");
|
||||
}
|
||||
if ("image".equals(request.resourceType())) {
|
||||
// 图片请求
|
||||
requestHeaders.put("Accept", "image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8");
|
||||
}
|
||||
else if ("script".equals(request.resourceType())) {
|
||||
// 图片请求
|
||||
requestHeaders.put("Accept", "*/*");
|
||||
}
|
||||
route.resume(new ResumeOptions().setHeaders(requestHeaders));
|
||||
});
|
||||
|
||||
Page page = context.newPage();
|
||||
WebviewResponseWrapper wrapper = new WebviewResponseWrapper();
|
||||
|
||||
page.onResponse(handler -> {
|
||||
String requestUrl = handler.request().url();
|
||||
if (requestUrl.endsWith(".js")) {
|
||||
String jsContent = handler.request().response().text();
|
||||
wrapper.jsMap.put(requestUrl, jsContent);
|
||||
}
|
||||
});
|
||||
|
||||
StringBuilder urlBuilder = new StringBuilder();
|
||||
urlBuilder.append("https://appstatic.emoney.cn/html/emapp/stock/note/?name=");
|
||||
urlBuilder.append(indexCode);
|
||||
urlBuilder.append("&emoneyScaleType=0&emoneyLandMode=0&token=");
|
||||
urlBuilder.append(getEmoneyRequestConfig().getAuthorization());
|
||||
String url = urlBuilder.toString();
|
||||
|
||||
page.navigate(url, new Page.NavigateOptions().setWaitUntil(WaitUntilState.NETWORKIDLE));
|
||||
|
||||
wrapper.setRenderedHtml(page.content());
|
||||
wrapper.setPage(page);
|
||||
browser.close();
|
||||
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
@Data
|
||||
@Accessors(chain=true)
|
||||
public static class WebviewResponseWrapper {
|
||||
private Map<String, String> jsMap = new HashMap<>();
|
||||
private String renderedHtml;
|
||||
private Page page;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user