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

打印分页的效果

相关推荐
qq_381454991 分钟前
Python学习技巧
开发语言·python·学习
Ndmzi8 分钟前
Matlab编程技巧:自定义Simulink菜单(理解补充)
前端·javascript·python
dagouaofei35 分钟前
AI生成个性化年终总结PPT
人工智能·python·powerpoint
white-persist2 小时前
VSCode 快捷键大全:从设计理念到场景化高效运用(详细解析)(文章末尾有vim快捷键大全)
linux·ide·vscode·python·编辑器·系统安全·vim
liliangcsdn2 小时前
python threading异步并发调用示例
python
计算机毕设匠心工作室2 小时前
【python大数据毕设实战】全面皮肤病症状数据可视化分析系统、Hadoop、计算机毕业设计、包括数据爬取、数据分析、数据可视化、机器学习、实战教学
后端·python·mysql
码界奇点2 小时前
基于Python与Pygame的多功能游戏系统设计与实现
python·游戏·毕业设计·pygame·源代码管理
万邦科技Lafite3 小时前
一键获取淘宝店铺所有商品信息,实时监控商品数据
开发语言·数据库·python·api·开放api·电商开放平台·淘宝开放平台
小糖学代码3 小时前
LLM系列:1.python入门:2.数值型对象
人工智能·python·ai
零日失眠者3 小时前
这5个Python库一旦掌握就离不开
后端·python