One step: Use Python to capture PC screenshots and automatically send emails to achieve screen monitoring

In the current digital world, automation has become a key part of our daily lives and work. It not only improves efficiency, but also saves a lot of time and energy. In this article, we will explore how to use Python to implement a specific automation task - automatically sending PC screenshots to a specified email address.

This task may seem complicated, but with Python, we can break it down into simple steps and implement them one by one. First, we need a tool that can capture screenshots. Second, we need a service that can send emails. Finally, we need to combine these two steps and create a script that can automate these tasks.

In this article, we will detail this process and provide corresponding Python code examples. Whether you are a Python beginner or an experienced developer looking for a new automation project, you can benefit from it. let's start.

The main function

1. Take screenshots by using pyautogui library.

2. Use smtplib library to send emails to send screenshots to recipients.

3. Use the tkinter library to create a simple graphical user interface (GUI) for configuring the application's settings.

4. Record logs by using the logging library and save the logs to files.

5. Use the configparser library to read and save the application's configuration settings.

6. The automatic startup function is implemented, and the application can be set to automatically start at startup.

7. Implemented the function of hiding and showing application windows.

8. The receiving email address is equal to the sending email address by default.

In addition, the code also implements some other functions, such as data encryption and decryption, deletion of sent screenshot files, etc.

The application provides users with a convenient way to take screenshots regularly and send the screenshots to designated recipients. It is suitable for monitoring, remote monitoring and other scenarios that require regular screenshots. Users can set the interval between screenshots, the number of screenshots, the email addresses of the sender and recipient, etc. through the graphical interface.

specific code

# coding=utf-8 
'''
 @Author  : TesterRoad
 @Time    : 2023/7/9 15:43
 @Desc    : 用python实现PC屏幕截图自动发送邮箱
 @Software: PyCharm
'''
import smtplib
import time
import pyautogui
from email.mime.multipart import MIMEMultipart
from email.mime.image import MIMEImage
from email.mime.text import MIMEText
import logging
import configparser
import os
import sys
import ctypes
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
import base64

import tkinter as tk
from tkinter import ttk
import datetime
import threading
import winreg
import glob

KEY = b'MySuperSecretKey'


def encrypt_data(data):
    cipher = AES.new(KEY, AES.MODE_CBC)
    ct_bytes = cipher.encrypt(pad(data.encode('utf-8'), AES.block_size))
    iv = base64.b64encode(cipher.iv).decode('utf-8')
    ct = base64.b64encode(ct_bytes).decode('utf-8')
    return iv + ct


def decrypt_data(data):
    try:
        iv = base64.b64decode(data[:24])
        ct = base64.b64decode(data[24:])
        cipher = AES.new(KEY, AES.MODE_CBC, iv=iv)
        pt = unpad(cipher.decrypt(ct), AES.block_size)
        return pt.decode('utf-8')
    except:
        return "Decryption Error!"


