【python】自动更新pu口袋校园活动

【python】自动更新pu口袋校园活动

 

脚本目标:

    1. 自动爬取pu口袋校园活动,筛选出需要的活动,此处我的筛选条件是线上活动,因为可以不用去就可以白嫖学时

    2. 自动发送邮件到QQ邮箱,每次只发送更新的活动,因为QQ邮箱的提醒可以在QQ里直接看到

    3. 挂在后台,不显示控制台

 

已知条件:

    1. pu口袋校园有网页版,可以直接登录,在网页上查看活动,和报名活动,所以可以写一个网页爬虫爬取数据

    2. pu口袋校园在查看活动列表的时候不需要cookie就可以看到,如果需要点进活动页面查看活动的具体内容需要cookie,而活动地点是在具体内容页面里的,所以需要准备一份cookie

    3. 整个网页没有反爬机制,不需要准备user-agent

    4. 判断线上活动的方式:活动地点为空

    5. 是服务器端渲染的网页,不需要用selenium

 

脚本思路:

    1. 写一个简单的网页爬虫,爬取页面源代码,提取其中活动的具体内容的url

    2. 爬取每个活动具体内容的源代码,筛选出活动地点为空的内容,将活动名称添加到列表

    3. 将第一次整理出来的列表为初始化的列表,每次更新先和之前的列表比对,筛选出来新的活动,作为一个列表

    4. 发送活动名称到QQ邮箱

 

代码实现:

  先把需要在后面用到的内容写在前面

 

obj = re.compile(".*? <span class=\"b1\">活动地点:</span><a title=\"(?P<area>.*?)\">")
obj2 = re.compile(".*?<title>(?P<name>.*?)</title>")
header = {"Cookie": "TS_LOGGED_USER=-kowQgrvPgFq4iqGji4hPA5vH; PHPSESSID=51fb2a5a61c010f0465d0; Hm_lvt_dd3ea352543392a029ccf9da1be54a50=1639667636,1639918552,1639977234; TS_think_language=zh-CN; Hm_lpvt_dd3ea352543392a029ccf9da1be54a50=1639994037"}

 

  这个链接点开可以得到活动列表页面https://xxx.pocketuni.net/index.php?app=event&mod=School&act=board&cat=all&&p=1

  我选择爬取前面八页的活动列表,返回八页活动列表的链接

def get_page_url():
    url_list=[]
    for num in range(1,8+1):
        url = f"https://xxx.pocketuni.net/index.php?app=event&mod=School&act=board&cat=all&&p={num}"
        url_list.append(url)
    return url_list

   

  这个函数用来请求八页活动列表的页面源代码,并且得到每个活动具体内容的网页地址,用xpath解析,返回具体活动内容的链接

def handle(url_list):
    child_url=[]
    for url in url_list:
        resp = requests.get(url)
        resp.close()
        resp_tree=etree.HTML(resp.text)
        child_url.extend(resp_tree.xpath("/html/body/div[2]/div/div[3]/div[2]/div[1]/ul/li/div[2]/div[1]/a/@href"))
    return child_url

  

  这个函数用来请求所有,活动具体内容的源代码,并且用正则表达式筛选出活动地点和活动名称,将活动地点为空所对应的活动名称添加到active_name_list的列表里,返回符合条件的活动名称

def handle2(child_urls):
    x=1
    active_name_list=[]
    for url in child_urls:
        resp = requests.get(url,headers=header)
        resp.close()
        active_area = str(obj.findall(resp.text)).replace("[","").replace("]","").replace("'","").replace(" ","")
        active_name = str(obj2.findall(resp.text)).replace("[","").replace("]","").replace("'","").replace(" ","")
        if active_area =='':
            active_name_list.append(active_name)
    return active_name_list

 

  

  比对出新更新的内容

        if x==1:                                             #x=1只在程序开始的时候初始化一次,判断是不是第一次执行程序,如果是就初始化old_list来作为下一次活动的比对条件
            old_list = old_list+active_name_list
            send_email(old_list)
            x+=1
        update_list = [x for x in active_name_list if x not in old_list]  #将得到的新列表和old_list比对,将更新的内容保存在update_list并发送邮件
        if len(update_list)==0:
            print("未出现新活动,最近一次更新时间为",time.strftime('%H:%M:%S',time.localtime(time.time())))
        else:
            print("出现新活动,发送")
       send_email(update_list)

 

  

  这个函数用来发送邮件,用自己的163邮箱发送给自己的QQ邮箱,当然自己给自己的邮箱发送也是可以的。

  此处授权密码是随便写的,用自己的授权密码。

  关于发送邮件需要注意:自己的邮箱需要开通pop3/SMTP服务,会给一个授权码,username和password分别写自己的邮箱和授权密码,注意开放的端口,端口不正确会导致连接不上邮箱

def send_email(text):
    smtpsrever = 'smtp.163.com'
    # 发送邮件的用户名和密码
    username = 'shui_feng_xxxxx@163.com'
    password = 'NJXXXXXXXXXNB'  # 授权密码
    # 接收邮件的邮箱
    receiver = '1609519xxx@qq.com'
    # 创建邮件对象
    message = MIMEMultipart('relate')  #生成一个带附件的邮件对象
    message = MIMEText(f'{text}', 'plain', 'utf-8')
    subject = "第一次测试"  # 邮件的主题
    # 把邮件的信息组装到邮件对象里
    message['from'] = username
    message['to'] = receiver
    message['subject'] = subject

    # 登录smtp服务器并发送邮件
    smtp = smtplib.SMTP()
    smtp.connect(smtpsrever)
    smtp.login(username, password)
    smtp.sendmail(username, receiver, message.as_string())
    smtp.quit()

 

  最后写一个主函数来执行这一切

