如何使用 Python 爬取天气预报网站的内容,并通过邮件发送爬取结果到指定邮箱地址

发布时间 2023-11-19 11:30:45作者: JerryWang_汪子熙

本文是作者参加腾讯云社区选题互换赛解答的一道题目。题目为:如何使用Python 爬取网页(例如天气,每日问好等等)

出题者的动机是:每天早上要和妹子说早安,想要做个定时任务,每天早上能自动爬取天气,发送天气问好邮件,希望大神支招。

面对这个题目,我们可以将其拆解成若干个小任务:

  1. 使用 Python 爬取某天气预报网站的数据并且保存到本地
  2. 将保存到本地的天气预报数据发送到某指定邮箱去
  3. 将上述两个任务的程序进行调度,定时执行

任务1 - 使用 Python 爬取某天气预报网站的数据

用 Chrome 打开 Bing 搜索引擎,根据关键字天气预报进行搜索,看到下面的结果列表。在网页上看到这个被嵌入在 Bing 搜索结果的上海浦东新区的天气预报结果,但是点击右键之后,无法在新的浏览器窗口打开这个网页。

这不要紧,按 F12 打开 Chrome 开发者工具。选中 Elements 面板,然后单击天气预报页面,即可在 Elements 面板里,看到这个上海浦东新区的天气预报结果的 url,如下图所示:

把它保存下来,新开一个浏览器窗口,地址栏输入进去,自动重定向成:https://www.msn.cn/zh-cn/weather/forecast/in-上海市,浦东新区

把这个 url 记录下来。现在我们已经有了使用 Python 进行数据爬取的网页 url 了,下一步就可以开始编写 Python 代码了。

接下来完成使用 Python 将指定 url 的网页源代码,全部爬取到本地的任务。

向 ChatGPT 发出指令:

你是一个 Python 编程专家,现在有一个网址为 www.xxx.com 的网页,请你使用 Python 读取这个网页的源代码,将其存储在一个 Python 变量并且打印出来。

得到 ChatGPT 解答:

需求很直接,ChatGPT 给出的代码质量也很高,直接拿来就能用。把代码粘贴到一个新建的 1.py 文件里,执行命令行 python 1.py

收到提示:

ModuleNotFoundError: No module named 'requests'

ChatGPT 已经针对这个错误做过提醒了,需要先执行命令行 pip install requests 安装名叫 requests 的工具库。

安装完毕之后重新执行 python 1.py 命令行,能看到 Python 代码调用 requests 工具库,从网络上读取的网页源代码,并打印到控制台上。第二步骤也顺利完成。

然后在网页上定位到需要解析的天气预报信息。

假设我们需要在 Python 代码里,打印出 今天大部分地区天气晴朗,最低气温 20这个字段的值,我们打开 Chrome,选择 Elements 面板,然后单击网页这个字段,即可在 Elements 面板里查询到对应的 HTML 源代码实现,发现这个字段通过一个赋予了 summaryDescCompact-E1_1 class 的 p 元素实现。

现在我们已经明确了下一步需要实现的目标:在 HTML 源代码里,找到 class 为 summaryDescCompact-E1_1 的 p 元素,并打印出来。

向 ChatGPT 发起指令:

你是一个 Python 编程专家,现在你已经用 python 代码将网页的源代码读取到了本地,存储在字符串变量 result 里。现在你想解析出一个 p 元素的值,这个 p 元素有一个 class,值为 summaryDescCompact-E1_1,请你编写 Python 代码,将这个特殊的 p 元素的值解析并打印出来。

ChatGPT 给出的结果:

这段代码首先使用 BeautifulSoup 解析 HTML 字符串,然后使用 find_all 方法找到所有 class 为 "summaryDescCompact-E1_1" 的 p 元素。最后,对每个找到的元素,使用 get_text 方法提取并打印其文本内容。

ChatGPT 给出的代码仍然质量非常高,粘贴进 1.py,直接就可以运行。

python 1.py 命令行执行完后,能打印出网页上看到的这个字段值了:

再试试另一个字段,把这个 22°C 打印出来:

使用同样的办法,定位到这个字段在网页源代码中的位置:

再次找 ChatGPT 帮忙:

你是一个 Python 编程专家,现在你已经用 python 代码将网页的源代码读取到了本地,存储在字符串变量 result 里。现在你想解析出一个 a 元素的值,这个 p 元素有两个 class,值分别为 summaryTemperatureCompact-E1_1 和 summaryTemperatureHover-E1_1,请你编写 Python 代码,将这个特殊的 a 元素的 title 属性值解析并打印出来。

不知疲倦的 ChatGPT 给了解答:

我原封不动地照搬到了 1.py 里,程序运行,完美获得了结果。

完整的 19 行代码如下:

import requests
from bs4 import BeautifulSoup

url = 'https://www.msn.cn/zh-cn/weather/forecast/in-%E4%B8%8A%E6%B5%B7%E5%B8%82,%E6%B5%A6%E4%B8%9C%E6%96%B0%E5%8C%BA'
response = requests.get(url)

