Python实战 任务计划程序部署 网页抓取+VBA宏调用

#避坑总结#

1.项目文件构成

sample.bat --批处理文件

sample.py  --执行文件

运行顺序

任务计划程序->sample.bat->sample.py

2.批处理文件完整示例:

@echo off

echo %date% %time% %username% >> c:\log.txt

REM 设置正确的用户名和密码
set your_username=域账户
set your_password=域账户密码

REM 建立网络连接
net use \\服务器\文件名 /user:%your_username% %your_password%

cd /d "C:\Users\admin\PycharmProjects\pythonProject\venv\"

python selenium_bw.py 1>>c:\log.txt 2>>&1

REM 断开网络连接(可选)
REM net use \\服务器\文件名 /delete

echo %date% %time% >> c:\log.txt

2-坑1:批处理文件访问网络服务器资源,需要先建立连接

通过CMD命令窗口或双击运行Bat批处理程序,可以访问正常执行。

通过任务计划程序访问域服务器的资源文件,需要建立网络连接,输入域账户和密码,才能访问。

REM 设置正确的用户名和密码
set your_username=域账户
set your_password=域账户密码

REM 建立网络连接
net use \\服务器\文件名 /user:%your_username% %your_password%

REM 断开网络连接(可选)
REM net use \\服务器\文件名 /delete

3.Python文件完整示例:

完成内容:1.从指定网站下载文件 2.执行数据编辑 3.发送邮件

import time
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import cv2
import os
import shutil
import datetime
import win32com.client
import io

import sys
sys.stdout = io.TextIOWrapper(sys.stdout.buffer,encoding='gb18030')

def login_and_process():
    for _ in range(3):  # Try执行3次
        try:
            ###############图形模式##################
            #browser = webdriver.Chrome()
            #browser.maximize_window()

            ###############无界模式##################
            options = webdriver.ChromeOptions()
            # 无界面模式
            #options.add_argument('--headless=new')
            options.add_argument('--disable-web-security')
            options.add_argument('--safebrowsing-disable-download-protection')
            options.add_argument('--allow-running-insecure-content')
            options.add_argument('--allow-cross-origin-auth-prompt')    
            # 最大化窗口
            options.add_argument('--start-maximized')
            options.add_argument('--ignore-certificate-errors')
            
            options.add_experimental_option("prefs", {
                              "download.default_directory": r"C:\Users\admin\Downloads",
                              "download.prompt_for_download": False,
                              "download.directory_upgrade": True,
                              "safebrowsing.enabled": False
            })

            browser = webdriver.Chrome(options=options)
            ####################################
            # 登录BW首页
            browser.get('http://xxxx.xxxx.com/portal?j_username=用户名&j_password=密码')
            time.sleep(3)

            # 尝试找到收藏夹按钮并点击
            favorite_link_xpath = "//li[@id='Favorites_HyperLink']/*[contains(@title,'收藏夹')]"
            browser.find_element('xpath', favorite_link_xpath)

            # 定义按钮名称和对应的XPATH
            buttons = {
                '第一个超链接': "//tr[@class='PopUpMenuItemRow'][contains(@title,'第一个超链接')]",
                '第二个超链接': "//tr[@class='PopUpMenuItemRow'][contains(@title,'第二个超链接')]",
                '第三个超链接': "//tr[@class='PopUpMenuItemRow'][contains(@title,'第三个超链接')]",   
            }

            for button_name, button_xpath in buttons.items():
                time.sleep(3)
                browser.find_element('xpath', favorite_link_xpath).click()
                time.sleep(1)
                # 打开对应的报表链接
                browser.find_element('xpath', button_xpath).click()
                # 等待1秒钟以确保页面刷新
                time.sleep(1)

                # 读取目标按钮图像
                target_image = cv2.imread(r"C:\Users\admin\Desktop\export.bmp", cv2.IMREAD_GRAYSCALE)

                while True:
                    # 保存屏幕截图
                    browser.save_screenshot("screenshot.png")

                    # 在屏幕截图中查找目标按钮位置
                    screenshot = cv2.imread("screenshot.png", cv2.IMREAD_GRAYSCALE)
                    result = cv2.matchTemplate(screenshot, target_image, cv2.TM_CCOEFF_NORMED)
                    min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
                    threshold = 0.8  # 设置匹配阈值

                    if max_val >= threshold:
                        # 如果找到了按钮
                        # 执行35次Tab键操作
                        for i in range(36):
                            # 找到当前焦点所在的元素
                            current_element = browser.switch_to.active_element

                            # 将焦点移到下一个元素
                            current_element.send_keys(Keys.TAB)

                            # 等待一段时间,以便观察效果
                            time.sleep(1) 
                            # 判断是否是最后一次循环
                            if i == 35:
                               # 最后一次循环,发送 Enter 键
                               print("找到了,开始点击...")
                               current_element.send_keys(Keys.ENTER)

                        # 等待下载完成
                        time.sleep(6)
                        print("下载完成...")
                        break
                    else:
                        # 如果没有找到按钮
                        time.sleep(2)
                        print("未找到按钮,继续查找...")

            browser.quit()
            break
        except Exception as e:
            print("登录或处理出错:", e)
            browser.quit()
            time.sleep(5)

    print("完成,退出程序")


def copy_and_move_files():
    print("开始Copy&Move")
    try:
       # 源文件夹路径
        source_folder = r"C:\Users\admin\Downloads"

        # 备份文件夹路径 
        backup_folder = r"C:\bak"

        # 目标文件夹路径
        target_folder = r"\\服务器名\文件名\targetfolder"

        # 获取当日日期
        today_date = datetime.datetime.now().strftime("%Y%m%d")
        print(today_date)
        # 判断是否有5个文件以0ANALYSIS开头
        source_files = [f for f in os.listdir(source_folder) if f.startswith('0ANALYSIS')]
        if len(source_files) == 5:
          # 创建以当日日期为名字的文件夹
          target_folder_today = os.path.join(backup_folder, today_date)
          os.makedirs(target_folder_today, exist_ok=True)

        # 复制文件到当日日期文件夹
        for filename in source_files:
            source_file = os.path.join(source_folder, filename)
            shutil.copy(source_file, target_folder_today)

        # 移动文件到服务器文件夹
        for filename in source_files:
            source_file = os.path.join(source_folder, filename)
            target_file = os.path.join(target_folder, filename)
            shutil.move(source_file, target_file)

    except Exception as e:
        print("复制和移动处理出错:", e)
        time.sleep(5)
    print("复制和移动完成")

def run_excel_macro():
    try:
        file_path = r"C:\autorun\autotest.xlsm"
        macro_name1 = "ThisWorkbook.macro1"
        macro_name2 = "ThisWorkbook.macro2"


        # 初始化 Outlook 应用程序
        appOutlook = win32com.client.Dispatch("Outlook.Application")
	
        excel = win32com.client.Dispatch("Excel.Application")
        excel.Visible = False  # 设置 Excel 不可见
        wb = excel.Workbooks.Open(file_path)
        excel.Application.Run(macro_name1)
        print("macro1运行完成")
        excel.Application.Run(macro_name2)
        print("macro2运行完成")  

    except Exception as e:
        print("异常错误:", e)
    finally:
       # if 'wb' in locals():
        #    wb.Close(SaveChanges=False)  # 关闭文件,不保存
        if 'excel' in locals():
            excel.Quit()  # 退出 Excel
            excel = None
        # 关闭 Outlook 应用程序
        appOutlook.Quit()
        # 释放对象
        appOutlook = None
		
def main():
    try:
        login_and_process()
        copy_and_move_files()
        run_excel_macro()
    except Exception as e:
        print("程序执行过程中出现异常:", e)

if __name__ == "__main__":
    main()

3.坑2:任务计划程序执行Selenium模拟webdriver,需要无界/无头模式运行

任务计划程序模式下,无法正常启动Chrome浏览器,可以通过 --headless=new的Option设置,隐藏Chrome实现启动Chrome,在隐藏模式下,通过Selenium模拟键盘的操作不受影响。

###############无界模式##################
            options = webdriver.ChromeOptions()
            # 无界面模式
            options.add_argument('--headless=new')
            options.add_argument('--disable-web-security')
            options.add_argument('--safebrowsing-disable-download-protection')
            options.add_argument('--allow-running-insecure-content')
            options.add_argument('--allow-cross-origin-auth-prompt')    
            # 最大化窗口
            options.add_argument('--start-maximized')
            options.add_argument('--ignore-certificate-errors')
            
            options.add_experimental_option("prefs", {
                              "download.default_directory": r"C:\Users\admin\Downloads",
                              "download.prompt_for_download": False,
                              "download.directory_upgrade": True,
                              "safebrowsing.enabled": False
            })

            browser = webdriver.Chrome(options=options)
####################################

3.坑3:点击“查看页面代码”获取不到的元素,需要通过Tab键操作

网页代码查看方式:网页任意位置,鼠标点击右键,选择查看页面源代码(如下图),查看控件的ID或者名称是否存在,如果不存在需要通过Tab键间接操作

3.坑4:页面加载完成,通过是否出现预期的按钮判断,比单纯设置等待时间精准高效

