python实战学习记录

本次实战实现目标如下:

目录

1.抓取网页信息,获取对应内容

2.启用日志输出,实现信息记录

3.通过配置文件,实现脚本调用

4.完成qq邮箱发送自定义信息

5.实现热重启功能

6.部署到WinServer2012云服务器

7.部署到Linux云服务器


1.抓取网页信息,获取对应内容

get_daily_sentence.py

python 复制代码
import requests
from lxml import etree


def get_daily_sentence():
    url = 'https://dict.eudic.net/home/dailysentence/'

    try:
        # 发送请求
        headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
        }
        r = requests.get(url, headers=headers)
        r.raise_for_status()  # 检查请求是否成功

        # 解析 HTML
        html = etree.HTML(r.text)

        # 提取内容
        en_sentence = html.xpath('/html/body/div/div[2]/div[1]/div[2]/p[1]/text()')
        zh_translation = html.xpath('/html/body/div/div[2]/div[1]/div[2]/p[2]/text()')

        # 打印结果
        # if en_sentence and zh_translation:
        #     print("=" * 50)
        #     print("每日一句")
        #     print("=" * 50)
        #     print(f"英文: {en_sentence[0]}")
        #     print(f"中文: {zh_translation[0]}")
        #     print("=" * 50)
        # else:
        #     print("未找到每日一句内容,可能是XPath路径有变化")

        print(f"英文: {en_sentence[0]}")
        print(f"中文: {zh_translation[0]}")

    except requests.RequestException as e:
        print(f"请求出错: {e}")
    except Exception as e:
        print(f"处理出错: {e}")


if __name__ == "__main__":
    get_daily_sentence()

2.启用日志输出,实现信息记录

python 复制代码
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler('x:\\xx\\scheduler.log', encoding='utf-8'),
        logging.StreamHandler()
    ]
)

3.通过配置文件,实现脚本调用

4.完成qq邮箱发送自定义信息

(动态获取通过api文本信息)

python 复制代码
# """
# @Project :test
# @File :1029.py
# @IDE :PyCharm
# @Author :by202
# @Date :2025/10/29 11:16
# """
import requests
from lxml import etree
import smtplib
from email.mime.text import MIMEText
from email.utils import formataddr


url = 'https://dict.eudic.net/home/dailysentence/'
r = requests.get(url)
text = r.text
html = etree.HTML(text)
# enx = text.xpath('/html/body/div/div[2]/div[1]/div[2]/p[1]/text()')

en = html.xpath('/html/body/div/div[2]/div[1]/div[2]/p[1]/text()')
zh = html.xpath('/html/body/div/div[2]/div[1]/div[2]/p[2]/text()')
text = en[0] +"\n"+ zh[0]

print(text)
print(f"英文: {en[0]}")
print(f"中文: {zh[0]}")

# 通过qq邮箱进行发送
my_sender = '2@qq.com'  # 填写发信人的邮箱账号
my_pass = 'yjyqvdgea'  # 发件人邮箱授权码
my_user = '5@qq.com'  # 收件人邮箱账号
su_user = '1@qq.com' #抄送多人发送,在下面的sendmail方法中进行抄送即可

def mail():
    ret = True
    try:
        msg = MIMEText(text, 'plain', 'utf-8')  # 填写邮件内容
        # msg = MIMEText(zh[0], 'plain', 'utf-8')  # 填写邮件内容
        msg['From'] = formataddr(["tracy", my_sender])  # 括号里的对应发件人邮箱昵称、发件人邮箱账号
        msg['To'] = formataddr(["test", my_user])  # 括号里的对应收件人邮箱昵称、收件人邮箱账号
        msg['Subject'] = "发送邮件测试"  # 邮件的主题,也可以说是标题

        server = smtplib.SMTP_SSL("smtp.qq.com", 465)  # 发件人邮箱中的SMTP服务器
        server.login(my_sender, my_pass)  # 括号中对应的是发件人邮箱账号、邮箱授权码
        server.sendmail(my_sender, [my_user,su_user ], msg.as_string())  # 括号中对应的是发件人邮箱账号、收件人邮箱账号、发送邮件
        # server.sendmail(my_sender, [su_user, ], msg.as_string()) wu
        server.quit()  # 关闭连接
    except Exception:  # 如果 try 中的语句没有执行,则会执行下面的 ret=False
        ret = False
    return ret



ret = mail()
if ret:
    print("邮件发送成功")
else:
    print("邮件发送失败")

5.实现热重启功能

修改配置文件不需重启脚本

task_config.json

javascript 复制代码
{
  "tasks": [
    {
      "name": "发送邮件",
      "script_path": "C:\\test\\send_mail.py",
      "schedule": "00:00",
      "enabled": true
    },
    {
      "name": "发送邮件",
      "script_path": "E:\\test\\send_mail.py",
      "schedule": "14:52",
      "enabled": true
    }
  ]
}

main.py

python 复制代码
import schedule
import time
import subprocess
import json
import logging
from datetime import datetime
import os
import threading

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler('C:\\scripts\\scheduler.log', encoding='utf-8'),
        logging.StreamHandler()
    ]
)


class TaskScheduler:
    def __init__(self, config_file):
        self.config_file = config_file
        self.tasks = self.load_config()

    def load_config(self):
        """加载任务配置"""
        try:
            with open(self.config_file, 'r', encoding='utf-8') as f:
                return json.load(f)['tasks']
        except Exception as e:
            logging.error(f"加载配置文件失败: {e}")
            return []

    def run_script(self, script_path, task_name):
        """运行Python脚本 - 修复编码问题"""
        try:
            logging.info(f"开始执行任务: {task_name}")

            # 检查脚本文件是否存在
            if not os.path.exists(script_path):
                logging.error(f"脚本文件不存在: {script_path}")
                return

            # 设置环境变量,指定UTF-8编码
            env = os.environ.copy()
            env['PYTHONIOENCODING'] = 'utf-8'
            env['PYTHONUTF8'] = '1'

            # 使用subprocess运行脚本,指定编码
            result = subprocess.run(
                ['python', script_path],
                capture_output=True,
                text=True,
                timeout=300,  # 5分钟超时
                encoding='utf-8',
                errors='ignore',  # 忽略编码错误
                env=env
            )

            if result.returncode == 0:
                logging.info(f"任务完成: {task_name}")
                if result.stdout and result.stdout.strip():
                    # 限制输出长度,避免日志过大
                    output = result.stdout.strip()
                    if len(output) > 500:
                        output = output[:500] + "...(输出过长,已截断)"
                    logging.info(f"任务输出: {output}")
            else:
                logging.error(f"任务失败: {task_name}, 返回码: {result.returncode}")
                if result.stderr and result.stderr.strip():
                    error_output = result.stderr.strip()
                    if len(error_output) > 500:
                        error_output = error_output[:500] + "...(错误信息过长,已截断)"
                    logging.error(f"错误信息: {error_output}")

        except subprocess.TimeoutExpired:
            logging.error(f"任务超时: {task_name}")
        except FileNotFoundError:
            logging.error(f"Python解释器或脚本文件未找到: {script_path}")
        except Exception as e:
            logging.error(f"执行任务异常 {task_name}: {str(e)}")

    def run_script_safe(self, script_path, task_name):
        """安全运行脚本 - 在新线程中运行避免阻塞主线程"""

        def run_in_thread():
            self.run_script(script_path, task_name)

        thread = threading.Thread(target=run_in_thread, name=f"Task-{task_name}")
        thread.daemon = True  # 设置为守护线程
        thread.start()

    def setup_schedule(self):
        """设置定时任务"""
        for task in self.tasks:
            if not task['enabled']:
                continue

            script_path = task['script_path']
            task_name = task['name']
            schedule_time = task['schedule']

            # 检查脚本是否存在
            if not os.path.exists(script_path):
                logging.error(f"脚本文件不存在,跳过任务: {task_name} - {script_path}")
                continue

            # 每天固定时间执行
            schedule.every().day.at(schedule_time).do(
                self.run_script_safe, script_path, task_name
            )

            logging.info(f"已安排任务: {task_name} - 每天 {schedule_time}")

    def run(self):
        """运行调度器"""
        logging.info("任务调度器启动...")
        self.setup_schedule()

        logging.info("调度器运行中,按 Ctrl+C 退出...")

        while True:
            try:
                schedule.run_pending()
                time.sleep(30)  # 每30秒检查一次,减少CPU使用
            except KeyboardInterrupt:
                logging.info("调度器被用户中断")
                break
            except Exception as e:
                logging.error(f"调度器运行异常: {e}")
                time.sleep(60)


if __name__ == "__main__":
    scheduler = TaskScheduler("task_config.json")
    scheduler.run()

6.部署到WinServer2012云服务器

每日指定时间运行对应脚本

(winserver/centos,理论上主调度文件可通用)

效果6:

7.部署到Linux云服务器

使用crontab -e每日指定时间运行对应脚本

效果7.

在centos系统上进行测试

可以安装好python后进行虚拟环境创建

pip install requests,bs4,schedule......

更新-2025年11月13日

python 复制代码
# -*- coding: utf-8 -*-
import smtplib
import sys
import io
import requests
from lxml import etree
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.utils import formataddr
from datetime import datetime

# 设置标准输出编码为UTF-8
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8')

my_sender = '@qq.com'  # 填写发信人的邮箱账号
my_pass = 'a'  # 发件人邮箱授权码
my_user = '@qq.com'  # 收件人邮箱账号
jie = '@qq.com'



def get_daily_sentence():
    """获取每日英语句子"""
    try:
        url = 'https://dict.eudic.net/home/dailysentence/'
        headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
        }
        r = requests.get(url, headers=headers, timeout=10)
        r.encoding = 'utf-8'
        text = r.text
        html = etree.HTML(text)

        # 提取英文和中文句子
        en = html.xpath('/html/body/div/div[2]/div[1]/div[2]/p[1]/text()')
        zh = html.xpath('/html/body/div/div[2]/div[1]/div[2]/p[2]/text()')

        if en and zh:
            english_sentence = en[0].strip()
            chinese_sentence = zh[0].strip()
            return english_sentence, chinese_sentence
        else:
            return "No sentence found today.", "今日未找到句子。"

    except Exception as e:
        print(f"获取每日句子失败: {e}")
        return "Failed to get sentence.", "获取句子失败。"


def send_mail():
    ret = True
    try:
        # 获取每日句子
        english, chinese = get_daily_sentence()
        current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")

        # 创建邮件对象
        msg = MIMEMultipart('related')
        msg['From'] = formataddr(["每日英语", my_sender])
        msg['To'] = formataddr(["收件人", my_user,])
        msg['Subject'] = f"每日英语学习 {datetime.now().strftime('%Y-%m-%d')}"

        # 创建HTML内容
        html_content = f"""
        <!DOCTYPE html>
        <html>
        <head>
            <meta charset="utf-8">
            <style>
                body {{
                    font-family: 'Microsoft YaHei', Arial, sans-serif;
                    margin: 0;
                    padding: 0;
                    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
                    min-height: 100vh;
                }}
                .container {{
                    max-width: 600px;
                    margin: 0 auto;
                    background: white;
                    border-radius: 20px;
                    overflow: hidden;
                    box-shadow: 0 20px 40px rgba(0,0,0,0.1);
                    margin-top: 20px;
                    margin-bottom: 20px;
                }}
                .header {{
                    background: linear-gradient(135deg, #ff6b6b 0%, #feca57 100%);
                    color: white;
                    padding: 40px 30px;
                    text-align: center;
                }}
                .content {{
                    padding: 40px 30px;
                }}
                .sentence-en {{
                    font-size: 24px;
                    font-weight: bold;
                    color: #2c3e50;
                    line-height: 1.6;
                    text-align: center;
                    margin-bottom: 20px;
                    font-style: italic;
                }}
                .sentence-zh {{
                    font-size: 18px;
                    color: #7f8c8d;
                    line-height: 1.6;
                    text-align: center;
                    margin-bottom: 30px;
                }}
                .image-section {{
                    text-align: center;
                    margin: 30px 0;
                    padding: 20px;
                    background: linear-gradient(135deg, #a8edea 0%, #fed6e3 100%);
                    border-radius: 15px;
                }}
                .footer {{
                    text-align: center;
                    padding: 20px;
                    background: #34495e;
                    color: #bdc3c7;
                    font-size: 12px;
                }}
                .date {{
                    background: rgba(255,255,255,0.2);
                    display: inline-block;
                    padding: 8px 20px;
                    border-radius: 20px;
                    margin-top: 10px;
                    font-size: 14px;
                }}
                .emoji {{
                    font-size: 48px;
                    margin-bottom: 20px;
                }}
            </style>
        </head>
        <body>
            <div class="container">
                <div class="header">
                    <div class="emoji">📚</div>
                    <h1 style="margin:0; font-size: 32px;">每日英语学习</h1>
                    <div class="date">{current_time}</div>
                </div>

                <div class="content">
                    <div class="sentence-en">
                        "{english}"
                    </div>
                    <div class="sentence-zh">
                        {chinese}
                    </div>

                    <div class="image-section">
                        <h3 style="color: #333; margin-bottom: 20px;">🎉 坚持学习,每天进步!</h3>
                        <img src="https://staticv2.hi2future.com/upload/emotion/tsj/t_0034.gif" 
                             alt="Learning GIF" 
                             style="max-width: 200px; border-radius: 15px; border: 4px solid white; box-shadow: 0 8px 25px rgba(0,0,0,0.15);">
                        <p style="margin-top: 15px; color: #666; font-size: 14px;">每天一句英语,积累无限可能</p>
                    </div>
                </div>

                <div class="footer">
                    <p>📧 邮件为每日15点内时间段自动发出,来自九牧</p>
                    <p>🔔 如需拒收可联系发件人,或者拉入黑名单</p>
                    <p style="margin-top: 10px; opacity: 0.7;">&copy; {datetime.now().strftime('%Y')} 每日多邻国英语学习计划</p>
                </div>
            </div>
        </body>
        </html>
        """

        # 纯文本版本(备用)
        text_content = f"""
每日英语 - {datetime.now().strftime('%Y-%m-%d')}

英文句子:
{english}

中文翻译:
{chinese}

{'-' * 50}
邮件为每日15点自动发出,来自九牧
如需拒收可联系发件人,或者拉入黑名单
        """

        # 添加HTML内容
        msg.attach(MIMEText(html_content, 'html', 'utf-8'))
        # 添加纯文本内容(某些邮箱客户端可能不支持HTML时显示)
        msg.attach(MIMEText(text_content, 'plain', 'utf-8'))

        # 发送邮件
        server = smtplib.SMTP_SSL("smtp.qq.com", 465)
        server.login(my_sender, my_pass)
        server.sendmail(my_sender, [my_user,jie ], msg.as_string())
        server.quit()

        print(f"每日英语邮件发送成功 - {current_time}")
        print(f"英文: {english}")
        print(f"中文: {chinese}")
        return True

    except Exception as e:
        error_msg = f"邮件发送失败 - 错误信息: {str(e)}"
        print(error_msg)
        return False


if __name__ == "__main__":
    try:
        success = send_mail()
        sys.exit(0 if success else 1)
    except Exception as e:
        print(f"脚本执行异常: {str(e)}")
        sys.exit(1)
相关推荐
The_Second_Coming43 分钟前
Python 学习笔记:基础篇
运维·笔记·python·学习
思成不止于此1 小时前
软考中级软件设计师备考指南(二):计算机体系结构与指令系统
笔记·学习·软件设计师
AI松子6661 小时前
PyTorch-混合精度训练(amp)
人工智能·pytorch·python
MDLZH1 小时前
Pytorch性能调优简单总结
人工智能·pytorch·python
程序员爱钓鱼2 小时前
Python 编程实战 · 实用工具与库 — Flask 路由与模板
前端·后端·python
程序员爱钓鱼2 小时前
Python 编程实战 · 实用工具与库 — Django 项目结构简介
后端·python·面试
新之助小锅3 小时前
java版连接汇川PLC,发送数据,读取数据,保持重新链接,适用安卓
android·java·python
海琴烟Sunshine3 小时前
leetcode 383. 赎金信 python
python·算法·leetcode
say_fall4 小时前
C语言编程实战:每日刷题 - day2
c语言·开发语言·学习