爬虫 | 微博热搜采集发送器
本实验将实现一款爬虫工具,微博热搜采集发送器,通过 requests 库加 bs4 库完成对热搜的爬取,之后通过 smtplib 库与 email 库实现邮件信息的传递。最后还为大家介绍了一个爬虫技巧,pandas 一行代码抓取表格数据。
知识点
- 微博热搜爬取
- Python 邮件发送
- pandas 一行代码爬取网页表格
微博热搜爬取
本实验中的目标网站为 微博热搜榜单,即下图中出现的序号,关键词,热度相关信息。
对网站源码进行分析之后,发现数据都存储在下图所示的结构体中,核心以表格标签形式存在:
在编写爬虫的过程中,发现目标网站数据存在一定的问题,例如第一行数据缺少序号与阅读量,第十行数据缺少最右侧的图标。
以上内容在爬虫程序中属于异常数据,在编写代码时需要针对性对其处理,本实验选用之前课程中提及的 requests 库与 bs4 库进行爬取。由于相关知识已经提前学习,直接进入编码环节,具体细节在代码注释中体现。
将如下代码写入 /home/project/wb.py
文件:
下述代码中的 COOKIE ,可通过浏览器访问微博热搜之后,进行获取。
import requests
from bs4 import BeautifulSoup
# 获取网页元素
def get_html():
# headers 头字典
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36",
"Referer": "https://www.baidu.com",
"cookie": "可先打开浏览器,获取浏览器COOKIE之后,粘贴到该位置"
}
# 抓取网页
res = requests.get("https://s.weibo.com/top/summary", headers=headers)
# 返回网页内容
return res.text
def analy_html():
html = get_html()
# 通过 lxml 方式解析数据
soup = BeautifulSoup(html, 'lxml')
# 查找主 table 标签
data = soup.find(name="tbody")
# 发现所有的 tr,即表格中的行
items = data.find_all(name='tr')
for item in items:
# 序号
order_number = item.find(attrs={"class": "td-01"}).text
# 容错处理,如果序号为空,设置为 0
if order_number == "":
order_number = 0
# 标题区域所有内容
title_content = item.find(attrs={"class": "td-02"}).contents
# 标题
title = ""
# 阅读量
readers = ""
# 第二个单元格存在多个网页标签,获取第一个与第三个即可
if len(title_content) > 3:
print(title_content)
title = title_content[1].text
readers = title_content[3].text
else:
title = title_content[1].text
readers = "0"
# 热度标签
level = item.find(attrs={"class": "td-03"}).text # 热度标签
print(order_number, title, readers, level)
if __name__ == "__main__":
analy_html()
以上代码可以顺利的输出目标数据:
但是在编写的过程中发现如下问题,这部分内容希望你可以掌握,具体如下。
bs4 库获取所有子标签
在 bs4 库中通过 contents
属性,可以获取某一标签下的所有子标签,返回一个 list
,上述代码相关部分如下:
# 标题区域所有内容
title_content = item.find(attrs={"class": "td-02"}).contents
在 bs4 库中与其相似的一些属性如下:
children
返回所有的子标签,但是返回的是一个迭代器;descendants
返回所有后代标签,与contents
、children
最大的区别是,这二者只返回直接子标签;parent
返回某标签的父标签;parents
返回某标签的所有父辈标签;next_sibling
和previous_sibling
返回下一兄弟标签和上一兄弟标签;next_siblings
和previous_siblings
返回所有下一兄弟标签和上一兄弟标签。
以上内容在实际的编码中需要结合实际情况进行使用,在使用时如果出现对应的标签无父级标签,无兄弟标签,会直接返回 None
。
关于父级标签,兄弟标签的相关概念如果你对前端语言不是很熟悉,可以直接在互联网查找一些资料,非常容易理解。
子标签获取到的内容
上文中提及的代码存在一个问题,在使用 contents
属性获取子标签后,得到的 list
包含回车,即 \n
数据。
# 标题
title = ""
# 阅读量
readers = ""
# 第二个单元格存在多个网页标签,获取第一个与第三个即可
if len(title_content) > 3:
print(title_content)
title = title_content[1].text
readers = title_content[3].text
上述代码中输出内容如下,注意到除了基本标签以外,还出现了换行符,此时在获取标题与阅读量的时候,留意索引。
['\n', <a href="/weibo?q=%23%E6%9D%8E%E4%BD%B3%E7%90%A6%E7%BB%99%E9%87%91%E9%9D%96%E8%BF%87%E7%94%9F%E6%97%A5%23&Refer=top" target="_blank">李佳琦给金靖过生日</a>, '\n', <span>227719</span>, '\n']
Python 邮件发送
下面完成本实验第二部分知识,邮件发送,使用 Python3 内置的 smtplib
库即可实现。关于该库的使用教程,属于 Python 基础知识部分内容,本实验中不在对其赘述。
代码编写前需要将对应的邮箱在邮箱后台配置好,当开启邮箱的 SMTP
时,注意是否提供了单独密码,如果提供了要使用 SMTP
密码。
导入对应模块
import smtplib
from email.mime.text import MIMEText # 定义邮件内容
from email.header import Header # 定义邮件标题
import time
邮件发送函数如下:
# 邮件发送
def send_email():
# 发送时间
rq = time.strftime("%Y-%m-%d")
# 发送的邮箱
from_addr = "发送ID@163.com"
# 发送邮箱SMTP服务器地址
smtpserver = "smtp.163.com"
# 密码,填写自己的密码即可,163 邮箱和网页登录的邮箱不同
password = "邮箱密码"
# 接收邮箱的账号
to_addr = "接收ID@qq.com"
# 多个接收者的时候使用
# to_addrs = ["接收ID@qq.com", from_addr]
# 邮件的标题
subject = "{rq} 微博热搜".format(rq=rq)
# 邮件为 html 格式,需要把热搜的爬取到的数据进行格式化,analy_html 方法即为获取微博热搜内容
data = analy_html()
table = "<table>"
for item in data:
table += "<tr><td>{order}:{title}:{readers}:{level}</td></tr>".format(
order=item[0], title=item[1], readers=item[2], level=item[3])
table += "</table>"
content = table
# 邮件的正文
msg = MIMEText(content, 'html', 'utf-8')
# 邮件的标题
msg['Subject'] = Header(subject, 'utf-8')
# 邮件发送方
msg['From'] = from_addr
# 邮件接收方,发送给一人
msg['To'] = to_addr
# 邮件接收方,发送给多人
# msg['To']=','.join(to_addrs)
# SSL协议端口号要使用465
smtp = smtplib.SMTP_SSL(smtpserver, 465)
# helo 向邮箱标识用户身份
smtp.helo(smtpserver)
# 服务器返回结果确认
smtp.ehlo(smtpserver)
# 登录邮箱服务器,输入自己的账号和密码
smtp.login(from_addr, password)
print("热搜发送中...")
# 邮件发送多人
# smtp.sendmail(user,to_addrs,msgroot.as_string())
# 发送给个人的邮件
smtp.sendmail(from_addr, to_addr, msg.as_string())
smtp.quit()
print("发送完毕")
邮件发送对应的是 HTML 格式数据,记得发送前进行格式的拼接。由于发送邮件的函数中使用了 analy_html
函数,所以调整其的返回值。
def analy_html():
...
items = data.find_all(name='tr')
# 待发送的内容
send_msgs = []
for item in items:
...
# send_msg 列表追加数据
send_msgs.append ((order_number,title,readers,level))
return send_msgs
相同部分代码进行了省略。代码对应关键信息修改成自己的信息之后,可以测试邮件发送是否成功,如果完成,你会收到一封如下格式的邮件。
邮件内容如下:
小扩展:微博热搜的采集与发送可以做成定时任务,每日发送一次,这样就能在第一时间收到今日热点信息了。
补充一点:学习 SMTP 可以直接在下述网址学习 菜鸟教程 或者直接百度关键字 Python SMTP
。
pandas 一行代码爬取网页表格
在爬取微博热搜的过程中,发现目标数据存在与一个表格之中,针对这种类型的数据,有一个小技巧提供给大家,有了它,你可以对网页表格数据实现一行代码抓取。
实现该内容的库就是 pandas
,准确的说该第三方库是一款数据分析库,一般用在数据处理上,但是它提供了一个 read_html
方法,可以实现对网页表格的抓取。
将如下代码写入 /home/project/demo2.py
文件:
import pandas as pd
import requests
from bs4 import BeautifulSoup
# 获取网页元素
def get_html():
# headers 头字典
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36",
"Referer": "https://www.baidu.com",
"cookie": "可先打开浏览器,获取浏览器COOKIE之后,粘贴到该位置"
}
# 抓取网页
res = requests.get("https://s.weibo.com/top/summary", headers=headers)
# 返回网页内容
return res.text
# 读取网页表格
tb = pd.read_html(get_html())
# 获取到的表格数据为 list 类型
print(type(tb))
print(len(tb))
print(tb[0])
实验楼也非常贴心的为咱们预装好了该库,直接测试上述代码即可:
学会了 pandas 的 read_html
方法之后,在碰到网页中数据结构是以表格形式存在的,你解决问题的方法又多了一条。
实验总结
从本实验开始,后面的几个内容都是爬虫实际场景应用,我们学习编程的最终目的是将程序应用到工作与生活当中,在学习的过程中,如果你的程序能真正的帮助你解决问题,这样学习效率会变的更高。
爬虫的最佳的场景就是替你完成手动重复的操作,实现自动化处理某些任务,例如本实验中,将爬虫程序与邮件结合,除了采集热搜以外,也可以帮助你监视任意网站,当其出现更新或者变更时,都可以及时的给你发送信息告知于你,希望本爬虫实验可以让你对爬虫的应用场景有所认识。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)