while True:
                    # 保存屏幕截图
                    browser.save_screenshot("screenshot.png")

                    # 在屏幕截图中查找目标按钮位置
                    screenshot = cv2.imread("screenshot.png", cv2.IMREAD_GRAYSCALE)
                    result = cv2.matchTemplate(screenshot, target_image, cv2.TM_CCOEFF_NORMED)
                    min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
                    threshold = 0.8  # 设置匹配阈值

                    if max_val >= threshold:
                        #找到了
                        break
                    else
                        #没找到,继续找

3.坑4:屏幕保护模式下,需要Selenium模拟键盘,无法使用Pyautogui点击操作

虽然手动可以启动Chrome完成页面点击操作,在屏保模式下,鼠标将失去焦点,无法完成点击操作,此时需要用到Selenium的模式键盘操作,完成点击操作。

# 从当前按钮开始,按10下Tab键,假设当前按钮顺序第一,希望点击按钮顺序在第11个
for i in range(11):
   current_element = browser.switch_to.active_element

   # 将焦点移到下一个元素
   current_element.send_keys(Keys.TAB)

   # 等待一段时间,以便观察效果
   time.sleep(1) 
   # 判断是否是最后一次循环
      if i == 10:
          # 最后一次循环,发送 Enter 键
          print("找到了,开始点击...")
          current_element.send_keys(Keys.ENTER)

3.坑5:解决Python执行Excel文件Open时,提示'gbk' codec can't encode character '\u2022'错误

import sys
sys.stdout = io.TextIOWrapper(sys.stdout.buffer,encoding='gb18030')

 3.坑6:任务计划程序模式下,需要创建Desktop文件夹才能打开Excel运行Macro宏

虽然手动可以运行Excel的Macro宏,但是windows任务计划出于安全机制,不允许自动运行Excel的Macro宏,需要通过以下设置回避。

C:\Windows\System32\config\systemprofile\Desktop
C:\Windows\SysWOW64\config\systemprofile\Desktop

 3.坑7:使用Google Chrome122之前的版本,可以解决“已阻止不安全的下载”的问题

随着Chrome版本的升级,会遇到之前可以下载,后续遇到无法下载的问题,这时需要卸载当前版本,安装122以前的版本,并关闭Chrome的升级更新,保证不被升级到最新版本。

修改注册表的值,如果没有项或值则新建

路径:计算机\HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Google\Chrome

RendererCodeIntegrityEnabled 的值设置为0

 

需要使用的ChromeDriver下载地址 

​​​​​​ChromeDriver - WebDriver for Chrome - Downloads (chromium.org)

解压之后的存放路径,和python.exe放在一起。

C:\Users\admin\AppData\Local\Programs\Python\Python39 

4.任务计划程序设置

远程服务器上创建计划任务,不要注销账户,直接关闭远程窗口,任务计划可以正常运行。

起始于:输入批处理文件的路径

程序或脚本:输入批处理文件名

勾选:使用最高权限运行,不管用户是否登录都要运行

 4.坑8:任务计划程序,Excel调用Outlook的方法

本案例python执行selenium需要使用最高权限运行,在此设定下无法启动Excel的VBA宏发送创建Outlook邮件实例。对应方案,创建两个计划任务,一个执行python提取数据,一个执行Excel的VBA加工和发送数据。以下为调用Excel的VBA示例

不需要勾选1:不管用户是否登录都要运行

不需要勾选2:使用最高权限运行

程序或脚本:"C:\Program Files\Microsoft Office\root\Office16\EXCEL.EXE"

添加参数:C:\autopsi\autotest.xlsm /e 

VBA相关代码

Sub Workbook_Open()
    Call sendmail    
    ThisWorkbook.Save
    If Workbooks.Count = 1 Then
        Application.Quit
    Else
        ThisWorkbook.Close
    End If
End Sub

Public Sub sendmail()
  strBody = "<span style=""font-family:MS UI Gothic"">" _
                     & "大家好:<br>" _
                     & "<br>" _
                     & "系统自动发信-无需回复</span>"
                      

    baseSubject = "测试邮件"

    'Outlook定义
    Set appOutlook = CreateObject("Outlook.Application")
    Dim objMail As Outlook.MailItem
    Set objMail = appOutlook.CreateItem(olMailItem)
    
     ' 收件人信息
    topath = xxxx@xx.xx

    With objMail
        .BodyFormat = olFormatHTML
        .Subject = baseSubject
        .HTMLBody = strBody
        .To = topath
        .Send
    End With


    '释放对象
    Set objMail = Nothing

End Sub

5.Python运行环境配置

根据Python中使用import导入的库,需要通过CMD命令依次进行安装

不用pyinstaller --onefile sample.py生成exe的原因,python.exe直接运行py文件比运行打包的exe文件速度快,提高调试速度。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值