之前实现了在 Ubuntu 服务器上网页自动截图的功能,本文记录将其部署在服务器上的过程。
实现思路
在实现 Ubuntu 自动截图的基础上,需要将该功能部署成前端可以访问的服务
- 配置好自动截图所需的服务
- 前端发送需要使用的网址列表
- 搭建后端程序,监听端口,启动线程异步执行截图功能并保存在某个文件夹
- 保存的文件名为网址的 md5 字符串
- 前端调用图像时在前端计算网址的 md5 值并拼凑出图像地址进行图像
- nginx 反向代理提供 https 链接
- 设置系统开机自动启动服务
实现步骤
web 截图环境配置
- 参考 无界面 Ubuntu 服务器搭建 selenium chromedriver 实现 Python 自动网页截图
前端发送网址列表
通过 ejs 模板结合 js 脚本代码获取 yaml 配置文件 中的网址列表
代码语言:javascript复制<script>
var total_links={};
var index = 0;
<% for(const sub_item of theme.vvd_local_links.families || []) { %>
<% for(const link_info of sub_item.items || []) { %>
total_links[index] = '<%- link_info.link %>'
index = index 1;
<% } %>
<% } %>
</script>
使用 jquery 发送 post 请求
代码语言:javascript复制<script src="https://101.43.39.125/HexoFiles/js/vvd_js/jquery.js"> </script>
<script>
var url = 'https://yourhost:port/make_post_img'
$.post(url, total_links);
</script>
搭建后端
- 后端用 Python 实现监听端口服务,开放某个端口和路由
- 获取 request 后解析出网址列表
- 参考代码:
from flask import Flask, request
from flask_cors import CORS
import mtutils as mt
from lib import FileManager
port = '3000'
log_file_path = 'log.log'
app = Flask(__name__)
app.logger = mt.log_init(log_file_path)
CORS(app, supports_credentials=True)
file_manager = FileManager(app.logger)
@app.route("/make_post_img", methods=['GET','POST'])
def make_post_img():
url_dict = dict(request.values)
url_list = list(url_dict.values())
file_manager.infer_screenshots(url_list, 'screenshots')
return 'make_post_img'
if __name__ == '__main__':
app.logger("**************** FileManager Sever Start *******************")
app.run('0.0.0.0', port=port)
pass
- 核心功能在
FileManager
类中实现
import time
import mtutils as mt
from selenium import webdriver
import hashlib
from threading import Thread, Lock
def async_call(fn):
def wrapper(*args, **kwargs):
Thread(target=fn, args=args, kwargs=kwargs).start()
return wrapper
class FileManager:
FileRoot = "~/FileManager/"
lock = Lock()
def __init__(self, logger):
self.logger = logger
mt.dir_check(self.FileRoot)
self.fail_list = []
@async_call
def infer_screenshots(self, input_url_list, dir_name):
print('Start infer_screenshots. ')
target_dir = mt.OS_join(self.FileRoot, dir_name)
mt.dir_check(target_dir)
cur_img_list = mt.glob_recursively(target_dir, 'jpg')
stem_list = mt.get_list_from_list(cur_img_list, lambda x: mt.get_path_stem(x))
tar_list = []
for input_url in input_url_list:
md5_str = mt.md5(input_url)
if md5_str not in stem_list:
if input_url not in self.fail_list:
tar_list.append(input_url)
try:
self.screen_shot(tar_list, target_dir)
except Exception as e:
print(e)
print('Finish infer_screenshots. ')
def screen_shot(self, url_list, save_dir):
time.sleep(2)
options = webdriver.ChromeOptions()
options.add_argument("--no-sandbox")
driver = webdriver.Chrome(chrome_options=options)
width = int(1024)
height = int(768)
driver.set_window_size(width, height)
driver.set_page_load_timeout(10)
for url in mt.tqdm(url_list):
print(url)
try:
driver.get(url)
md5_str = mt.md5(url)
self.logger(driver.title)
img_path = mt.OS_join(save_dir, md5_str '.jpg')
time.sleep(5) # 延迟截图
driver.get_screenshot_as_file(img_path) # 保存截图
except Exception as e:
self.fail_list.append(url)
self.logger(e)
driver.close() # 关闭浏览器
driver.quit()
- 主要逻辑为获取 url 列表,挑出本地没有存到的图像,开启 异步执行 网页截图 保存到本地的工作
- 把获取不到的放到一个躺平列表里,之后再见到这个链接直接放弃
- 过程中保存日志
网址的 md5 字符串
- 由于网址可能出现千奇百怪的字符,为了统一并且不会碰撞,采用将网址字符串转换为 md5 字符串的方法
- 使用 Python 和 JS 中实现 md5 的函数/包完成转换
前端
- 用 ejs 模板语法与 js MD5 拼接出 MD5 图像链接
<script src="https://101.43.39.125/HexoFiles/js/md5/md5.min.js"> </script>
<img src='<%- theme.vvd_local_links.screecshot_prefix %><%- md5(link_info.link) %>.jpg' alt="<%- link_info.name %>" onerror="this.onerror=null; this.src=this.srcset='<%- theme.vvd_local_links.lost_page %>'">
后端
- Python 实现 md5
import hashlib
m = hashlib.md5('test'.encode(encoding='utf-8')).hexdigest()
nginx 反向代理提供 https 链接
- 用之前 Nginx 的 docker 为本地端口映射出 https 协议的对外端口
设置系统开机自动启动服务
ubuntu selenium chromedriver 网页截图需要 xvfb
创建 shell 脚本
代码语言:javascript复制#!/bin/bash
Xvfb :99 -ac -screen 0 1280x1024x24 &
export DISPLAY=:99
/path-to-python /path-to-your-python-script.py
创建 systemctl 服务文件
代码语言:javascript复制Description = Service to site image for www.zywvvd.com
After = network.target
[Service]
ExecStart = /usr/bin/bash run_fm.sh
WorkingDirectory = /your-workspace
StandardOutput = inherit
StandardError = inherit
Restart = always
User = lighthouse
[Install]
WantedBy=multi-user.target
设置开机启动
代码语言:javascript复制sudo systemctl enable <your-service-name>.service
保存截图
在保存文件的目录下可以看到保存的截图文件
代码语言:javascript复制FileManager$ ls screenshots/
33a74bc3a5d45da92630a8fc22b24e53.jpg 82e4d834406a37981f2c701a362ac814.jpg cb88ee5fdb88a8e5ef7fc5c001d42d17.jpg
56ad8422f9b9c0bbca264e7f6994e4c1.jpg 8e120cf7f45cc0e217c547280c597acf.jpg e81c1f5749545c5f7d247b3a100ffe62.jpg
73cac8a8906097ccc1c98b92213edaf6.jpg c2e0ee8b940ec3d3da9cacb40a0dad75.jpg
参考资料
- https://www.zywvvd.com/notes/tools/selenium-screenshot/ubuntu-selenium-chrome/ubuntu-selenium-chrome/
- https://cloud.tencent.com/developer/article/2220508
- https://cloud.tencent.com/developer/article/2067307
- https://cloud.tencent.com/developer/article/2345866
- https://cloud.tencent.com/developer/article/2220515
- https://cloud.tencent.com/developer/article/2220506
- https://cloud.tencent.com/developer/article/2067465
- https://cloud.tencent.com/developer/article/2067390
- https://www.zywvvd.com/notes/system/linux/commands/systemd/systemd_practice/