网易云爬虫评论(Selenium 方式)——part 1 前端内容获取

Chrome-ChromeDriver配置

一定注意关闭Chrome浏览器的自动更新,每次我搞新爬虫项目都会出现版本不一致的问题(抓狂)。没有安装过Chrome的是最好的,新电脑一安装就是自动匹配好的。如果已有了Chrome,ChromeDriver安装网址:https://googlechromelabs.github.io/chrome-for-testing/#stable,下载与你Chrome版本一致-系统一致的ChromeDriver即可。ChromeDriver文件解压的两个文件后放在你python.exe的文件夹中替换原始版本即可。

项目简介

我想要获取的是《5:20AM》这首网易云音乐的评论,然后进行文本分析。获取的目标数据为:用户名、评论内容、评论时间。拟采用Selenium的方式采用非登录的方式进行数据获取。《5:20AM》这首歌的url为:https://music.163.com/#/song?id=2124731026,Let’s go!

Selenium 方式

Selenium 我觉得比之前我刚接触爬虫的时候方便许多,只要定义好要查找的Xpath即可。但是网易云网页中包含嵌入的iframe或frame元素,所以导致Selenium 只能访问主文档的DOM(文档对象模型),就会出现纯粹使用Selenium点击Xpath的方式失灵,导致一直停在一个网页不会出现任何模拟操作的情况,此时就需要switch_to.frame()方式与在网页中嵌入的iframe或frame元素交互,以防定位不到元素。

什么是Frame或iFrame

Frame:在HTML中, 元素用于在浏览器窗口中划分多个独立的区域,每个区域都能独立地加载文档。这是HTML4的特性,现在已经较少使用。
iFrame(Inline Frame):是HTML中的一个元素(),允许一个HTML文档被嵌入到另一个HTML文档中。它是现代网页中常用的技术,用于嵌入外部内容,例如视频、地图或其他从不同源或网站加载的互动内容。

如何使用switch_to.frame()

通过索引:如果页面中有多个frame,可以通过它们在页面中出现的顺序(从0开始的索引)来切换。
通过名称或ID:如果frame有 name 或 id 属性,可以直接使用这些属性值来切换。
通过WebElement:如果已经通过Selenium获取到了frame的WebElement,也可以直接传递这个WebElement来切换

如何发现网页里有嵌入的iframe或frame元素

使用Web浏览器(如Chrome、Firefox、Edge等)的开发者工具来检查网页的源代码:在“元素”标签页中,使用搜索功能(通常通过 Ctrl+F 快捷键激活),输入 或 来查找这些标签,如下图所示,可以发现网易云音乐的主界面是被iframe元素覆盖的,所以需要使用switch_to.frame()去定位真正的元素位置。
在这里插入图片描述
使用Selenium查找iframe或frame元素

from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()
driver.get("https://music.163.com/#/song?id=2124731026")

# 查找所有iframe和frame元素
frames = driver.find_elements(By.TAG_NAME, 'iframe') + driver.find_elements(By.TAG_NAME, 'frame')

# 输出找到的frame和iframe的数量和属性
for frame in frames:
    print(frame.get_attribute('id'), frame.get_attribute('name'))

driver.quit()

run了代码之后可以直接列出iframe或frame的名称,根据这些 ID 或名称,可以使用 Selenium 切换到相应的 iframe 进行进一步的操作。
在这里插入图片描述
通过两种方式都可以发现这个网页覆盖的主iframe为:
由此可见,定位到的iframe name为"contentFrame",ID为g_iframe

使用switch_to.frame()重新定位元素

既然已经确认了 iframe 的名称 (contentFrame) 和 ID (g_iframe),就可以使用这两个属性中的任何一个来切换到这个iframe,并开始在其中操作元素。

通过名称切换

driver.switch_to.frame("contentFrame")

通过ID切换

driver.switch_to.frame("g_iframe")

本项目选取通过ID进行切换的方式(经多次调试发现使用ID切换才可以正确读取到数据,原因不详)。
测试 :


from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options

def get_browser():
    chrome_options = Options()
    browser = webdriver.Chrome(options=chrome_options)
    browser.implicitly_wait(10)  # 设置隐性等待时间
    return browser

def get_comments(url, browser):
    browser.get(url)
    browser.switch_to.frame("g_iframe")  # 如果评论在iframe中,请确保切换到该frame

    # 使用 XPath 定位评论容器,注意字符串的正确用法
    comments = browser.find_elements(By.XPATH, '//div[@class="cmmts j-flag"]')
    for comment in comments:
        print(comment.text)  # 打印每条评论的文本

