文章目录
前言
作为上电的一份子,学校的讲座必不可缺,但麻烦的是讲座公告在学校官网发布。想知道最近有无讲座还得打开浏览器-书签-上电官网-放大-点进去,然后注意下讲座的时间是否过期。网页对手机还没做适配。太麻烦了!
我就想能否自动爬取该页面,一有更新就把消息发送给我?
在学习了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邮箱为例:
打开邮箱设置-账户
下拉至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邮箱为例:
代码
注: 关键信息需要自己填写
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
以本文件为例,结果是
在dist目录下有可执行文件,运行结果如图
其他用法
用法 | 说明 |
---|---|
–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\
-
如果不填第三栏,任务计划程序的历史记录中会显示启动了,但程序实际没运行。
-
如果第三栏填成了程序路径,历史记录中会显示任务启动失败。
成果
展示下从程序运行以来的记录: