定时爬取学校官网讲座公告并邮件发给自己

前言

作为上电的一份子,学校的讲座必不可缺,但麻烦的是讲座公告在学校官网发布。想知道最近有无讲座还得打开浏览器-书签-上电官网-放大-点进去,然后注意下讲座的时间是否过期。网页对手机还没做适配。太麻烦了!

在这里插入图片描述

我就想能否自动爬取该页面,一有更新就把消息发送给我?

在学习了python爬虫和邮件发送功能后我感觉我能做了,于是就开始捣鼓起来。

流程

在这里插入图片描述

各部分说明

获取网页-Request库

帮助文档:https://docs.python-requests.org/zh_CN/latest/

本人学习记录:https://www.wolai.com/fBGguVWnNNhfQE7s5nP8is

pip install requests 安装第三方库

>>> import requests
>>> r = requests.get("https://www.bilibili.com/")
>>> r.status_code  # 如果不是200,表示访问服务器有异常
200
>>> r.encoding = r.apparent_encoding  # 指定编码为从内容中分析出的编码
>>> print(r.text)
# 输出的前100字符
<!DOCTYPE html><html lang="zh-CN"><head><meta charset="utf-8"><title>哔哩哔哩 (-)つロ 干杯~-bilibili</titl

从HTML中提取数据-BeautifulSoup库

帮助文档:https://beautifulsoup.readthedocs.io/zh_CN/latest/

本人学习记录:https://www.wolai.com/iAFWbu3KacKLMybjpcgBz9

pip install beautifulsoup4 安装第三方库

BeautifulSoup-转换成BeautifulSoup 的对象

格式: bs4.BeautifulSoup(<要解析的文本>, <解析器>)

文本例如:'<title>The Dormouse's story</title>'

解析器推荐使用lxml ,因为效率更高,可能需要pip下载

ps: 在该转换过程中,都采用utf-8编码

# 复用上面的内容
from bs4 import BeautifulSoup
soup = BeautifulSoup(r.text, 'lxml')
print(soup.prettify())
# 将结构化输出内容
--------------
<!DOCTYPE html>
<html lang="zh-CN">
 <head>
  <meta charset="utf-8"/>
  <title>
   哔哩哔哩 (-)つロ 干杯~-bilibili
  </title>
  <meta content="bilibili是国内知名的视频弹幕网站,这里有及时的动漫新番,活跃的ACG氛围,有创意的Up主。大家可以在这里找到许多欢乐。" name="description"/>
...

find()-查找

find_all() 方法将返回文档中符合条件的所有标签,返回列表类型

find() 方法将返回找到标签的第一个

# 复用上面的内容
>>> soup.find('title')   # 寻找title标签
<title>哔哩哔哩 (-)つロ 干杯~-bilibili</title>
>>> soup.find_all('a', class_='name')  # 寻找所有class属性为name的a标签,由于html中class与python中class冲突,所以用class_
[<a class="name" href="//www.bilibili.com/v/douga/mad/">MAD·AMV</a>, <a class="name" href="//www.bilibili.com/v/douga/mmd/">MMD·3D</a>, ...]

attrs-属性

可以获取标签特定属性的内容,直接使用返回字典类型

# 复用上面的内容
>>> tag = soup.find('a', class_='name')
>>> tag.attrs
{'href': '//www.bilibili.com/v/douga/mad/', 'class': ['name']}
>>> tag.attrs['href']
'//www.bilibili.com/v/douga/mad/'

发送邮件

两个模块:

smtplib -用来发送邮件

email -用来写邮件

开通SMTP功能

建议不用163邮箱,本人使用时发现无法开通该项功能。

以QQ邮箱为例:在这里插入图片描述
打开邮箱设置-账户
[(img-X5dSLgTa-1634278433825)(image/image_2.png)]
下拉至SMTP服务,开启(本人为已开启状态),会得到一个授权码,先记下来

小练习

import smtplib
from email.mime.text import MIMEText
from email.header import Header

# 写邮件
msg = MIMEText("Hello,world!来自自己的第一封信。", "plain")  # plain表示纯文字,若是html页面则改为html
msg["Subject"] = Header("来自Python的信~")  # 主题
msg["To"] = Header("自己")    # 接收者的称呼
msg["From"] = Header("我")   # 发送者的称呼

# Send
try:
    smtp_obj = smtplib.SMTP_SSL("smtp.qq.com", 465)  # 不同邮箱地址和端口不一样,详情见下
    smtp_obj.login("**********@qq.com", "************")  # QQ邮箱账号与密码
    smtp_obj.sendmail("**********@qq.com", "*********@*****.com", msg.as_string())  # 发送者的邮箱和接受者的邮箱
    print("mail has been send successfully.")
except smtplib.SMTPException as e:
    print(e)


smtp_obj = smtplib.SMTP_SSL("smtp.qq.com", 465)

该句用来指定邮箱服务器地址和端口,在邮箱网站上能查到

以QQ邮箱为例:
[(img-lJ80U1n9-1634278433827)(image/image_3.png)]


代码

注: 关键信息需要自己填写

import requests
from bs4 import BeautifulSoup
import time
import os
import smtplib
from email.mime.text import MIMEText
from email.header import Header


# 记录日志
def log(text):
    with open('log.txt', 'a', encoding='utf-8') as f:
        f.write(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) + '\t' + text + '\n')

