selenium实战之爬取虎牙直播列表页

文章目录

声明

前面有了 selenium的基础,这里就拿虎牙直播页面来做一个实战测试,这是作为学习,测试使用,并不用作为商业用途,不刻意损害他人利益

实现流程给你

主播列表页面分析

我们需要把中间部分的列表页面内容给爬取下来,包括直播间封面,名称,主播昵称,头像,热度,游戏类别等。

从他的页面结构可以看出,其 xpath就是:

xml 复制代码
//div[@class="box-bd"]//ul[@id="js-live-list"]/li


登录遮罩层处理

从页面结构来看,登录弹窗是在一个 id="UDBSdkLgn_iframe"的iframe中,所以我们在这里在进来时候,需要先切换到 iframe中,然后将窗口关闭

  • 代码实现:
  1. 开启隐式等待,等待元素加载完成
  2. 将句柄切换到 iframe中,关闭登录弹窗
  3. 从 iframe中切除,回到主页面
python 复制代码
...
 # 隐式等待 最大10秒
 self.driver.implicitly_wait(10)

 # 关闭登录弹窗,需要切换到弹窗的iframe中
 self.driver.switch_to.frame('UDBSdkLgn_iframe')
 self.driver.find_element(by=By.ID, value="close-udbLogin").click()
 # 从弹窗的iframe中切换回主页面
 self.driver.switch_to.default_content()
...

解析直播列表的数据

根据 xpath 分析出各个元素的内容,在这里封装了一个函数,在每一页去拉取时调用它,在这里为了避免数据取不到的情况报错,我就加了 try...catch 代码如下:

python 复制代码
def parse(self, page):
    """
    解析虎牙直播的数据
    @param data_list:属于引用数据
    @return:
    """
    list_data = []
    room_list = self.driver.find_elements(by=By.XPATH, value='//div[@class="box-bd"]//ul[@id="js-live-list"]/li')
    for key, elem in enumerate(room_list):
        # 获取每个直播间的 链接,封面,直播间名字,主播名称,热度,游戏类名组成字典
        tmp_dic = {}
        # 直播间链接
        try:
            tmp_dic['link'] = elem.find_element(by=By.XPATH, value='./a[1]').get_attribute('href')
        except:
            tmp_dic['link'] = ''
            pass

        # 直播间封面
        try:
            tmp_dic['cover'] = elem.find_element(by=By.XPATH, value='./a[1]/img').get_attribute('src')
        except:
            tmp_dic['cover'] = ''
            pass

        # 直播间名字
        try:
            tmp_dic['name'] = elem.find_element(by=By.XPATH, value='./a[2]').text
        except:
            tmp_dic['name'] = ''
            pass

        # 主播头像
        try:
            tmp_dic['user-cover'] = elem.find_element(by=By.XPATH,
                                                      value='.//span[contains(@class,"avatar")]/img').get_attribute(
                'src')
        except:
            tmp_dic['user-cover'] = ''
            pass

        # 主播昵称
        try:
            tmp_dic['user-name'] = elem.find_element(by=By.XPATH, value='.//span[contains(@class,"avatar")]/i').text
        except:
            tmp_dic['user-name'] = ''
            pass

        # 游戏名称
        try:
            tmp_dic['game-name'] = elem.find_element(by=By.XPATH,
                                                     value='.//span[contains(@class,"game-type")]/a').text
        except:
            tmp_dic['game-name'] = ''
            pass

        # 游戏链接
        try:
            tmp_dic['game-link'] = elem.find_element(by=By.XPATH,
                                                     value='.//span[contains(@class,"game-type")]/a').get_attribute(
                'href')
        except:
            tmp_dic['game-link'] = ''
            pass

        # 热度
        try:
            tmp_dic['hot'] = elem.find_element(by=By.XPATH, value='.//span[@class="num"]/i[@class="js-num"]').text
        except:
            tmp_dic['hot'] = ''
            pass

        # 新增时间
        tmp_dic['insert_time'] = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))
        # 将数据写入列表
        list_data.append(tmp_dic)
        pass

    # 将数据写入文件
    with open(f'huya{page}.json', 'a', encoding="utf-8") as f:
        json.dump(list_data, f, indent=4, sort_keys=False)
        pass
    return list_data

分页处理

因为分页结构在最下面,所以需要来用 js做一个页面滚动,滚动时,水平方向不用变,垂直放下往下滚动到最下面就行

  • 代码片段:
python 复制代码
# 滚动到底部
self.driver.execute_script("window.scrollTo(0, 10000);")
self.driver.find_element(by=By.XPATH,value='//div[@id="js-list-page"]//a[@class="laypage_next"]').click()

完整的代码

我在这里是爬取前10页,所以在在解析和分页的外面套了一层循环,再每一页分析完成,入库到 mongodb中,具体看如下完整代码:

python 复制代码
import json
import time

from selenium import webdriver
from selenium.webdriver.chrome.service import Service as ChromService
from selenium.webdriver.common.by import By

from db.mongo_pool import MongoPool


