用Python爬取斗鱼网站的一个小案例

思路解析:

  1、我们需要明确爬取数据的目的:为了按热度查看主播的在线观看人数

  2、浏览网页源代码,查看我们需要的数据的定位标签

        

  3、在代码中发送一个http请求,获取到网页返回的html(需要注意的是,许多网页都有反爬虫机制,所以需要在请求中添加user-agent,伪装成客户端访问)

  4、对获取到的html进行分析,使用正则表达式提取我们需要的部分(需要注意的是要把主播名称和观看人数所在的块整个提取,分别提取的话如果网页设计不规律的话很难对应)

  5、将得到的单个主播的数据存储在字典中,并把所有主播的数据存储在list中

  6、如果抓取到的数据中包含空格换行等无用字符,还需要对数据进行精炼。

  7、对抓取到的数据从大到小进行排序(需要注意的是:我们抓取到的数据是字符串,并且单位可能是人或者万人,所以要对观看人数进行处理)

  8、将排好序的数据遍历输出。

由于斗鱼网站的网页是采用模板实现的,案例是抓取王者荣耀的主播的数据,想抓取别的类目的话,只需要修改url即可~

代码实现:

'''
    爬取斗鱼网站的王者荣耀分类主播的观看人数和主播名字,并按热度排名
'''
from urllib import request
from io import BytesIO
import gzip
import re


class Spider():
    url = 'https://www.douyu.com/g_wzry'

    # 根节点的字符串匹配正则表达式,匹配除了根节点中间的所有字符,非贪婪模式,找到第一个</div>就结束
    root_pattern = '<div class="DyListCover-info">([sS]*?)</div>'

    headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36'}

    # 观看人数匹配字符串
    number_pattern_str = '<span class="DyListCover-hot is-template">([sS]*?)</span>'
    # 观看人数的字符串,删除前面的icon部分
    number_pattern = '<svg><use xlink:href="#icon-hot_8a57f0b"></use></svg>'

    name_pattern_str = '<h2 class="DyListCover-user is-template">([sS]*?)</h2>'
    name_pattern = '<svg><use xlink:href="#icon-user_c95acf8"></use></svg>'

    # 抓取自定网页内容并解码
    def __fetch_content(self):
        # 发送一个http的请求,获取返回的html代码
        req = request.Request(Spider.url, headers=Spider.headers)
        htmls = request.urlopen(req).read()

        # 解码
        buff = BytesIO(htmls)
        f = gzip.GzipFile(fileobj=buff)
        htmls = f.read().decode('utf-8')
        return htmls

    # 分析抓取内容,选取标签时尽量选取闭合标签,标签成组的选择好对应
    def __analysis(self, htmls):
        # 获取到需要的全部数据
        root_html = re.findall(Spider.root_pattern, htmls)
        # 由于网页中一个块有两个相同的class类,其中第一个主播介绍
        # 第二个才是需要的数据,所以选取奇数下标元素
        root_info_html = root_html[1::2]

        # 最后获取到的数据列表
        anchors = []
        # 遍历列表,提取用户名和观看人数
        for html in root_info_html:
            # 提取到的是带icon的部分
            watch_num_str = re.findall(Spider.number_pattern_str, html)
            # 剔除icon部分
            watch_num = re.sub(Spider.number_pattern, '', watch_num_str[0])

            # 提取带icon的name的部分
            name_str = re.findall(Spider.name_pattern_str, html)
            name = re.sub(Spider.name_pattern, '', name_str[0])

            # 将名字和观看人数用字典存储,最后再用列表存储每个主播的数据
            anchor = {'name': name, 'number': watch_num}
            anchors.append(anchor)

        return anchors

    # 精炼函数
    # def __refine(self, anchors):
    #    lam = lambda anchor: {'name': anchor['name'][0], 'number': anchor['number'][0]}
    #    return map(lam, anchors)

    # 排序
    def __sort(self, anchors):
        anchors = sorted(anchors, key=self.__sort_key, reverse=True)
        return anchors

    # 排序规则
    def __sort_key(self, anchor):
        # 提取数字并计算
        r = re.findall('d*', anchor['number'])
        number = float(r[0])
        if '' in anchor['number']:
            number *= 10000
        return number

    # 显示数据
    def __show(self, anchors):
        # for anchor in anchors:
        #    print(anchor['name'], ':', anchor['number'])
        for rank in range(0, len(anchors)):
            print("Rank ", rank+1, ": ", anchors[rank]['name'], "    ", anchors[rank]['number'])

    # 入口方法
    def go(self):
        htmls = self.__fetch_content()
        anchors = self.__analysis(htmls)
        anchors = self.__sort(anchors)
        self.__show(anchors)


spider = Spider()
spider.go()

  

原文地址:https://www.cnblogs.com/syq816/p/12637776.html