前些日子我手上接到一个需求,老板要求将一个非常复杂的网页(各种表格,各种统计图,各种数据)以图片的形式分享出去,第一时间我就觉得这个需求很奇葩,为什么不直接分享网页地址呢是吧?但是老板既然要这么一个功能我们想尽办法也得给他实现,于是我整理出了三个方案:①小程序端用canvas绘制页面并保存;②后端用Java swing绘制页面并生成图片,③小程序端访问后端,后端请求H5页面并截图,由于网页实在太复杂最终选择了方案三,后台访问截图用Python实现。
# -*- coding: utf-8 -*-
import sys
import time
import oss2
import json
import argparse
import base64
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
class Result(object):
def __init__(self,resutlCode,data):
# 返回结果对象
self.resutlCode = resutlCode
self.data = data
def to_json(self):
return json.dumps(self.__dict__)
def get_image(url, pic_name):
print("python版本号:" + sys.version)
chrome_options = Options()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu')
# 创建浏览器对象
# windows
driver = webdriver.Chrome(executable_path = 'E:/projects/onegolf/onegolf-parent/onegolf-server/onegolf-api/onegolf-python/windows/chromedriver', options=chrome_options)
# linux
# driver = webdriver.Chrome(/home/chromedriver', options=chrome_options)
# 打开网页
driver.get(url)
# driver.maximize_window()
# 加延时 防止未加载完就截图
time.sleep(1)
# 用js获取页面的宽高,如果有其他需要用js的部分也可以用这个方法
width = driver.execute_script("return document.documentElement.scrollWidth")
height = driver.execute_script("return document.documentElement.scrollHeight")
# 将浏览器的宽高设置成刚刚获取的宽高
driver.set_window_size(width, height)
time.sleep(1)
# 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录 https://ram.console.aliyun.com 创建RAM账号。
auth = oss2.Auth('ossAccessKeyId', 'ossAccessKeySecret')
# Endpoint以背景为例,其它Region请按实际情况填写。
bucket = oss2.Bucket(auth, 'http://oss-cn-beijing.aliyuncs.com', 'ossBucketName')
bucket.put_object('oss/image/match/' + pic_name, driver.get_screenshot_as_png())
driver.quit()
return Result( "200",'https://ip/oss/image/match/' + pic_name)
def base64_str_decode(base64_str):
temp = bytes(base64_str, encoding='utf-8')
return bytes(base64.b64decode(temp)).decode()
if __name__ == "__main__":
# 读取入参网页地址+图片名称
parser = argparse.ArgumentParser()
parser.add_argument('-params')
args = parser.parse_args()
# base64解码
param = base64_str_decode(args.params)
print("请求参数:" + param)
task = json.loads(param)
url = task[0]
pic_name = task[1]
print("url:" + url + ",pic_name:" + pic_name)
# 返回结果
result = None
try:
result = get_image(url, pic_name)
except Exception as e:
print(e)
# 输出结果,由Java接收
sys.stdout = sys.__stdout__
print("<<<)
print(result.to_json())
print(">>>>out>>>>")
package com.onegolf.base.util;
import com.alibaba.fastjson.JSONObject;
import com.onegolf.common.exceptions.CommonException;
import com.onegolf.common.response.ResponseResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.system.ApplicationHome;
import org.springframework.util.Base64Utils;
import org.springframework.util.CollectionUtils;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Collections;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* python脚本处理方法
*/
@Slf4j
public class PythonUtil {
/**
* 正则命名捕获的分组名
*/
private static final String RESULT = "result";
private static final String OPEN_TAG = "<<<;
private static final String CLOSE_TAG = ">>>>out>>>>";
/**
* python输出内容正则表达式
*/
private static final Pattern PATTERN = Pattern.compile(String.format("(?%s.*?%s)" , OPEN_TAG, CLOSE_TAG));
/**
* <<<>>>out>>>> 自身的长度
*/
private static final int FLAG_LENGTH = 11;
private static String pythonScriptPath;
// 这里回去python脚本的相对路径
static {
ApplicationHome applicationHome = new ApplicationHome(Object.class);
// windows
pythonScriptPath = applicationHome.getDir().getParentFile().getAbsolutePath()
+ File.separator + "onegolf-parent" + File.separator + "onegolf-server" + File.separator + "onegolf-api" + File.separator + "onegolf-python";
// linux
// pythonScriptPath = "/home";
}
/**
* 调用python获取截图地址
*
* @return 执行结果状态
*/
public static ResponseResult callAiTrainTask(List<String> cellNames) {
if (CollectionUtils.isEmpty(cellNames)) {
cellNames = Collections.emptyList();
}
try {
log.info("Starting execution");
// 这里的result对象和python的返回对象要一致
ResponseResult result =
callFunction("process.py", cellNames, ResponseResult.class);
log.info("Execution finished");
return result;
} catch (CommonException e) {
log.error("Execution fail with error", e);
ResponseResult result = new ResponseResult();
result.setResultCode("500");
result.setResultDesc(e.getMessage());
return result;
}
}
/**
*这里将python返回结果对象反序列换成java需要返回的对象
*/
private static <P, R> R callFunction(String fileName, P params, Class<R> returnType)
throws CommonException {
String paramsJson = JSONObject.toJSONString(params);
paramsJson = Base64Utils.encodeToString(paramsJson.getBytes());
String resultJson = callFunction(pythonScriptPath + File.separator + fileName, paramsJson);
try {
return JSONObject.parseObject(resultJson, returnType);
} catch (Exception e) {
log.error("返回结果反序列化失败:" + resultJson);
return null;
}
}
/**
*调用python的核心实现
*/
private static String callFunction(String fullFileName, String params) throws CommonException {
String command = String.format("python %s -params %s", fullFileName, params);
log.info("execute python command->" + command);
try {
Process process = Runtime.getRuntime().exec(command);
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
BufferedReader errReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
String temp;
String errorInfo;
while ((errorInfo = errReader.readLine()) != null){
log.debug(errorInfo);
}
StringBuilder resultBuilder = new StringBuilder();
boolean openTagFound = false;
while ((temp = reader.readLine()) != null) {
if (!openTagFound) {
// 找到OPEN_TAG标志前丢弃python输出,否则消息很长
if (!temp.contains(OPEN_TAG)) {
continue;
} else {
openTagFound = true;
}
}
resultBuilder.append(temp);
}
String result = resultBuilder.toString();
Matcher matcher = PATTERN.matcher(result);
if (matcher.find()) {
result = matcher.group(RESULT);
result = result.substring(FLAG_LENGTH, result.length() - FLAG_LENGTH);
return result;
}
return "";
} catch (IOException e) {
log.error("find a python function error", e);
throw new CommonException(e.getMessage());
}
}
}