ScreenshotUtil.java 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. /*
  2. * <<
  3. * Davinci
  4. * ==
  5. * Copyright (C) 2016 - 2019 EDP
  6. * ==
  7. * Licensed under the Apache License, Version 2.0 (the "License");
  8. * you may not use this file except in compliance with the License.
  9. * You may obtain a copy of the License at
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. * >>
  17. *
  18. */
  19. package edp.davinci.service.screenshot;
  20. import com.alibaba.druid.util.StringUtils;
  21. import edp.core.consts.Consts;
  22. import edp.core.utils.DateUtils;
  23. import edp.core.utils.FileUtils;
  24. import edp.davinci.core.enums.LogNameEnum;
  25. import lombok.extern.slf4j.Slf4j;
  26. import org.openqa.selenium.*;
  27. import org.openqa.selenium.TimeoutException;
  28. import org.openqa.selenium.chrome.ChromeDriver;
  29. import org.openqa.selenium.chrome.ChromeDriverService;
  30. import org.openqa.selenium.chrome.ChromeOptions;
  31. import org.openqa.selenium.logging.LogEntries;
  32. import org.openqa.selenium.logging.LogEntry;
  33. import org.openqa.selenium.logging.LogType;
  34. import org.openqa.selenium.phantomjs.PhantomJSDriver;
  35. import org.openqa.selenium.phantomjs.PhantomJSDriverService;
  36. import org.openqa.selenium.remote.DesiredCapabilities;
  37. import org.openqa.selenium.remote.RemoteWebDriver;
  38. import org.openqa.selenium.support.ui.ExpectedCondition;
  39. import org.openqa.selenium.support.ui.ExpectedConditions;
  40. import org.openqa.selenium.support.ui.WebDriverWait;
  41. import org.slf4j.Logger;
  42. import org.slf4j.LoggerFactory;
  43. import org.springframework.beans.factory.annotation.Autowired;
  44. import org.springframework.beans.factory.annotation.Value;
  45. import org.springframework.stereotype.Component;
  46. import java.io.File;
  47. import java.net.MalformedURLException;
  48. import java.net.URL;
  49. import java.util.ArrayList;
  50. import java.util.Comparator;
  51. import java.util.List;
  52. import java.util.concurrent.*;
  53. import java.util.concurrent.atomic.AtomicInteger;
  54. import static edp.davinci.service.screenshot.BrowserEnum.valueOf;
  55. @Slf4j
  56. @Component
  57. public class ScreenshotUtil {
  58. private static final Logger scheduleLogger = LoggerFactory.getLogger(LogNameEnum.BUSINESS_SCHEDULE.getName());
  59. @Value("${screenshot.default_browser:PHANTOMJS}")
  60. private String DEFAULT_BROWSER;
  61. @Value("${screenshot.chromedriver_path:}")
  62. private String CHROME_DRIVER_PATH;
  63. @Value("${screenshot.phantomjs_path:}")
  64. private String PHANTOMJS_PATH;
  65. @Value("${screenshot.remote_webdriver_url:}")
  66. private String REMOTE_WEBDRIVER_URL;
  67. @Value("${screenshot.timeout_second:600}")
  68. private int timeOutSecond;
  69. private static final int DEFAULT_SCREENSHOT_WIDTH = 1920;
  70. private static final int DEFAULT_SCREENSHOT_HEIGHT = 1080;
  71. private static final ExecutorService executorService = Executors.newFixedThreadPool(8);
  72. @Autowired
  73. private FileUtils fileUtils;
  74. public void screenshot(long jobId, List<ImageContent> imageContents, Integer imageWidth) {
  75. scheduleLogger.info("Start screenshot for job({})", jobId);
  76. try {
  77. int contentsSize = imageContents.size();
  78. List<Future> futures = new ArrayList<>(contentsSize);
  79. final AtomicInteger index = new AtomicInteger(1);
  80. imageContents.forEach(content -> futures.add(executorService.submit(() -> {
  81. scheduleLogger.info("Cronjob({}) thread({}) for screenshot start, type:{}, id:{}, total:{}", jobId, index.get(), content.getDesc(), content.getCId(), contentsSize);
  82. try {
  83. File image = doScreenshot(jobId, content.getUrl(), imageWidth);
  84. System.out.println("生成的图片>>>>" + image.getName());
  85. content.setContent(image);
  86. } catch (Exception e) {
  87. scheduleLogger.error("Cronjob({}) thread( {}) screenshot error", jobId, index.get());
  88. scheduleLogger.error(e.getMessage(), e);
  89. } finally {
  90. scheduleLogger.info("Cronjob({}) thread({}) for screenshot finish, type:{}, id:{}, total:{}", jobId, index.get(), content.getDesc(), content.getCId(), contentsSize);
  91. index.incrementAndGet();
  92. }
  93. })));
  94. try {
  95. for (Future future : futures) {
  96. future.get();
  97. }
  98. } catch (ExecutionException e) {
  99. scheduleLogger.error(e.getMessage(), e);
  100. }
  101. imageContents.sort(Comparator.comparing(ImageContent::getOrder));
  102. } catch (InterruptedException e) {
  103. scheduleLogger.error(e.getMessage(), e);
  104. } finally {
  105. scheduleLogger.info("Cronjob({}) finish screenshot", jobId);
  106. }
  107. }
  108. private File doScreenshot(long jobId, String url, Integer imageWidth) throws Exception {
  109. WebDriver driver = generateWebDriver(jobId, imageWidth);
  110. driver.get(url);
  111. scheduleLogger.info("Cronjob({}) do screenshot url={}, timeout={} start", jobId, url, timeOutSecond);
  112. try {
  113. WebDriverWait wait = new WebDriverWait(driver, timeOutSecond);
  114. ExpectedCondition<WebElement> ConditionOfSign = ExpectedConditions.presenceOfElementLocated(By.id("headlessBrowserRenderSign"));
  115. ExpectedCondition<WebElement> ConditionOfWidth = ExpectedConditions.presenceOfElementLocated(By.id("width"));
  116. ExpectedCondition<WebElement> ConditionOfHeight = ExpectedConditions.presenceOfElementLocated(By.id("height"));
  117. wait.until(ExpectedConditions.or(ConditionOfSign, ConditionOfWidth, ConditionOfHeight));
  118. String widthVal = driver.findElement(By.id("width")).getAttribute("value");
  119. String heightVal = driver.findElement(By.id("height")).getAttribute("value");
  120. int width = imageWidth != null && imageWidth > 0 ? imageWidth : DEFAULT_SCREENSHOT_WIDTH;
  121. int height = DEFAULT_SCREENSHOT_HEIGHT;
  122. if (!StringUtils.isEmpty(widthVal)) {
  123. width = Integer.parseInt(widthVal);
  124. }
  125. if (!StringUtils.isEmpty(heightVal)) {
  126. height = Integer.parseInt(heightVal);
  127. }
  128. driver.manage().window().setSize(new Dimension(width, height));
  129. Thread.sleep(2000);
  130. File tempImage = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
  131. File tempDir = new File(fileUtils.fileBasePath + Consts.DIR_TEMP + DateUtils.getNowDateYYYYMMDD());
  132. if (!tempDir.exists()) {
  133. tempDir.mkdirs();
  134. }
  135. File image = new File(tempDir.getPath() + File.separator + tempImage.getName());
  136. if (FileUtils.copy(tempImage, image) > -1) {
  137. tempImage.delete();
  138. return image;
  139. }
  140. } catch (TimeoutException te) {
  141. String text = driver.findElements(By.tagName("html")).get(0).getAttribute("innerText");
  142. scheduleLogger.info("Cronjob({}) do screenshot url={} text=\n{}", text);
  143. LogEntries logEntries = driver.manage().logs().get(LogType.BROWSER);
  144. for (LogEntry entry : logEntries) {
  145. scheduleLogger.info(entry.getLevel() + " " + entry.getMessage());
  146. }
  147. scheduleLogger.error(te.getMessage(), te);
  148. } catch (InterruptedException e) {
  149. LogEntries logEntries= driver.manage().logs().get(LogType.BROWSER);
  150. for (LogEntry entry : logEntries) {
  151. scheduleLogger.info(entry.getLevel() + " " + entry.getMessage());
  152. }
  153. scheduleLogger.error(e.getMessage(), e);
  154. } finally {
  155. scheduleLogger.info("Cronjob({}) do screenshot url={} finish", jobId, url);
  156. driver.quit();
  157. }
  158. return null;
  159. }
  160. private WebDriver generateWebDriver(Long jobId, Integer imageWidth) throws ExecutionException {
  161. WebDriver driver;
  162. BrowserEnum browserEnum = valueOf(DEFAULT_BROWSER);
  163. switch (browserEnum) {
  164. case CHROME:
  165. driver = generateChromeDriver();
  166. scheduleLogger.info("Cronjob({}) generating chrome driver({})...", jobId, driver.getClass().toString());
  167. break;
  168. case PHANTOMJS:
  169. driver = generatePhantomJsDriver();
  170. scheduleLogger.info("Cronjob({}) generating PhantomJs driver({})...", jobId, PHANTOMJS_PATH);
  171. break;
  172. default:
  173. throw new IllegalArgumentException("Unknown Web browser:" + DEFAULT_BROWSER);
  174. }
  175. driver.manage().timeouts().implicitlyWait(3, TimeUnit.MINUTES);
  176. driver.manage().window().maximize();
  177. driver.manage().window().setSize(new Dimension(imageWidth != null && imageWidth > 0 ? imageWidth : DEFAULT_SCREENSHOT_WIDTH, DEFAULT_SCREENSHOT_HEIGHT));
  178. return driver;
  179. }
  180. private WebDriver generateChromeDriver() throws ExecutionException {
  181. if (!StringUtils.isEmpty(REMOTE_WEBDRIVER_URL)) {
  182. scheduleLogger.info("User remoteWebDriver:{}", REMOTE_WEBDRIVER_URL);
  183. try {
  184. return new RemoteWebDriver(new URL(REMOTE_WEBDRIVER_URL), DesiredCapabilities.chrome());
  185. } catch (MalformedURLException ex) {
  186. scheduleLogger.error(ex.toString(), ex);
  187. }
  188. }
  189. String cpath = CHROME_DRIVER_PATH;
  190. if(isLinux()){
  191. cpath = CHROME_DRIVER_PATH + "/linux/chromedriver";
  192. }
  193. if(isWindows()){
  194. cpath = CHROME_DRIVER_PATH + "/window";
  195. }
  196. // CHROME_DRIVER_PATH = "/app/resources/chrome-driver/linux/chromedriver";
  197. System.out.println("CHROME_DRIVER_PATH>>>"+ cpath);
  198. File file = new File(cpath);
  199. System.out.println("file type>>>"+ file.isFile());
  200. System.out.println(file.getAbsolutePath()+"["+file.getName()+"]********************"+file.length());
  201. if (!file.canExecute()) {
  202. if (!file.setExecutable(true)) {
  203. throw new ExecutionException(new Exception(cpath + " is not executable!"));
  204. }
  205. }
  206. System.setProperty(ChromeDriverService.CHROME_DRIVER_EXE_PROPERTY, cpath);
  207. ChromeOptions options = new ChromeOptions();
  208. options.addArguments("headless");
  209. options.addArguments("no-sandbox");
  210. options.addArguments("disable-gpu");
  211. options.addArguments("disable-features=NetworkService");
  212. options.addArguments("ignore-certificate-errors");
  213. options.addArguments("silent-launch");
  214. options.addArguments("disable-application-cache");
  215. options.addArguments("disable-web-security");
  216. options.addArguments("no-proxy-server");
  217. options.addArguments("disable-dev-shm-usage");
  218. return new ChromeDriver(options);
  219. }
  220. public static void main(String[] args) throws ExecutionException {
  221. String OS = System.getProperty("os.name").toLowerCase();
  222. System.out.println(OS);
  223. }
  224. public static boolean isLinux(){
  225. String OS = System.getProperty("os.name").toLowerCase();
  226. return OS.indexOf("linux")>=0;
  227. }
  228. public static boolean isWindows(){
  229. String OS = System.getProperty("os.name").toLowerCase();
  230. return OS.indexOf("windows")>=0;
  231. }
  232. private WebDriver generatePhantomJsDriver() throws ExecutionException {
  233. File file = new File(PHANTOMJS_PATH);
  234. if (!file.canExecute()) {
  235. if (!file.setExecutable(true)) {
  236. throw new ExecutionException(new Exception(PHANTOMJS_PATH + " is not executable!"));
  237. }
  238. }
  239. System.setProperty(PhantomJSDriverService.PHANTOMJS_EXECUTABLE_PATH_PROPERTY, PHANTOMJS_PATH);
  240. return new PhantomJSDriver();
  241. }
  242. }