class ScreenshotApp:
    def __init__(self):
        self.root = tk.Tk()
        self.root.title("Screen")

        self.config = configparser.ConfigParser()
        self.config_file = os.path.join(os.path.dirname(os.path.abspath(sys.argv[0])), "config.ini")

        if not os.path.exists(self.config_file):
            self.create_default_config()

        self.config.read(self.config_file)  # 读取配置文件

        self.sender_email_label = ttk.Label(self.root, text="发件邮箱:")
        self.sender_email_label.grid(row=0, column=0, padx=5, pady=5)
        self.sender_email_entry = ttk.Entry(self.root)
        self.sender_email_entry.grid(row=0, column=1, padx=5, pady=5)

        self.sender_password_label = ttk.Label(self.root, text="发件邮箱密码:")
        self.sender_password_label.grid(row=1, column=0, padx=5, pady=5)
        self.sender_password_entry = ttk.Entry(self.root, show="*")
        self.sender_password_entry.grid(row=1, column=1, padx=5, pady=5)

        self.interval_label = ttk.Label(self.root, text="截图间隔时间:")
        self.interval_label.grid(row=2, column=0, padx=5, pady=5)
        self.interval_entry = ttk.Entry(self.root)
        self.interval_entry.grid(row=2, column=1, padx=5, pady=5)

        self.count_label = ttk.Label(self.root, text="发送截图数量:")
        self.count_label.grid(row=3, column=0, padx=5, pady=5)
        self.count_entry = ttk.Entry(self.root)
        self.count_entry.grid(row=3, column=1, padx=5, pady=5)

        self.start_button = ttk.Button(self.root, text="开始截图", command=self.start_screenshot)
        self.start_button.grid(row=4, column=0, padx=5, pady=5)

        self.stop_button = ttk.Button(self.root, text="停止截图", command=self.stop_screenshot)
        self.stop_button.grid(row=4, column=1, padx=5, pady=5)
        self.stop_button.configure(state="disabled")

        self.save_button = ttk.Button(self.root, text="save", command=self.save_settings)
        self.save_button.grid(row=5, column=0, padx=5, pady=5)

        self.autostart_var = tk.BooleanVar()
        self.autostart_checkbutton = ttk.Checkbutton(self.root, text="开机自动启动", variable=self.autostart_var,
                                                     command=self.save_settings)
        self.autostart_checkbutton.grid(row=6, column=0, columnspan=2, padx=5, pady=5)

        self.toggle_visibility_button = ttk.Button(self.root, text="显示/隐藏", command=self.toggle_visibility)
        self.toggle_visibility_button.grid(row=7, column=0, columnspan=2, padx=5, pady=5)

        # 创建日志记录器
        self.log_file_path = os.path.join(os.path.dirname(os.path.abspath(sys.argv[0])), "screenshot.log")
        self.logger = logging.getLogger("ScreenshotApp")
        self.logger.setLevel(logging.INFO)
        self.logger.addHandler(logging.FileHandler(self.log_file_path))

        self.screenshot_running = False
        self.screenshot_thread = None
        self.stop_event = threading.Event()

        # 初始化输入框的值
        self.sender_email_entry.insert(0, self.config.get("Settings", "sender_email", fallback=""))
        self.sender_password_entry.insert(0, self.get_decrypted_password())
        self.interval_entry.insert(0, self.config.get("Settings", "interval", fallback=""))
        self.count_entry.insert(0, self.config.get("Settings", "count", fallback=""))

        # 初始化开机自动启动选项
        self.autostart_var.set(self.is_autostart_enabled())

        self.root.protocol("WM_DELETE_WINDOW", self.on_close)

        self.root.bind("<F12>", self.toggle_visibility)

        # 初始化窗口可见性
        visibility = self.config.get("Settings", "visibility", fallback="visible")
        if visibility == "hidden":
            self.root.withdraw()

        if self.autostart_var.get():
            self.start_screenshot()

        self.root.mainloop()

    def on_close(self):
        self.stop_screenshot()
        self.save_settings()
        self.delete_screenshots()
        self.root.quit()

    def create_default_config(self):
        if not os.path.exists(self.config_file):
            self.config["Settings"] = {
                "sender_email": "",
                "sender_password": "",
                "interval": "",
                "count": "",
                "autostart": "False",
                "visibility": "visible"
            }

        config_file_path = os.path.join(os.path.dirname(os.path.abspath(sys.argv[0])), "config.ini")
        with open(config_file_path, "w") as configfile:
            self.config.write(configfile)

    def start_screenshot(self):
        interval_text = self.interval_entry.get()
        count_text = self.count_entry.get()

        if not interval_text or not count_text:
            self.logger.error("请提供Screen间隔时间和Screen次数")
            return

        try:
            interval = int(interval_text)
            count = int(count_text)
        except ValueError:
            self.logger.error("Screen间隔时间和Screen次数必须是有效的整数")
            return
        if not self.screenshot_running:
            sender_email = self.sender_email_entry.get()
            sender_password = self.sender_password_entry.get()
            interval = int(self.interval_entry.get())
            count = int(self.count_entry.get())

            receiver_email = sender_email  # 收件邮箱地址默认等于发件邮箱地址

            self.logger.info("开始Screen")

            self.start_button.configure(state="disabled")
            self.stop_button.configure(state="normal")
            self.screenshot_running = True
            self.stop_event.clear()

            self.screenshot_thread = threading.Thread(target=self.screenshot_loop, args=(
            receiver_email, sender_email, sender_password, interval, count))
            self.screenshot_thread.start()

    def stop_screenshot(self):
        if self.screenshot_running:
            self.screenshot_running = False
            self.stop_event.set()
            self.screenshot_thread.join()

            self.logger.info("停止Screen")
            self.start_button.configure(state="normal")
            self.stop_button.configure(state="disabled")

    def screenshot_loop(self, receiver_email, sender_email, sender_password, interval, count):
        screenshot_count = 0
        screenshots = []

        # 获取用户主目录,并创建'Screenshots'文件夹
        user_dir = os.path.expanduser('~')
        screenshot_dir = os.path.join(user_dir, 'Screenshots')
        os.makedirs(screenshot_dir, exist_ok=True)

        # 在开始Screen前清空'Screenshots'文件夹
        self.delete_screenshots()

        while screenshot_count < count and not self.stop_event.is_set():
            try:
                # Screen
                screenshot = pyautogui.screenshot()

                # 生成文件名,格式为“Screen时间.png”
                current_time = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
                filename = f"Screen_{current_time}.png"

                # 保存Screen到'Screenshots'文件夹中
                screenshot_path = os.path.join(screenshot_dir, filename)
                screenshot.save(screenshot_path)
                screenshots.append(screenshot_path)
                screenshot_count += 1
                # 设置文件为隐藏
                FILE_ATTRIBUTE_HIDDEN = 0x02
                ctypes.windll.kernel32.SetFileAttributesW(screenshot_path, FILE_ATTRIBUTE_HIDDEN)
                self.logger.info(f"Screen成功: {screenshot_path}")

                if screenshot_count == count:  # 达到指定Screen次数后发送Screen
                    screenshot_count = 0
                    self.send_email(receiver_email, sender_email, sender_password, screenshots)
                    self.logger.info(f"Screen发送成功,共发送了 {len(screenshots)} 张Screen")
                    self.delete_screenshots(screenshots)
                    screenshots = []  # 清空已发送的Screen列表
            except Exception as e:
                self.logger.error(f"Screen失败: {str(e)}")

            time.sleep(interval)

    def send_email(self, receiver_email, sender_email, sender_password, filenames):
        msg = MIMEMultipart()
        msg["From"] = sender_email
        msg["To"] = receiver_email
        msg["Subject"] = "Screen"

        # 添加邮件正文
        msg.attach(MIMEText("请查看附件中的Screen。", "plain"))

        # 添加Screen作为附件
        for filename in filenames:
            with open(filename, "rb") as f:
                image = MIMEImage(f.read())
            image.add_header('Content-Disposition', 'attachment', filename=os.path.basename(filename))
            msg.attach(image)

        try:
            # 发送邮件
            with smtplib.SMTP_SSL("smtp.qq.com", 465) as smtp:
                smtp.login(sender_email, sender_password)
                smtp.send_message(msg)

            self.logger.info(f"邮件发送成功,收件人: {receiver_email}")

        except Exception as e:
            self.logger.error(f"邮件发送失败: {str(e)}")

    def save_settings(self):

        self.config.set("Settings", "sender_email", self.sender_email_entry.get())
        self.config.set("Settings", "interval", self.interval_entry.get())
        self.config.set("Settings", "count", self.count_entry.get())
        self.config.set("Settings", "autostart", str(self.autostart_var.get()))

        visibility = "visible" if self.root.state() == "normal" else "hidden"
        self.config.set("Settings", "visibility", visibility)

        if self.sender_password_entry.get() != self.get_decrypted_password():
            encrypted_password = encrypt_data(self.sender_password_entry.get())
            self.config.set("Settings", "sender_password", encrypted_password)

        config_file_path = os.path.abspath(self.config_file)
        with open(config_file_path, "w") as configfile:
            self.config.write(configfile)
            self.logger.handlers.clear()
            self.logger.addHandler(logging.FileHandler(self.log_file_path))

        self.set_autostart(self.autostart_var.get())

    def delete_screenshots(self, filenames=None):
        # 获取'Screenshots'文件夹路径
        user_dir = os.path.expanduser('~')
        screenshot_dir = os.path.join(user_dir, 'Screenshots')

        if filenames is None:
            filenames = glob.glob(os.path.join(screenshot_dir, "Screen*.png"))

        for filename in filenames:
            try:
                os.remove(filename)
                self.logger.info(f"删除Screen: {filename}")
            except Exception as e:
                self.logger.error(f"删除Screen失败: {str(e)}")

    def get_decrypted_password(self):
        encrypted_password = self.config.get("Settings", "sender_password", fallback="")
        if encrypted_password:
            return decrypt_data(encrypted_password)
        else:
            return ""

    def toggle_visibility(self, event=None):
        if self.root.state() == "withdrawn":
            self.root.deiconify()
        else:
            self.root.withdraw()
        self.save_settings()

    def set_autostart(self, enabled):
        key = winreg.HKEY_CURRENT_USER
        run_key = r"Software\Microsoft\Windows\CurrentVersion\Run"
        app_name = "Screen"
        app_path = sys.executable  # 获取当前脚本的绝对路径

        try:
            with winreg.OpenKey(key, run_key, 0, winreg.KEY_SET_VALUE) as reg_key:
                if enabled:
                    winreg.SetValueEx(reg_key, app_name, 0, winreg.REG_SZ, app_path)
                    self.logger.info("已设置开机自动启动")
                else:
                    winreg.DeleteValue(reg_key, app_name)
                    self.logger.info("已取消开机自动启动")
        except FileNotFoundError as e:
            self.logger.error(f"找不到注册表路径: {str(e)}")
        except PermissionError as e:
            self.logger.error(f"没有足够的权限访问注册表: {str(e)}")
        except Exception as e:
            self.logger.error(f"设置开机自动启动失败: {str(e)}")

    def is_autostart_enabled(self):
        key = winreg.HKEY_CURRENT_USER
        run_key = r"Software\Microsoft\Windows\CurrentVersion\Run"
        app_name = "Screen"
        app_path = sys.executable  # 获取当前脚本的绝对路径

        try:
            with winreg.OpenKey(key, run_key, 0, winreg.KEY_READ) as reg_key:
                try:
                    value, value_type = winreg.QueryValueEx(reg_key, app_name)
                    return value == app_path
                except FileNotFoundError:
                    return False
        except FileNotFoundError as e:
            self.logger.error(f"找不到注册表路径: {str(e)}")
        except PermissionError as e:
            self.logger.error(f"没有足够的权限访问注册表: {str(e)}")
        except Exception as e:
            self.logger.error(f"读取开机自动启动设置失败: {str(e)}")

        return False


if __name__ == "__main__":
    app = ScreenshotApp()

Open CMD and enter python ScreenCaptureSendEmail.py

picture

We enter the sending email address, the sending email password (QQ email is the authorization code), the screenshot interval, the number of screenshots sent, and then click to start taking screenshots. We will receive a QQ email later.

As shown below

picture

picture

In this article, we discuss in detail how to use Python to implement the function of taking PC screenshots and automatically sending them to email. We explored the use of related libraries. And by writing actual code, we demonstrate step by step how to put these features together. I hope this article can help you make progress in automating tasks and improving work efficiency. If you encounter any problems during practice or have any suggestions, please feel free to communicate with me. Remember, programming is the art of problem solving, and you can master it better through continuous learning and practice.

Finally, I would like to thank everyone who reads my article carefully. Reciprocity is always necessary. Although it is not a very valuable thing, if you can use it, you can take it directly:

Insert image description here

This information should be the most comprehensive and complete preparation warehouse for [software testing] friends. This warehouse has also accompanied tens of thousands of test engineers through the most difficult journey. I hope it can also help you!  

Guess you like

Origin blog.csdn.net/nhb687095/article/details/133078077