测试用的,暂时同步

This commit is contained in:
2025-05-22 00:27:35 +08:00
parent 83b53299a4
commit 3ab59fe79c
2 changed files with 178 additions and 0 deletions

1
conf/extra/indexJs.js Normal file

File diff suppressed because one or more lines are too long

View 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;
}
}