Baby爬虫

发布于 2024-10-24  275 次阅读


import time
from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from datetime import datetime

import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.application import MIMEApplication




# 邮件配置
smtp_server = '你用的邮箱的服务器地址'  # SMTP 服务器地址
smtp_port = SMTP端口 # SMTP 端口(通常为587或465)
email_user = '你的邮箱'  # 发件人邮箱
email_password = '你的邮箱密码'  # 发件人邮箱密码
recipient_email = '收件人邮箱密码'  # 收件人邮箱
subject = '实验项目预约输出'  # 邮件主题
body =   '请查收实验项目预约的输出文件。'# 邮件正文

# 创建邮件
msg = MIMEMultipart()
msg['From'] = email_user
msg['To'] = recipient_email
msg['Subject'] = subject

# 附加邮件正文
msg.attach(MIMEText(body, 'plain'))


# 初始化 WebDriver
driver = webdriver.Chrome()

# 登录页面
driver.get('需要登陆的网站地址')

# 输入用户名和密码
driver.find_element(By.ID, 'username').send_keys('账号')
driver.find_element(By.ID, 'password').send_keys('密码')

# 点击登录按钮
driver.find_element(By.XPATH, '//*[@id="fm1"]/div/table/tbody/tr[4]/td/input[1]').click()

while(True):
# 获取跳转后的页面
    driver.get('大物选课界面的src')

    # 等待页面加载完毕
    WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.TAG_NAME, "tbody")))

    # 重新获取页面信息
    page_source = driver.page_source
    soup = BeautifulSoup(page_source, 'html.parser')

    # 获取所有行
    rows = soup.find_all('tr', align='center')

    # 指定要检查的实验项目名称
    target_projects = ["导热系数测量", "磁悬浮动力学", "声速测定", "刚体转动惯量的测定", "霍尔效应及螺线管测磁场"]

    # 用于记录已预约的课程及其时间
    reserved_courses = {}


    #记录是否允许发送文件
    available = False
    # 打开输出文件
    with open('output.txt', 'w', encoding='utf-8') as output_file:
        for row in rows:
            # 获取实验项目名称
            project_name_cell = row.find_all('td')[2]  # 假设实验项目名称是第3列
            project_name = project_name_cell.text.strip()

            # 查找状态单元格
            status_cell = row.find('span', id=lambda x: x and x.startswith('gvUser_ctl'))

            # 打印状态和项目名称
            if status_cell and project_name in target_projects:
                output_file.write(f'实验项目: {project_name}, 当前行状态: {status_cell.text}\n')

                # 如果可以预约且项目属于目标项目之一
                if '预约课堂' in status_cell.text and project_name in target_projects:
                    link = status_cell.find('a')  # 查找链接
                    if link:
                        full_url = f"http://syjx.hyit.edu.cn/student/{link['href']}"
                        output_file.write(f'预约课堂链接: {full_url}\n')
                        # 进入预约课堂的链接
                        driver.get(full_url)
                        driver.find_element(By.XPATH, '//*[@id="ddlxq"]/option[3]').click()
                        soup1 = BeautifulSoup(driver.page_source, 'html.parser')

                        # 获取所有对齐为center的行
                        rows1 = soup1.find_all('tr', align='center')

                        # 用于记录是否找到可预约的项目
                        found_available = False

                        for row1 in rows1:
                            # 获取实验项目名称
                            project_name_cell = row1.find_all('td')[1]  # 假设实验项目名称是第2列
                            project_name = project_name_cell.find('font').text.strip()  # 提取 <font> 标签中的文本

                            if project_name:
                                # 获取实验时间
                                time_cell = row1.find_all('td')[3].text.strip()  # 第4列为实验时间
                                # 获取预约进度
                                progress_cell = row1.find_all('td')[5].text.strip()  # 第6列为预约进度

                                # 提取时间部分并解析
                                time_str = time_cell.split()[2]  # 获取时间部分
                                experiment_time = datetime.strptime(time_str, '%H:%M:%S')  # 解析时间

                                # 解析预约进度
                                total, current = map(int, progress_cell.split('/'))  # 预约进度格式为"当前/总数"
                                
                                # 检查条件:时间在9点之后且当前预约人数小于总人数
                                if experiment_time.hour >= 9 and current < total:
                                    # 检查是否已预约该课程
                                    if project_name not in reserved_courses:
                                        # 检查与已预约课程的时间冲突
                                        if not any(
                                            abs((experiment_time - time).total_seconds()) < 7200  # <2小时冲突
                                            for time in reserved_courses.values()
                                        ):
                                            available = found_available = True
                                            output_file.write(f'实验项目: {project_name.strip()}, '
                                                            f'指导教师: {row1.find_all("td")[2].text.strip()}, '
                                                            f'实验时间: {time_cell}, '
                                                            f'预约进度: {progress_cell}\n')
                                            reserve_button = row1.find('input', {'type': 'submit'})
                                            if reserve_button and reserve_button.get('disabled') != 'disabled':
                                                driver.execute_script("arguments[0].click();", reserve_button)
                                                output_file.write(f'成功预约实验项目: {project_name.strip()}\n')
                                                reserved_courses[project_name] = experiment_time  # 记录已预约课程及时间
                                            else:
                                                output_file.write(f'预约按钮不可用: {project_name.strip()}\n')
                                    else:
                                        output_file.write(f'课程 {project_name} 已预约\n')

                        
    if(available):                       
        file_path = r'电脑中.txt文件的地址'  # 本地文件路径
        with open(file_path, 'rb') as attachment:
            part = MIMEApplication(attachment.read(), Name='output.txt')
            part['Content-Disposition'] = f'attachment; filename="output.txt"'
            msg.attach(part)

                                # 发送邮件
        try:
            with smtplib.SMTP(smtp_server, smtp_port) as server:
                server.starttls()  # 启动TLS加密
                server.login(email_user, email_password)  # 登录
                server.send_message(msg)  # 发送邮件
                print('邮件发送成功!')
        except Exception as e:
                print(f'发送邮件失败: {e}')
    time.sleep(1)   #一秒钟执行一次         
 

以上就是具体的代码了,emmmm,属于开袋即食,有些被我更改的信息也加注中文了,大家修改一下换成自己的信息即可,对了,不要问站主什么“难道要注册两个邮箱吗”这种问题,,,,,愿意的话可以尝试自己发给自己,,,,

python环境是3.11.9,建议使用此版本,其他版本可能会有bug?

使用之前记得先安装一下库文件,emmmm,,,

代码格式有点乱,如果想看运行过程的话可以复制到自己的编辑器里看,这个框架只能设置这么大间距了,我也无能为力,,,,

几行代码的小设计我就直接放在博客里了,emmm,以后如果有机会做一些比较大的项目会更新到github中,,,目前来说,应该要等到站主读研吧,,,,希望有导师收留我,我真的很会打工,QAQ

下面是一些重点步骤的解析,一些不重要的步骤我就跳过了,,,,,


问题一:什么是src

网站中的 src 是 HTML 标签的属性之一,代表 source(源)的缩写,通常用于指定外部资源(如图片、视频、音频、脚本等)的路径。这个属性告诉浏览器从哪里加载相关的文件或资源。——来自chatgpt


问题二:为什么要用src,如何找到src

src这个属性标签可以用来加载其他网页或嵌入内容,常在<iframe>(内嵌框架标签)用于此作用,所以我们可以通过查找src找到我们想要的跳转的网站的地址,网站的src是固定的,不用担心发生变化

在跳转前的网页中我们按下 F12 审计网页js代码,之后按下Ctrl(唱跳rap篮球/小黑子又黑我家哥哥/bushi)+F,查找关键词iframe,肉眼搜索有无出现的src,有的话可以点击看看是不是需要的src,找到需要的src执行

driver.get('大物选课界面的src')

让爬虫跳转到你需要的网页

——感谢班上某位不愿透露姓名的同学分享的知识,伟大的开源精神!!!


问题三:为什么要这么麻烦,既然网页的src不会改变,我直接去gank网站,找到src,让爬虫直接请求不就行了?搞登录干什么,那么麻烦

首先介绍一下Cookie

Cookie 是浏览器和服务器之间通信时使用的一小段数据,通常用于以下用途:

  1. 身份验证:当用户登录网站后,服务器会发送一个包含用户身份信息的 Cookie,浏览器会存储该 Cookie。在后续的每个请求中,浏览器会自动将 Cookie 发送回服务器,服务器通过 Cookie 确认用户身份。
  2. 会话管理:Cookie 可以用于保存用户的会话信息,比如登录状态、购物车信息等。
  3. 个性化设置:例如,保存用户的语言、主题等偏好设置。
  4. 跟踪和分析:网站可以通过 Cookie 记录用户行为,进行数据分析或广告投放。

Cookie 的结构

Cookie 是一对 键-值 形式的数据。一个典型的 Cookie 可能包含以下内容:

  • 名称 (name):Cookie 的标识符。
  • (value):Cookie 的数据内容。
  • (domain):Cookie 所属的域名,只有在该域名下的请求才能访问 Cookie。
  • 路径 (path):限定 Cookie 的有效路径,通常是站点的根目录(/)。
  • 有效期 (expires):Cookie 的失效时间,超过该时间后,浏览器会删除该 Cookie。
  • 安全性 (secure):如果设置了该标志,Cookie 只能通过 HTTPS 发送。
  • HttpOnly:如果设置了该标志,JavaScript 无法访问 Cookie,只能通过 HTTP 请求发送。

——来自chatgpt

Cookie可以作用于登陆状态,如果我们直接去让爬虫get指定网站的地址,这样对于需要登录的网站是不会成功的,因为爬虫没有获得你的Cookie,他无法通过登录认证这一步,所以我们呢才有上面那么繁琐的操作,先让爬虫自动登录网站,保存对应的Cookie值,维持登录状态,之后再以登录的状态去进行其他操作


以上就是我觉得比较值得分享的内容,大家有兴趣的话可以把代码拿去自己调试,因为我写完之后其实也没怎么用过,emmmm,,,,测试了剩余课程的扫描,这个应该是没问题的,抢课的代码我不想写了,,,就让chatgpt自己搞了,所以错误的可能性很大,大家别随便用抢课的功能,,,,有兴趣的话可以完善一下代码,有新想法可以和我讨论,非常喜欢和别人讨论的说,但是别问“难道我要注册两个邮箱吗?”“什么是SMTP?”这种百度一下就可以知道的回答,emmmm,这样会让我感觉有点不尊重我的劳动成果,站主不会很开心呢


编写不易,如果喜欢可以点赞+分享,赞助的话也是非常支持的hhh,如果要评论的话记得修改昵称,不要随便暴露个人信息哦