if __name__ == "__main__":
    browser = get_browser()
    try:
        get_comments("https://music.163.com/#/song?id=2124731026", browser)  # 替换为实际的网页URL
    finally:
        browser.quit()
        print("Browser closed")

结果可见,通过定位到类的方式,成功获取到网易云的评论信息(精彩评论+最新评论)
在这里插入图片描述

数据调试part1:将用户名、评论内容、评论时间、点赞量切分

前文实现了,对于元素中所包含全部文本内容的获取,我想要实现自动化的数据切分,输出。通过将前述的定位到类的全部元素进行分析他们的正则式,引入CSS选择器,以实现对数据的精确定位:
使用 CSS 选择器:对于复杂的网页结构,CSS选择器通常提供了一种更快更简洁的方式来定位元素。

CSS选择器

CSS选择器(CSS Selector)是一种在HTML文档中定位和选择元素的语法,它是通过样式表(CSS)中定义的模式来选择HTML文档中的元素。在Selenium自动化测试中,CSS选择器被广泛用于快速、高效地查找页面上的元素,这对于自动化测试和网页数据抓取尤其有用。
CSS选择器的基本组成可以包括元素名称、ID、类名、属性等。这里是一些基本的CSS选择器及其用途:
元素选择器:
选择所有特定的HTML元素。例如,div 会选择所有的 < div > 元素。
ID选择器:
使用 # 符号,选择具有特定ID的单个元素。例如,#header 会选择ID为 header 的元素。
类选择器:
使用 . 符号,选择具有特定类的元素。例如,.menu 会选择所有具有 menu 类的元素。
属性选择器:
使用 [attribute=value] 格式,选择具有特定属性值的元素。例如,[type=“text”] 选择所有 type 属性为 text 的元素。
组合使用
CSS选择器可以组合使用,以更精确地定位元素:
后代选择器:
通过空格分隔,选择某元素内部的后代元素。例如,div p 会选择所有位于任意 < div > 元素内的 < p > 元素。
子选择器:
使用 > 符号,仅选择直接子元素。例如,ul > li 会选择所有直接作为 < ul > 子元素的 < li > 元素。
相邻兄弟选择器:
使用 + 符号,选择紧接在另一元素后的元素。例如,div + p 会选择所有紧跟在 < div > 元素后的第一个 < p > 元素。
通用兄弟选择器:
使用 ~ 符号,选择某元素之后的所有兄弟元素。例如,h1 ~ p 会选择所有在 < h1 > 元素之后的 < p > 元素。

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options

def get_browser():
    chrome_options = Options()
    browser = webdriver.Chrome(options=chrome_options)
    browser.implicitly_wait(10)  # 设置隐性等待时间
    return browser

def extract_comment_data(comment_element):
    # 用户名
    username = comment_element.find_element(By.CSS_SELECTOR, '.cntwrap .cnt .s-fc7').text
    # 评论内容
    content = comment_element.find_element(By.CSS_SELECTOR, '.cntwrap .cnt').text.split(':', 1)[1]
    # 评论时间
    time = comment_element.find_element(By.CSS_SELECTOR, '.rp .time').text
    # 点赞数,处理点赞数可能不存在的情况
    likes_element = comment_element.find_elements(By.CSS_SELECTOR, '.rp a[data-type="like"]')
    likes = likes_element[0].text if likes_element else '(0)'  # 如果没有找到点赞数,设为'(0)'
    likes = likes.strip('()')  # 移除括号

    return username, content, time, likes

def get_comments(url, browser):
    browser.get(url)
    browser.switch_to.frame("g_iframe")  # 切换到评论所在的iframe

    # 获取精彩评论元素
    top_comments = browser.find_elements(By.CSS_SELECTOR, 'div.itm[data-id]')
    for comment in top_comments:
        print(extract_comment_data(comment))

if __name__ == "__main__":
    browser = get_browser()
    try:
        get_comments("https://music.163.com/#/song?id=2124731026", browser)
    finally:
        browser.quit()
        print("Browser closed")

run了代码后段时间内只出现了三行输出结果,就不再加载数据也不结束代码,只能人为断开浏览器(失败告终)
在这里插入图片描述
代码在输出三行之后停止执行而没有报错或异常,这可能意味着一些可能的情况:

**有限数量的评论元素:**代码只找到了三个评论元素。这可能是因为页面结构问题、定位器不正确或页面没有加载更多评论。
**加载或渲染问题:**页面可能需要更多时间来加载所有元素,或者需要用户交互(如滚动)来触发更多评论的加载。
**异常未捕获:**可能在处理过程中发生了异常,但没有在代码中捕获或记录。

