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自定点击分页:

打印分页的效果

相关推荐
努力的家伙是不讨厌的1 分钟前
解析json导出csv或者直接入库
开发语言·python·json
云空23 分钟前
《Python 与 SQLite:强大的数据库组合》
数据库·python·sqlite
凤枭香1 小时前
Python OpenCV 傅里叶变换
开发语言·图像处理·python·opencv
测试杂货铺1 小时前
外包干了2年,快要废了。。
自动化测试·软件测试·python·功能测试·测试工具·面试·职场和发展
艾派森1 小时前
大数据分析案例-基于随机森林算法的智能手机价格预测模型
人工智能·python·随机森林·机器学习·数据挖掘
小码的头发丝、2 小时前
Django中ListView 和 DetailView类的区别
数据库·python·django
Chef_Chen2 小时前
从0开始机器学习--Day17--神经网络反向传播作业
python·神经网络·机器学习
千澜空3 小时前
celery在django项目中实现并发任务和定时任务
python·django·celery·定时任务·异步任务
斯凯利.瑞恩3 小时前
Python决策树、随机森林、朴素贝叶斯、KNN(K-最近邻居)分类分析银行拉新活动挖掘潜在贷款客户附数据代码
python·决策树·随机森林
yannan201903133 小时前
【算法】(Python)动态规划
python·算法·动态规划