# 获取网页
def get_html_text(get_url):
    try:
        r = requests.get(get_url, timeout=30)
        r.raise_for_status()  # 如果status_code不是200,则会引发HTTPError异常
        r.encoding = r.apparent_encoding
        return r.text
    except:
        return "get_html_text产生异常"

# 解析网页
def html_parse(html):
    try:
        title_list = []
        url_list = []
        soup = BeautifulSoup(html, 'lxml')
        page = soup.find('ul', class_='wp_article_list')
        lecture_soup = page.find_all('a')
        for line in lecture_soup:
            title = line.attrs['title']
            url = line.attrs['href']
            title_list.append(title)
            url_list.append(url)
        return title_list, url_list
    except:
        return "html_parser产生异常"

# 读取讲座标记点
def read_lecture_data(filename):
    try:
        with open(filename, 'r', encoding='utf-8') as f:
            return f.read()
    except:
        return -1

# 保存讲座标记点
def save_lecture_data(filename, content):
    with open(filename, 'w', encoding='utf-8') as f:
        f.write(content)
    pass

# 数据处理
def parse_web_data(url, filename):

    html = get_html_text(url)
    title_list, url_list = html_parse(html)
    first_lecture_title = read_lecture_data(filename)

    # 存储讲座标记点的文件未创建
    if first_lecture_title == -1:
        save_lecture_data(filename, title_list[0])
        log('创建文件完成,下次正式运行~')
        os._exit(0)
    # 讲座未更新
    elif first_lecture_title == title_list[0]:
        log('检查完成')
        os._exit(0)
    # 有更新
    else:
        save_lecture_data(filename, title_list[0])
        index = title_list.index(first_lecture_title)
        new_lecture = []
        pre_url = '/'.join(url.split('/')[:3])
        for i in range(index):
            new_lecture.append([title_list[i], pre_url + url_list[i]])
        return new_lecture

# 发送邮件
def send_email(content):
    smtp_obj = smtplib.SMTP_SSL("smtp.qq.com", 465)
    smtp_obj.login("发送方邮箱账号", "SMTP授权码")    # <-这里自己填写
    for j in range(len(content)):
        # 记录日志
        log(content[j][0])

        html = get_html_text(content[j][1])
        soup = BeautifulSoup(html, 'lxml')
        emailbody = str(soup.find('div', class_='article-box')) + '\n' + '原文链接:' + content[j][1]

        msg = MIMEText(emailbody, "html")    # 这里发送的是html页面,所以后一项写为html
        msg["From"] = Header("上电讲座爬虫")    # 发送人称呼
        msg["To"] = Header("自己")            # 接收人称呼
        msg["Subject"] = Header(content[j][0], 'utf-8')    # 标题为讲座标题


        smtp_obj.sendmail("发送方邮箱账号", "接收方邮箱地址", msg.as_string())    # <-这里自己填写 
        print(f"{content[j][0]} 发送成功")

if __name__ == '__main__':
    target_url = 'https://news.shiep.edu.cn/lecture/list.htm'
    lecture_filename = 'first_lecture_title.txt'
    lecture = parse_web_data(target_url, lecture_filename)
    send_email(lecture)


打包

我使用了PyInstaller来打包该python文件。Pyinstaller会收集代码所依赖的库形成单个文件夹或一个exe文件。

它是一个第三方库,可通过pip安装

pip install pyinstaller

具体可参考帮助文档:https://pyinstaller.readthedocs.io/

PyInstaller用法

语法:

pyinstaller [options] script

最简单的即是打开cmd,进入文件所在路径,输入

pyinstaller 文件名.py

以本文件为例,结果是
[(img-jyjFmW16-1634278433831)(image/image_4.png)]
在dist目录下有可执行文件,运行结果如图
[)(image/image_5.png)]

其他用法

用法说明
–distpath DIR指定exe文件存放位置(默认:./dist)
–workpath WORKPATH指定临时文件存放位置(默认:./build)
-a, --ascii不支持unicode(默认:可用则支持)
–clean清理 PyInstaller 缓存并删除临时文件。
-D, --onedir生成包含可执行文件的文件夹(默认)
-F, --onefile生成单可执行文件
-c, --console, --nowindowed打开控制台窗口(默认)
-w, --windowed, --noconsole不打开控制台窗口
-i, --icon <FILE.ico or “NONE”>指定可执行文件的图标,或显示默认图标

在python代码中运行Pyinstaller

可键入如下代码

import PyInstaller.__main__

PyInstaller.__main__.run([
    'my_script.py',
    '--onefile',
    '--windowed'
])

它等同于

pyinstaller my_script.py --onefile --windowed

最终运行

pyinstaller -F -w -i favicon.ico 上电讲座报告2.py


尝试使用--clean 发现无效果

尝试不带-w ,使用中会出现命令行窗口

定时运行

利用任务计划程序
在这里插入图片描述
创建基本程序
在这里插入图片描述

填写名称和描述(描述选填)

在这里插入图片描述
按需定时
在这里插入图片描述
在这里插入图片描述
这里注意:第一栏填写程序路径,第三栏填写程序所在目录路径

举例:

第一栏:C:\Debug\Pyinstaller\dist\上电讲座报告2.exe
第三栏:C:\Debug\Pyinstaller\dist\
  • 如果不填第三栏,任务计划程序的历史记录中会显示启动了,但程序实际没运行。

  • 如果第三栏填成了程序路径,历史记录中会显示任务启动失败。


成果

展示下从程序运行以来的记录:
在这里插入图片描述

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值