经过手动检查显示页面上确实有35个 .itm[data-id] 元素——评论数量有35个,但我实际上只输出了3个-Debug

最后发现是我的网太差了,但是也增加了等待时间,最后输出了网易云评论的内容,代码如下:

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

def get_browser():
    chrome_options = Options()
    browser = webdriver.Chrome(options=chrome_options)
    browser.implicitly_wait(20)  # 设置隐性等待时间
    return browser

def get_comments(url, browser):
    browser.get(url)
    WebDriverWait(browser, 20).until(EC.frame_to_be_available_and_switch_to_it((By.ID, "g_iframe")))  # 确保正确切换到iframe

    # 等待直到至少35个评论元素出现
    WebDriverWait(browser, 20).until(
        EC.presence_of_all_elements_located((By.CSS_SELECTOR, 'div.itm[data-id]'))
    )

    # 提取评论
    top_comments = browser.find_elements(By.CSS_SELECTOR, 'div.itm[data-id]')
    print(f"Found {len(top_comments)} comments.")  # 打印找到的评论数量
    for comment in top_comments:
        try:
            print(extract_comment_data(comment))
        except Exception as e:
            print(f"Failed to extract data for a comment: {e}")

def extract_comment_data(comment_element):
    username = comment_element.find_element(By.CSS_SELECTOR, '.cntwrap .cnt .s-fc7').text
    content = comment_element.find_element(By.CSS_SELECTOR, '.cntwrap .cnt').text.split(':', 1)[1]
    time = comment_element.find_element(By.CSS_SELECTOR, '.rp .time').text

    likes_elements = comment_element.find_elements(By.CSS_SELECTOR, '.rp a[data-type="like"]')
    likes = likes_elements[0].text.strip('()') if likes_elements else '0'  # 直接在此处理点赞数的格式

    return username, content, time, likes

if __name__ == "__main__":
    browser = get_browser()
    try:
        get_comments("https://music.163.com/#/song?id=2124731026", browser)
    finally:
        browser.quit()
        print("Browser closed")

在这里插入图片描述
但是仍有不完美,最新评论没有点赞的话没有成功赋值为0,继续debug但是网太差了!!


from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

def get_browser():
    chrome_options = Options()
    browser = webdriver.Chrome(options=chrome_options)
    browser.implicitly_wait(20)  # 设置隐性等待时间
    return browser

def get_comments(url, browser):
    browser.get(url)
    WebDriverWait(browser, 20).until(EC.frame_to_be_available_and_switch_to_it((By.ID, "g_iframe")))  # 确保正确切换到iframe

    # 等待直到至少35个评论元素出现
    WebDriverWait(browser, 20).until(
        EC.presence_of_all_elements_located((By.CSS_SELECTOR, 'div.itm[data-id]'))
    )

    # 提取评论
    top_comments = browser.find_elements(By.CSS_SELECTOR, 'div.itm[data-id]')
    print(f"Found {len(top_comments)} comments.")  # 打印找到的评论数量
    for comment in top_comments:
        try:
            print(extract_comment_data(comment))
        except Exception as e:
            print(f"Failed to extract data for a comment: {e}")

def extract_comment_data(comment_element):
    username = comment_element.find_element(By.CSS_SELECTOR, '.cntwrap .cnt .s-fc7').text
    content = comment_element.find_element(By.CSS_SELECTOR, '.cntwrap .cnt').text.split(':', 1)[1]
    time = comment_element.find_element(By.CSS_SELECTOR, '.rp .time').text

    # likes_elements = comment_element.find_elements(By.CSS_SELECTOR, '.rp a[data-type="like"]')
    # likes = likes_elements[0].text.strip('()') if likes_elements else '0'  # 直接在此处理点赞数的格式
    likes_elements = comment_element.find_elements(By.CSS_SELECTOR, '.rp a[data-type="like"]')
    if likes_elements and likes_elements[0].text:  # Check 元素是否存在
        likes = likes_elements[0].text.strip('()')
    else:
        likes = '0'  # 赋值为0

    return username, content, time, likes

if __name__ == "__main__":
    browser = get_browser()
    try:
        get_comments("https://music.163.com/#/song?id=2124731026", browser)
    finally:
        browser.quit()
        print("Browser closed")

网太差了,啊啊啊啊啊啊啊结果输出全靠随缘。

  • 16
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值