进阶网络爬虫实践内容---微博网页内容爬取

        实战内容:访问微博热搜榜(Sina Visitor System),获取微博热搜榜前50条热搜名称、链接及其实时热度,并将获取到的数据通过邮件的形式,每20秒发送到个人邮箱中。

话不多说,先放注意事项:

  1. 定义请求头

        本实验需要获取User-Agent、Accept、Accept-Language、Accept-Ecoding、Cookie五个字段,前四个字段可能都是相同的,主要是Cookie不同。具体获取流程如下:

  • 打开目标网页,本实验目标网页为Sina Visitor System
  • 按键盘上面F12进入开发者模式,此时页面如下:

进阶网络爬虫实践内容---微博网页内容爬取_第1张图片

  • 按键盘上面F5刷新页面,此时开发者模式中会有网页相关信息,页面如下:

进阶网络爬虫实践内容---微博网页内容爬取_第2张图片

  • 依次点击Network、All、以及summary(即目标链接的地址),各个位置如下图所示:

进阶网络爬虫实践内容---微博网页内容爬取_第3张图片

  • 点击summary后出现右侧窗口,点击Header能够得到相关报文字段,如下图所示:

进阶网络爬虫实践内容---微博网页内容爬取_第4张图片

  • 本实验所需的字段均在Request Header中,即下图中标注的字段。具体字段对应的值以各自浏览器为主,无需与图中字段值相同。

进阶网络爬虫实践内容---微博网页内容爬取_第5张图片

  • 记住User-Agent、Accept、Accept-Language、Accept-Ecoding、Cookie五个字段值,后续在代码中会用到。(建议使用文本保存,以便使用)

除此之外,我们还需要获取一个非常重要的东西,来帮助我们实现邮箱发送功能。

    2.获取发送邮箱的smtp授权码

smtp授权码只需要发送邮箱的,不是接收邮箱的。因为不是我们自己主动发送邮件,通过第三方(python代码)发送的,所以需要获取smtp授权码进行第三方登录。本实验以QQ邮箱为例,获取QQ邮箱的smtp授权码,其他类型邮箱类似或者可以上网查找相关资料。

  • 打开QQ邮箱设置-账户,往下滑找到如图所示的选项。

进阶网络爬虫实践内容---微博网页内容爬取_第6张图片

  • 将上图中的四个服务全开起来,具体操作步骤略,点击开启的时候会有相关提示。
  • 点击图中生成授权码,并根据提示进行操作。

进阶网络爬虫实践内容---微博网页内容爬取_第7张图片

  • 操作过后会得到下面的提示框,记住显示的授权码,备用。

进阶网络爬虫实践内容---微博网页内容爬取_第8张图片

本次实战的重点注意部分:

 

其他说明

        浏览微博热搜榜html网页源码可发现整个热搜榜内容均在…,每条热搜的信息(序号、关键词、热度)均在…标签内。

        本实验还是使用CSS选择器获取指定元素信息。具体某条热搜链接和关键词的CSS选择器为:

#pl_top_realtimehot > table > tbody > tr:nth-child(1) > td.td-02 > a

为获取全部热搜的CSS选择器,将上面的改为:

#pl_top_realtimehot > table > tbody > tr> td.td-02 > a

同理,获取全部热搜热度的CSS选择器为:

#pl_top_realtimehot > table > tbody > tr > td.td-02 > span

        热搜榜置顶没有显示热度,需要特殊处理。另外就是部分热搜的链接会出现别的情况,也需要特殊处理。

前面的注意事项准备完成后,我们开始正式上手:

老规矩,先上我们实战需要的库和包

        除过之前我们需要的老三样,这次还需要smtplib、MIMEText、MIMEMultipart三个库和相关包。

进阶网络爬虫实践内容---微博网页内容爬取_第9张图片

        前三个库和包的作用,之前的文章(经典网络爬虫实践内容---豆瓣网页内容爬取(初级)-CSDN博客)已经讲过,所以这里就不再赘述了。引入smtplib、MIMEText、MIMEMultipart三个库和相关包,是分别为了能够实现,邮件发送(stmplib)、邮件内容操作(MIMExxxxx)等两个功能。

        请求网页函数,同样也已经讲过(为了降低文章冗余性,本次实战内容中,之前已经涉及的模块将不再讲解)建议先阅读(经典网络爬虫实践内容---豆瓣网页内容爬取(初级)-CSDN博客)以及(经典网络爬虫实践内容---豆瓣网页内容爬取(完结)-CSDN博客)两篇内容,再进行本次实战,将会更容易一些。

解析网页函数:

        和之前相同的是,我们解析网页,通过CSS选择器进行选择标签。

进阶网络爬虫实践内容---微博网页内容爬取_第10张图片

        因为本次实验需要将或许到的热搜榜单发送到邮箱内,且考虑到stmp协议,并不支持发送二进制内容,所以在这里我们需要将获取到的内容,全部以字符串的形式存储,因此我们声明了集合与列表,用来暂存我们所获取到的内容,在最后一步统一转换为规定好的字符串格式,这里与之前不同的是,对微博热搜名称的获取时,我们使用了strip()函数来去除获取内容中的空格,避免因为空格存在造成的一些小bug。除过之前使用的get_text()和get()函数,这里的两种用法也可以实现相同的目的。这一段内容是获取头热搜榜单,也就是前面我们提到的,不存在热度的热搜内容。所以我们人工规定它的热搜度为“无”。接着将获取到的内容存入列表中,且追加入集合中。

进阶网络爬虫实践内容---微博网页内容爬取_第11张图片

        紧接着上面的内容,我们开始对其余内容进行获取。(可能你会疑问,微博热搜不是50条吗,为什么我的范围是从1-52,这里的解释是:第0条就是我们刚才获取到的没有热度的热搜内容,且最后一位(52)是不可取的,仔细观察发现在热搜内容中还有一条是夹杂在热搜中间的,没有序号,也没有热度,并且链接所在的标签也是与众不同,前面提到,可能会有特殊的热搜需要特殊处理,就是此处)在这里,对热度的一个获取,需要进行进一步处理。因为获取到的内容中还包含热搜类别,我们只需要获取数值就可以了。对于这条特殊热搜,我们的处理方式是,直接获取href类型的标签,这条特殊链接的href标签内容固定为“javascript:void(0);”,并且它的真实链接位于href_to中,所以我们只需要判断,当一个热搜内容的href标签内容为字符串“javascript:void(0);”时,改为获取它的href_to标签。我使用print的目的是为了查看内容是否成功获取,并进行对代码修正,算是一种另类的debug方式。

进阶网络爬虫实践内容---微博网页内容爬取_第12张图片

        前面说到,stmp协议不支持传输二进制,所以我们需要将获取到的内容转换为字符串,这里将列表中的全部内容,按照固定的格式,进行转换并且获取系统的当前时间,作为一个时间戳,来验证是否是每20秒发送一次。将转换好的字符串交给EmailQQ()函数进行转发,解析网页函数的功能就结束了。

邮件发送函数EmailQQ():

进阶网络爬虫实践内容---微博网页内容爬取_第13张图片

        在这里发送人、接收人邮箱都是自己的邮箱账号,stmp写入自己的授权码(前面获取的)使用MIMEMultipart()创建一个对象,将字符串以utf-8的格式重新编码,存入对象中(这个发送过去就是一长串的汉字和链接,当然还有另一种方式,以附件的形式传输)

进阶网络爬虫实践内容---微博网页内容爬取_第14张图片

在项目文件夹下创建一个txt文本,将news的内容装入txt中,并将txt变为附件,加入到mer中

进阶网络爬虫实践内容---微博网页内容爬取_第15张图片

        最后赋予mer一个主题,并将发送人和接收人信息传给mer,使用smtplib对邮件进行传输,首先登陆用户,发送邮件后,及时退出,并返回发送成功信息。EamilQQ()函数的功能就结束了。

最后是main函数:

进阶网络爬虫实践内容---微博网页内容爬取_第16张图片

按照对应的内容,编写好请求头内容,准备好url,写一个while循环,来实现每20秒执行一次

(记得测试完成后结束程序!!!不然第二天你会收到上千封邮件!!!!!!)

完整代码如下:

import requests
from bs4 import BeautifulSoup
import time
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart

#请求网页
def page_request(url,us):
    response=requests.get(url,headers=us)
    html=response.content.decode('utf-8')
    return html

#将爬取的数据进行打包,准备发送至个人邮箱
def EmailQQ(news):

    #发送人邮箱
    number = '[email protected]'
    #授权码
    smtp = 'xxxxxxxxxxxxxxx'
    #接收人邮箱
    to = '[email protected]'  # 可以是非QQ的邮箱
    #==================================================仅文字
    #创建一个对象
    mer = MIMEMultipart()
    #将获取的字符串以utf-8的格式进行编码便于后续操作
    mer.attach(MIMEText(news, 'html', 'utf-8'))
    print(news)
    #==================================================实现附件格式
    #打开微博热搜.txt并将获取到的字符串写入
    with open('微博热搜.txt', 'w', encoding='utf-8') as f:
        f.write(news)
    #将微博热搜里的内容读取到创建的对象里
    fujian = MIMEText(open('微博热搜.txt', 'rb').read(), 'base64', 'utf-8')
    #附件内容及文件名称
    fujian["Content-Type"] = 'application/octet-stream'
    fujian.add_header('Content-Disposition', 'file', filename=('utf-8', '', '微博热搜.txt'))
    #附加刚才创建的txt内容
    mer.attach(fujian)
    #===================================================
    mer['Subject'] = '每日微博热搜榜单'  # 邮件主题
    mer['From'] = number  # 发送人
    mer['To'] = to  # 接收人

    #发送邮件
    s = smtplib.SMTP_SSL('smtp.qq.com', 465)
    #登录用户
    s.login(number, smtp)
    #发送邮件
    s.send_message(mer)
    #退出登录
    s.quit()
    print('成功发送')

#解析网页
def page_parse(html):
    soup=BeautifulSoup(html,'html.parser')
    #创建一个列表将之后获取到的信息存入该列表中
    news=[]
    #创建集合进行临时存放
    new={}
    hot_topics = soup.select(".td-02 > a")  # 获取前50条热搜的名称和链接
    top_name=hot_topics[0].text.strip()
    top_link=hot_topics[0]["href"]
    new['name']=top_name
    new['link']=top_link
    new['top']='无'
    news.append(new)

    i=0
    for topic in hot_topics[1:52]:
        name = topic.text.strip()  # 热搜名称
        link = topic["href"]  # 热搜链接
        # 实时热度可能以其他方式呈现
        hot_score = soup.select(".td-02 > span")[i].get_text()
        hot_scores=hot_score.split(" ")[1]
        i+=1
        #针对时刻变化的链接进行特殊处理,获取“href_to”中的链接
        if link=="javascript:void(0);":
            new = {}
            link = topic["href_to"]
            new['name'] = name
            new['link'] = link
            new['top'] = '无'
            news.append(new)
        #对于普通链接进行普遍处理
        else:
            new = {}
            new['name'] = name
            new['link'] = link
            new['top'] = hot_scores
            news.append(new)
    print(news)
    #创建一个字符串用于将列表中的内容放入字符串中,以方便邮件的发送
    content = ''
    #将获取到的所有内容以固定格式转化为字符串形式
    for i in range(len(news)):
        content += news[i]['name'] + '\n' + '链接:https://s.weibo.com' + news[i]['link'] + '\n' + '热度:' + news[i]['top'] + ' \n'
    #获取当前时间
    get_time = time.strftime('%Y-%m-%d %X', time.localtime(time.time())) + '\n'
    #将获取到的时间追加值字符串中
    content += '获取事件时间为' + get_time
    #执行邮件发送任务
    EmailQQ(content)

if __name__=='__main__':
    print("开始爬取")
    ua={
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0",
        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
        "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
        "Accept-Ecoding":"gzip, deflate, br",
        "Cookie":"SCF=AnpXG01ZxY1wAyfDudkAT2_hIwp73gb1dIW6vESyvce-9GALd9FEXCOE7Az7BlC5pMnwUs-hc7cUFW6riwJykIA.; SUB=_2AkMSDpm8f8NxqwFRmfoUyG3nao9yzwjEieKkUmhnJRMxHRl-yT9kqhAPtRB6OY63UzpsBLDqTFgSSjLRQhoTnyhZbLTT; SUBP=0033WrSXqPxfM72-Ws9jqgMF55529P9D9WWUwZjIKHGEoe.arpQlbSZM; _s_tentry=-; Apache=6416867210035.957.1699878579813; SINAGLOBAL=6416867210035.957.1699878579813; ULV=1699878579827:1:1:1:6416867210035.957.1699878579813:"
        }
    url = f'https://s.weibo.com/top/summary'
    #设置循环每隔20s获取一次热搜信息并进行发送
    while True:
        #发出请求
        html = page_request(url, ua)
        #解析网页
        page_parse(html)
        #睡眠
        time.sleep(20)

老样子,如果觉得内容还可以,麻烦动动小手点个赞,谢谢啦!

 

你可能感兴趣的:(Python,爬虫,python,大数据)