if __name__=='__main__':
    old_list=[]
    x=1
    while True:
        url_list=get_page_url()
        child_urls=handle(url_list)
        active_name_list=handle2(child_urls)
        if x==1:
            old_list = old_list+active_name_list
            send_email(old_list)
            x+=1
        update_list = [x for x in active_name_list if x not in old_list]
        if len(update_list)==0:
            print("未出现新活动,最近一次更新时间为",time.strftime('%H:%M:%S',time.localtime(time.time())))
        else:
            print("出现新活动,发送")
            send_email(update_list)
        time.sleep(60*60*24) #死循环,每二十四小时执行一次

 

  最终功能代码

import requests
import os
import re
import time
from lxml import etree
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
obj = re.compile(".*? <span class=\"b1\">活动地点:</span><a title=\"(?P<area>.*?)\">")
obj2 = re.compile(".*?<title>(?P<name>.*?)</title>")
header = {"Cookie": "TS_LOGGED_USER=-kowQgrvPgFq4iqGji4hPA5vH; PHPSESSID=51fb2a5a61c010f0465d0; Hm_lvt_dd3ea352543392a029ccf9da1be54a50=1639667636,1639918552,1639977234; TS_think_language=zh-CN; Hm_lpvt_dd3ea352543392a029ccf9da1be54a50=1639994037"}
def handle(url_list):
    child_url=[]
    for url in url_list:
        resp = requests.get(url)
        resp.close()
        resp_tree=etree.HTML(resp.text)
        child_url.extend(resp_tree.xpath("/html/body/div[2]/div/div[3]/div[2]/div[1]/ul/li/div[2]/div[1]/a/@href"))
    return child_url
def handle2(child_urls):
    x=1
    active_name_list=[]
    for url in child_urls:
        resp = requests.get(url,headers=header)
        resp.close()
        active_area = str(obj.findall(resp.text)).replace("[","").replace("]","").replace("'","").replace(" ","")
        active_name =str(obj2.findall(resp.text)).replace("[","").replace("]","").replace("'","").replace(" ","")
        if active_area =='':
            active_name_list.append(active_name)
    return active_name_list

def send_email(text):
    smtpsrever = 'smtp.163.com'
    # 发送邮件的用户名和密码
    username = 'shui_feng_XXXX@163.com'
    password = 'NXXXXXXXXXB'  # 授权密码
    # 接收邮件的邮箱
    receiver = '1609519XXX@qq.com'
    # 创建邮件对象
    message = MIMEMultipart('relate')  # 生成一个带附件的邮件对象
    message = MIMEText(f'{text}', 'plain', 'utf-8')
    subject = "pu口袋校园活动"  # 邮件的主题
    # 把邮件的信息组装到邮件对象里
    message['from'] = username
    message['to'] = receiver
    message['subject'] = subject
    # 登录smtp服务器并发送邮件
    smtp = smtplib.SMTP()
    smtp.connect(smtpsrever)
    smtp.login(username, password)
    smtp.sendmail(username, receiver, message.as_string())
    smtp.quit()
def get_page_url():
    url_list=[]
    for num in range(1,8+1):
        url = f"https://XXX.pocketuni.net/index.php?app=event&mod=School&act=board&cat=all&&p={num}"
        url_list.append(url)
    return url_list
if __name__=='__main__':
    old_list=[]
    x=1
    while True:
        url_list=get_page_url()
        child_urls=handle(url_list)
        active_name_list=handle2(child_urls)
        if x==1:
            old_list = old_list+active_name_list
            send_email(old_list)
            x+=1
        update_list = [x for x in active_name_list if x not in old_list]
        if len(update_list)==0:
            print("未出现新活动,最近一次更新时间为",time.strftime('%H:%M:%S',time.localtime(time.time())))
        else:
            print("出现新活动,发送")
            send_email(update_list)
        time.sleep(60*60*24)

 

 

实现后台运行的方法:使用pyinstaller打包软件时,用 -w 可以不显示控制台,但是在后台可以在后台看到它正在运行

所以只需要用pyinstaller -F -w pu口袋校园.py 再执行exe文件就可以后台运行程序,或者再加一个开机自启也可以

 

实现效果:

 

 

 

且此时桌面没有控制台窗口的显示

 

小脚本完成,按照脚本给的活动名称报名就可以了,看有的线上活动会显示扫码签到,所以要注意一下,一般无需签到或者外勤签到都可以白嫖学时

 

 

后记:关于脚本的更改

  不同的学校我觉得页面应该都长差不多,毕竟都是pu口袋校园,只是要把脚本中以下内容改一下

  1. 活动列表的页面url

  2. 访问时的cookie

  3. 发送的邮箱,授权密码,接收的邮箱

  4. 根据自己的需要,重写筛选的条件

 

ENDING.............

 

posted @ 2022-01-08 22:57  小程不想写代码  阅读(4315)  评论(0编辑  收藏  举报