class GetHuyaDatas(object):
   def __init__(self):
       self.url = 'https://www.huya.com/l'
       # 显示设置驱动的路径,这是 selenium4之后的新写法,主要是为了解决 selenium打开浏览器慢的问题
       service = ChromService(executable_path="/usr/local/bin/chromedriver")
       self.driver = webdriver.Chrome(service=service)
       pass

   def run(self):
       self.driver.get(self.url)
       # 关闭登录弹窗
       try:
           # 隐式等待 最大10秒
           self.driver.implicitly_wait(10)

           # 关闭登录弹窗,需要切换到弹窗的iframe中
           self.driver.switch_to.frame('UDBSdkLgn_iframe')
           self.driver.find_element(by=By.ID, value="close-udbLogin").click()
           # 从弹窗的iframe中切换回主页面
           self.driver.switch_to.default_content()
       except Exception as e:
           print(e)
           pass

       # 隐式等待 最大15秒,等待ajax请求完成
       self.driver.implicitly_wait(15)

       # 遍历10页
       for i in range(1, 11):
           print(f'正在抓取第{i}页')
           time.sleep(1)

           with open(f'huya{i}.html', 'w') as f:
               f.write(self.driver.page_source)

           # 解析
           data_list = self.parse(i)
           self.save_data(data_list)

           # 点击下一页,获取新的页面内容
           try:
               # 滚动到底部
               self.driver.execute_script("window.scrollTo(0, 100000);")
               self.driver.find_element(by=By.XPATH,
                                        value='//div[@id="js-list-page"]//a[@class="laypage_next"]').click()
           except:
               print('已经到最后一页了')
               pass

       time.sleep(5)
       self.driver.quit()
       pass

   def save_data(self, data_list):
       """
       保存数据到mongodb
       @param data_list:
       @return:
       """
       MongoPool().test.huya.insert_many(data_list)

   def parse(self, page):
       """
       解析虎牙直播的数据
       @param data_list:属于引用数据
       @return:
       """
       list_data = []
       room_list = self.driver.find_elements(by=By.XPATH, value='//div[@class="box-bd"]//ul[@id="js-live-list"]/li')
       for key, elem in enumerate(room_list):
           # 获取每个直播间的 链接,封面,直播间名字,主播名称,热度,游戏类名组成字典
           tmp_dic = {}
           # 直播间链接
           try:
               tmp_dic['link'] = elem.find_element(by=By.XPATH, value='./a[1]').get_attribute('href')
           except:
               tmp_dic['link'] = ''
               pass

           # 直播间封面
           try:
               tmp_dic['cover'] = elem.find_element(by=By.XPATH, value='./a[1]/img').get_attribute('src')
           except:
               tmp_dic['cover'] = ''
               pass

           # 直播间名字
           try:
               tmp_dic['name'] = elem.find_element(by=By.XPATH, value='./a[2]').text
           except:
               tmp_dic['name'] = ''
               pass

           # 主播头像
           try:
               tmp_dic['user-cover'] = elem.find_element(by=By.XPATH,
                                                         value='.//span[contains(@class,"avatar")]/img').get_attribute(
                   'src')
           except:
               tmp_dic['user-cover'] = ''
               pass

           # 主播昵称
           try:
               tmp_dic['user-name'] = elem.find_element(by=By.XPATH, value='.//span[contains(@class,"avatar")]/i').text
           except:
               tmp_dic['user-name'] = ''
               pass

           # 游戏名称
           try:
               tmp_dic['game-name'] = elem.find_element(by=By.XPATH,
                                                        value='.//span[contains(@class,"game-type")]/a').text
           except:
               tmp_dic['game-name'] = ''
               pass

           # 游戏链接
           try:
               tmp_dic['game-link'] = elem.find_element(by=By.XPATH,
                                                        value='.//span[contains(@class,"game-type")]/a').get_attribute(
                   'href')
           except:
               tmp_dic['game-link'] = ''
               pass

           # 热度
           try:
               tmp_dic['hot'] = elem.find_element(by=By.XPATH, value='.//span[@class="num"]/i[@class="js-num"]').text
           except:
               tmp_dic['hot'] = ''
               pass

           # 新增时间
           tmp_dic['insert_time'] = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))
           # 将数据写入列表
           list_data.append(tmp_dic)
           pass

       # 将数据写入文件
       with open(f'huya{page}.json', 'a', encoding="utf-8") as f:
           json.dump(list_data, f, indent=4, sort_keys=False)
           pass
       return list_data

   pass


if __name__ == '__main__':
    huya = GetHuyaDatas()
    huya.run()

selenium自定点击分页:

打印分页的效果

相关推荐
沐霜枫叶2 分钟前
解决pycharm无法识别miniconda
ide·python·pycharm
途途途途24 分钟前
精选9个自动化任务的Python脚本精选
数据库·python·自动化
蓝染然43 分钟前
jax踩坑指南——人类早期驯服jax实录
python
许野平1 小时前
Rust: enum 和 i32 的区别和互换
python·算法·rust·enum·i32
问道飞鱼1 小时前
【Python知识】Python进阶-什么是装饰器?
开发语言·python·装饰器
AI视觉网奇1 小时前
Detected at node ‘truediv‘ defined at (most recent call last): Node: ‘truediv‘
人工智能·python·tensorflow
GuYue.bing2 小时前
网络下载ts流媒体
开发语言·python
牛顿喜欢吃苹果2 小时前
linux创建虚拟串口
python
-Mr_X-2 小时前
FFmpeg在python里推流被处理过的视频流
python·ffmpeg
一个不秃头的 程序员2 小时前
代码加入SFTP JAVA ---(小白篇3)
java·python·github