soup = BeautifulSoup(response.text, 'html.parser')

p_elements = soup.find_all('p', class_='summaryDescCompact-E1_1')

for p in p_elements:
    print(p.get_text())

element = soup.find('a', {'class': ['summaryTemperatureCompact-E1_1', 'summaryTemperatureHover-E1_1']})

if element and 'title' in element.attrs:
    print(element['title'])
else:
    print("没有找到匹配的元素或者 title 属性不存在")

任务2 - 将保存到本地的天气预报数据发送到某指定邮箱去

向 ChatGPT 发出指令:

你是一个资深的 Python 技术专家,请你编写一段 Python 代码,将一个字符串值通过电子邮件,发送到指定的邮箱中去。

得到源代码:

我使用网易邮箱进行测试,把源代码拷贝到我本地后,稍作修改,主要是将我网易邮箱的用户名和 password,硬编码到代码里去,然后把网易邮箱的 SMTP 服务器地址和端口,填写到代码中去。

总共 31 行代码:

发送的正文,硬编码在代码第 19 行。

执行 Python 代码,出错了,遇到如下错误消息:smtplib.SMTPAuthenticationError: (550, b'User has no permission')

其实这个错误不怪 ChatGPT,因为 ChatGPT 上面的回复里,已经明确提醒过我们:

为了使用Gmail SMTP服务器,你需要允许"不够安全的应用"访问你的账户。你可以在Google帐户的"安全性"设置中更改这个选项。如果你启用了两步验证,你需要生成一个应用专用密码来代替你的常规密码。

出于安全考虑,国内外主流的邮件提供商,默认情况都没有开启允许第三方应用使用 SMTP.

我们登录网易邮箱,选择配置->POP3/SMTP/IMAP:

然后开启 POP3/SMTP 服务即可:

这里网易邮箱会生成一个专门的授权码,我们可以理解成调用 API 时需要传入的 Access Token:

把这个授权码写入代码第 10 行的 password 变量中:

大功告成。执行 Python 代码,然后到收件人邮箱中查看,果然收到了一封标题为 Python Email Test(上图代码第 16 行指定),正文由上图代码第 19 行指定的邮件。

ChatGPT 再次帮助我们成功完成了一个编程任务。

本步骤完整 Python 代码如下:

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

# 设置发件人、收件人、服务器、端口和密码
sender_email = "cle.ee@163.com"  # 发件人邮箱
receiver_email = "jerry.wang@sap.com"  # 收件人邮箱
smtp_server = "smtp.163.com"  # 邮箱服务器
port = 25  # 邮箱端口
password = "QUCC"  # 发件人邮箱密码

# 创建一个 multipart 消息并设置其值
msg = MIMEMultipart()
msg["From"] = sender_email
msg["To"] = receiver_email
msg["Subject"] = "Python Email Test"

# 添加邮件正文
body = "11月4日,我用 Python 代码发的这封邮件"
msg.attach(MIMEText(body, "plain"))

# 连接邮件服务器
server = smtplib.SMTP(smtp_server, port)
server.starttls()  # 启动安全传输模式
server.login(sender_email, password)

# 发送邮件
server.sendmail(sender_email, receiver_email, msg.as_string())

# 关闭邮件服务器连接
server.quit()

剩下的步骤就简单了,将包含上面源代码的 python 程序进行调度,让其定时执行就行了。

Linux 系统下 Python 程序的定时执行

在 Linux 系统中,我们可以使用 cron 来执行定时任务。

  1. 打开终端,输入 crontab -e 来编辑你的 cron 文件。

  2. 在打开的文件中,你可以添加一行来定义你的定时任务。下面是一个例子:

0 * * * * /usr/bin/python3 /path/to/your/script.py

这行代码意味着,每小时的第 0 分钟,执行 /path/to/your/script.py 文件。

cron 的时间格式是有特殊含义的,它的格式是:

*     *     *   *    *        command to be executed
-     -     -   -    -
|     |     |   |    |
|     |     |   |    +----- day of the week (0 - 6) (Sunday=0)
|     |     |   +------- month (1 - 12)
|     |     +--------- day of the month (1 - 31)
|     +----------- hour (0 - 23)
+------------- min (0 - 59)

Windows 系统中 Python 程序的定时执行

在 Windows 系统中,我们可以使用任务计划程序来实现。

  1. 打开任务计划程序,可以在开始菜单中搜索 任务计划程序 来找到它。

  2. 在任务计划程序中,选择 创建基本任务

  3. 在弹出的向导中,输入你的任务名称和描述,然后点击下一步。

  4. 选择触发器,你可以选择每日、每周、每月,或者在特定的时间运行任务,然后点击下一步。

  5. 选择操作,选择 启动程序,然后点击下一步。

  6. 启动程序 页面中,浏览你的 Python 程序的路径,如果你的程序需要参数或者需要在特定的起始目录中运行,你也可以在这里设置。

  7. 点击下一步,然后在完成的界面中,确认你的设置,然后点击完成。

至此本文已经实现了完整的需求,希望对广大 Python 学习者有所启发。