0x01 前言

在某些直播中计划进行抽奖活动,参加活动就得先报名,统计报名人员的信息是一个非常繁琐的工作。对于“懒到出汁”的我来说,手动统计是不可能的,这辈子都不可能的。

最近一次抽奖活动将在11号的直播中进行,而报名工作在我写这篇文章前就已经结束了,详细规则和其他内容请留意以下文章:

为了实现统计报名人数和“懒”的基本需求,我特意写了一个渣渣的python脚本。

0x02 思路与准备

为了方便使用脚本统一处理报名邮件,我针对我的实际情况制定了报名规则。需要编写标题格式如下的邮件并发送到指定的邮箱:

然后在邮件系统中新建一个文件夹用于存放报名邮件,还需要利用电子邮箱的自动规则功能识别邮件标题,并自动将报名邮件移动至该文件夹中。

因为我用的是office 365,所以这一切只需要在outlook中配置即可:

为了能通过脚本获取邮件,还需要开通邮箱系统的imap协议,以便通过imap协议登入邮件系统。

准备好之后即可开始编写脚本。

0x03 脚本

0x03.1 配置文件

首先需要准备配置文件,文件内容如下:

配置文件中包含电子邮箱的基本信息,因为我用的是office 365服务,所以信息如上。

还需要指定邮件标题的前缀,方便脚本中调用以便核查是否符合相关报名要求。最后是奖品类型的数量,这个数量的详情可以查看这次抽奖规则的文章。

0x03.2 定义基本信息

脚本一开始是读取配置文件并将相关信息赋值给变量,方便后面的函数调用。

这个脚本需要用到email和imaplib这两个模块,imaplib主要实现与邮件服务器的imap通讯;而email则负责处理邮件内容。

首先调用imaplib模块登入邮件服务器,并获取邮箱文件夹列表,赋值给变量:mail_folder。如果邮箱文件夹的名称包含英文以外的文字,则会被编码,赋值的时候不需要解码,它输出什么就填写什么,如上所示。

0x03.3 获取邮件

电子邮件在文件夹中是有独一无二的编号的,而且这编号是自动增长的,根据收到邮件的先后顺序自行分配,就算其中的邮件被删除也不会变更其他在此文件夹内的邮件的编号。

所以获取邮件的第一步需要向邮件服务器索取这个邮件id列表,相关函数如下:

有了邮件id,就可以通过id和文件夹名称向服务器拉去邮件主体:

一封邮件中包含的内容非常多,但我只需要邮件的内容、标题和发件人等信息。通过email.message_from_string函数可以很轻易地获取邮件不同部件的内容,然后加以处理即可得到我想需要的内容。

拉取邮件的时候需要注意的是,我的需求是拉取邮件的全部内容,在本地自行解析,这时候需要使用:

上面代码的意义为通过邮件的uid执行“fetch”命令,拉取该uid邮件的全部内容。

还有一种拉取邮件部分内容的方式:

通过这种方式可以减少数据的传输,比如需要拉取邮件的主题时,只需要拉取“Subject”即可,但在需要拉取多部份内容的情况下会导致请求次数过多,很久可能超过服务器的限制而导致脚本执行失败。

剩下的内容则是一些字符上的处理,没什么特别的。

0x03.4 文件存储与文件夹的建立

获取到邮件id列表后需要将最后的邮件id记录到一个临时文件中,当下次运行脚本时需要与之进行比对,以确认是否有新的邮件。

这个脚本本来是支持多个邮件文件夹的,为适配抽奖,我将大部分功能都删减了。但某些老旧的代码依然保留下来,下面的临时文件写入函数就是其中一个:

它会将传入的文件夹名称与邮件uid组合成字典的形式并写入临时文件中,内容格式如下:

本来我是计划将邮件保存功能一并删除的,但最后还是保留下来,以便日后查验邮件内容,以下是邮件内容的函数:

对数据保持一个简洁明了的文件夹结构是非常重要的,所以还针对数据存储路径做了简单规划:

以上代码会生成以下文件与目录结构:

0x03.5 uid的判断

拉取邮件前判断uid是否有效是非常重要的,可以避免重复性工作。以下是相关函数:

这里分3中情况:

  • 临时文件不存在:这说明从未进行过有效的邮件拉取动作,所以没有生成临时文件
  • 有临时文件但文件夹名称不在字典内:这说明之前进行过有效的拉取动作,但未拉取过当前的目标目录
  • 有临时文件且字典内有文件夹名称,且有与之对应的邮件id:这说明以前成功拉取过当前目标目录的邮件。

上面的函数会分别给三种不同的情况返还不同的内容,以便进行后续的工作。

0x03.6 邮件标题的格式化

在邮件源码内获取到邮件标题并不能直接使用,还需要对字符串进行处理:

我要求的邮件主题格式如下:

首先以“/”为元素对字符串进行分割,形成列表,然后判断列表的第一个元素是否与配置文件中“subj_prefix”的值相匹配,且列表共有3个元素。如果是则进一步处理,否则返还False,告知程序跳过这个邮件的处理流程。

当邮件主题符合要求后,会将第三个元素列表化,与第二个元素一起返还。

0x03.7 csv

逗号分隔文档–csv的格式是最简单的,直接写入到文本文档即可,以下函数就是干这工作的:

在写入之前需要组合每行的内容,通过遍历传入的奖品项目,然后将其转换为“True”和“False”即可。

接下来需要判断csv文件是否存在,如果不存在还需要组合首行内容,再和主要内容一起写入文件;如果文件存在则将主要内容写入即可。

写入后的内容如下图:

使用csv的一大好处是可以通过excel打开,打开后稍作修饰即可保存为excel的格式:

0x03.8 RUN

最后是run函数:

逻辑比较清晰,但是功能实现可能不太理想,主要是调用上面所说的各类函数。

0x04 结语

经过半天的调试,终于完成基本功能,估计以后的抽奖活动也会采用这种报名方式。在后续可能会增加实时展示功能,通过该功能可以将报名情况写入数据库,在前端显示。

生命在于折腾,其实我发现wordpress是由相关功能的插件的,但我就是不用!

通过我私有的gitlab可以找到最新的代码,还可以查看更新记录噢: