写在前面
请注意,本文仅供学习和交流使用,严禁用于任何违法活动,包括但不限于非法获取他人信息等。请遵守法律法规,合理使用技术。另,谢绝转载。
概要
使用Python编写一个定时任务脚本,通过Selenium模拟登录教务系统,获取所需要的信息,并通过邮件通知学生变化的内容。
关键步骤讲解
一、模拟登录教务系统(以Edge浏览器为例)
1.打开教务系统的登录页面。通过观察,不能发现,我们如果想要成功登录教务系统,需要正确地输入“用户名”和“密码”,再点击“登录”按键。
2.在这里,我们将使用Selenium库中的find_element
方法来定位网页元素,并使用XPath定位器来找到相关元素,然后使用send_keys
方法向该元素输入相关信息。
3.点击“F12”,进入“开发者工具”(或者点击“鼠标右键”,选择“检查”选项)。我们可以发现,“用户名”的输入框id为“username”。所以,可以使用Selenium库中的find_element
方法来定位网页元素,并使用XPath定位器来找到id为"username"的元素。然后,使用send_keys
方法向该元素输入字符串"xxxx"。对于“密码”而言,其代码与前面的代码类似,不同之处在于这里定位的是id为"password"的元素,并使用send_keys
方法向其输入密码字符串"xxxx"。另外,代码中使用了Keys.ENTER
来模拟按下回车键的操作,以完成密码的输入。
4.运行程序,可以发现成功登录。
示例代码:
# 导入相关库
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
url = 'https://xxx.edu.cn/login' # 填写教务系统的登录网址
# 创建Edge浏览器实例
web = webdriver.Edge()
# 打开教务系统登录页面
web.get(url)
# 输入用户名和密码
web.find_element(By.XPATH, '//*[@id="username"]').send_keys('xxxx') # 填写账号
time.sleep(2) # 强制延时2s,避免反爬虫系统
web.find_element(By.XPATH, '//*[@id="password"]').send_keys('xxxx', Keys.ENTER) # 填写密码
time.sleep(5)
web.quit() # 注意:加上该语句,浏览器会自动关闭
二、获取相关信息(以获取课程表为例)
成功登录教务系统后,我们可以继续使用Selenium库中的find_element
方法来定位网页元素,并使用XPath定位器来找到相关元素,并进行相关操作。
以获取课程表信息为例。
1.进入”开发者工具“后,左键点击选择教务系统网页上的”我的课表“选项,然后在开发者工具中,右键点击相关HTML代码,选择“复制完整的XPath”选项,将其内容粘贴至代码中,使用click()方法对找到的元素进行点击操作。
在此处运行程序时,教务系统页面会模拟点击“我的课表”选项,加载显示具体课程表信息。
2.同理,左键点击选择教务系统网页上的”我的课表“的内容,然后在开发者工具中,右键点击相关HTML代码,选择“复制完整的XPath”选项,将其内容粘贴至代码中,使用.text
属性来获取课程表元素的文本信息。
请注意,这里使用了WebDriverWait类来等待元素的出现,以确保元素已经加载完毕再进行操作。等待时间可以根据实际情况进行调整。
3.运行程序,可以发现成功获取课程表信息(截图有所省略)。
示例代码:
# 导入相关库
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
```
# 这里是登录教务系统的相关代码
```
# 获取课程表
web.find_element(By.XPATH, '/html/body/table/tbody/tr/td[1]/div/ul/li[1]/ul/div/li[15]/a').click()
# 等待相关页面加载完成,最长等待20s
wait = WebDriverWait(web, 20)
Course = wait.until(EC.presence_of_element_located((By.XPATH, '/html/body/table/tbody/tr/td[3]/div/table/tbody/tr/td/div/form/div[2]/table')))
# 获取信息所有文本
Course_text=Course.text
# 打印文本内容
print(Course_text)
三、发送邮件(以QQ邮箱为例)
我们可以通过发送邮件的方式,来通知用户他所关注的内容。这里以QQ邮箱为例,进行介绍。
示例代码:
# 导入相关库
import smtplib
from email.mime.text import MIMEText
from email.header import Header
# 邮件服务器配置
smtp_server = 'smtp.qq.com' # QQ邮件服务器地址
smtp_port = 465 # QQ邮件服务器端口号
smtp_username = 'xxx@qq.com' # 填写发送邮件的邮箱地址
smtp_password = 'xxx' # 填写发送邮件的邮箱授权码
# 发件人、收件人、邮件内容
sender = 'xxx@qq.com' # 填写发件人邮箱
receivers = ['xxx@qq.com','xxx@qq.com'] # 填写收件人邮箱,可以是多个
subject = '邮件测试' # 填写邮件主题
content ='这是一封测试邮件!' # 填写邮件内容
# 创建邮件对象
message = MIMEText(content, 'plain', 'utf-8')
message['From'] = Header(sender)
message['To'] = Header(','.join(receivers))
message['Subject'] = Header(subject)
server=None
try:
# 连接邮件服务器
server = smtplib.SMTP_SSL(smtp_server, smtp_port)
server.login(smtp_username, smtp_password)
server.set_debuglevel(True)
# 发送邮件
server.sendmail(sender, receivers, message.as_string())
print("邮件发送成功")
except Exception as e:
print("邮件发送失败:", str(e))
finally:
# 关闭连接
if server is not None:
server.quit()
上述代码使用Python的smtplib库实现了发送邮件的功能。首先,我们需要配置邮件服务器的相关信息,包括邮件服务器地址、端口号、发件人邮箱地址和授权码。然后,我们需要指定邮件的收件人、主题和内容。接下来,我们创建一个MIMEText对象,用于表示邮件的内容。然后,我们使用SMTP_SSL
方法连接到邮件服务器,并使用login
方法登录到发件人的邮箱。最后,我们使用sendmail
方法发送邮件,并在发送成功后打印提示信息。最后,我们使用quit
方法关闭与邮件服务器的连接。
下图是程序的测试结果:
四、设置定时任务
当我们需要每隔一段时间执行一次任务时,可以使用Python的schedule库来实现定时任务的调度。
示例代码:
# 导入相关库
import schedule
import time
n=1
# 定义任务函数
def job():
global n
print(f"这是第{n}次运行任务")
n+=1
# 第一次运行任务
job()
# 定义定时任务的调度规则,这里设定为每10s执行一次
schedule.every(10).seconds.do(job)
# 循环执行定时任务
while True:
schedule.run_pending()
time.sleep(1)
首先,定义一个名为job的函数。在上面的示例代码中,该job函数会在每次调用时打印出运行次数。然后,通过调用job函数来执行第一次任务。接下来,使用schedule.every(10).seconds.do(job)
来定义定时任务的调度规则,表示每隔10秒执行一次job函数。最后,通过循环执行schedule.run_pending()
来实现定时任务的循环执行,同时使用time.sleep(1)
来控制每次循环的间隔时间为1秒。这样,定时任务就会按照设定的规则周期性地执行。
下图是程序运行结果的截图:
可能遇到的问题
一、无法使用使用Selenium库(以Edge浏览器为例)
答:检查是否安装Edge驱动程序、Selenium库。
若没有安装,则需要进行以下几个步骤:
-
安装Edge驱动程序:首先,需要下载并安装适用于Edge浏览器的驱动程序。可以从Selenium官方网站或Edge浏览器官方网站(https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/)上获取适用于自己浏览器版本的驱动程序。
-
安装Selenium库:在Python环境中,使用
pip
命令安装Selenium库。可以使用以下命令进行安装:pip install selenium
-
导入相关库:在Python脚本中,需要导入Selenium库和WebDriver库,代码如下:
from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys
-
创建Edge浏览器实例:通过
webdriver.Edge()
方法创建Edge浏览器实例,代码如下:driver = webdriver.Edge(executable_path='path_to_edge_driver')
其中,
executable_path
参数指定Edge驱动程序的路径。 -
执行操作:使用浏览器实例进行各种操作,例如打开指定网页、查找元素、输入文本等。例如,要打开指定网页,可以使用以下代码:
driver.get('https://www.example.com')
-
关闭浏览器实例:在脚本执行完毕后,需要关闭浏览器实例,释放资源。可以使用以下代码关闭浏览器实例:
driver.quit()
二、无法使用SMTP_SSL方法连接到QQ邮件服务器或提示smtplib.SMTPServerDisconnected: please run connect() first
答:很大概率是你的QQ邮箱没有开启POP3/IMAP/SMTP/Exchange/CardDAV 服务。 详情及设置方法可见:帮助系统 (qq.com)或SMTP/IMAP服务 (qq.com)。另外注意,smtp_password = 'xxxxx'
填写的是发送邮箱的邮箱授权码,不是邮箱密码。
三、每次都自动弹出浏览器,怎么设置不让其自动弹出?
答:可以尝试以下代码。
# 设置Edge浏览器选项
edge_options = Options()
edge_options.add_argument('--headless') # 屏蔽可视化界面
# 创建Edge浏览器实例
web = webdriver.Edge(options=edge_options)
四、能不能换个浏览器或者邮箱进行讲解?
答:殊途同归。
五、为啥它没有自动运行?
答:检查是不是把编译器给关了。编译器关闭后,这个程序也就自动终止了。 你可以把程序代码放在云端。
完整示例代码
# 导入相关库
import schedule
import time
import smtplib
import re
from email.mime.text import MIMEText
from email.header import Header
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.edge.options import Options
# 定义发送邮件的函数
def send_email(gpa, ranking,grade):
# 邮件服务器配置
smtp_server = 'smtp.qq.com' # 邮件服务器地址,以QQ邮箱为例
smtp_port = 465 # 邮件服务器端口号,以QQ邮箱为例
smtp_username = '' # 填写发送邮件的邮箱地址
smtp_password = '' # 填写发送邮件的邮箱授权码
# 发件人、收件人、邮件内容
sender = '' # 填写发件人邮箱
receivers = [''] # 填写收件人邮箱,可以是多个
subject = '' # 填写邮件主题
content = '' # 填写邮件内容
# 创建邮件对象
message = MIMEText(content, 'plain', 'utf-8')
message['From'] = Header(sender)
message['To'] = Header(','.join(receivers))
message['Subject'] = Header(subject)
server=None
try:
# 连接邮件服务器
server = smtplib.SMTP_SSL(smtp_server, smtp_port)
server.login(smtp_username, smtp_password)
server.set_debuglevel(True)
# 发送邮件
server.sendmail(sender, receivers, message.as_string())
print("邮件发送成功")
except Exception as e:
print("邮件发送失败:", str(e))
finally:
# 关闭连接
if server is not None:
server.quit()
# 以获取gpa,ranking为例,初始化变量
previous_gpa = None
previous_ranking = None
# 定义定时任务
def job():
global previous_gpa, previous_ranking # 声明previous_gpa和previous_ranking为全局变量
url = '' # 填写教务系统的登录网址
# 设置Edge浏览器选项
edge_options = Options()
edge_options.add_argument('--headless') # 屏蔽可视化界面
# 创建Edge浏览器实例
web = webdriver.Edge(options=edge_options)
# 打开教务系统登录页面
web.get(url)
# 输入用户名和密码
web.find_element(By.XPATH, '//*[@id="username"]').send_keys('xxxx') # 填写账号
time.sleep(2) # 强制延时2s,避免反爬虫系统
web.find_element(By.XPATH, '//*[@id="password"]').send_keys('xxxx', Keys.ENTER) # 填写密码
time.sleep(2) # 强制延时2s,避免反爬虫系统
# 获取学生成绩、GPA和排名等信息
web.find_element(By.XPATH, '//*[@id="menu_panel"]/ul/li[1]/ul/div/li[19]/a').click()
# 等待相关页面加载完成,最长等待20s
wait = WebDriverWait(web, 20)
grade = wait.until(EC.presence_of_element_located((By.XPATH, '/html/body/table/tbody/tr/td[3]/div/div/div[3]/div/table/tbody')))
rank = wait.until(EC.presence_of_element_located((By.XPATH, '/html/body/table/tbody/tr/td[3]/div/div/div[3]/p')))
# 获取信息所有文本
g = grade.text
r = rank.text
# 使用正则表达式在给定的字符串中搜索gpa和ranking值
gpa = re.search(r'平均绩点\(GPA\)为([\d.]+)', r).group(1)
ranking = re.search(r'专业排名第(\d+)名', r).group(1)
# 控制台打印相关信息
print("当前GPA:", gpa)
print("当前排名:", ranking)
# 检查GPA和排名是否有变化
if gpa != previous_gpa or ranking != previous_ranking:
send_email(gpa, ranking,g)
# 更新前一次的GPA和排名
previous_gpa = gpa
previous_ranking = ranking
# 关闭WebDriver
web.quit()
# 第一次运行任务
job()
# 定义定时任务的调度规则,每30min执行一次
schedule.every(30).minutes.do(job)
# 循环执行定时任务
while True:
schedule.run_pending()
time.sleep(1)
程序运行结果:
写在最后
写这个程序脚本是因为等期末成绩的时候,过于无聊,又懒得登教务系统查询,就简单写了个程序,也算学有所用。其实,本来打算用爬虫的,无奈学校的教务系统对登录密码进行“动态字符串+密码”的SHA1加密,在“开发者工具”中没找到相关加密文档,就放弃了,转而采用Selenium库进行模拟登录。
自我感觉没啥用。另外不建议拿来作为课程作业,看看即可。