从零学习Python+Selenium爬取微博点赞数

289 阅读5分钟

本文主要内容:

以爬取微博点赞数为例,从零开始学习如何使用Python+Selenium爬取网页数据。

image.png


一、Selenium概述

Selenium是一个Web的自动化测试工具,最初是为网站自动化测试而开发的,Selenium可以直接运行在浏览器上,它支持所有主流的浏览器。

因为Selenium可以控制浏览器发送请求,并获取网页数据,因此可以应用于爬虫领域。

Selenium可以根据我们的指令,让浏览器自动加载页面,获取需要的数据,甚至页面截屏,或者判断网站上某些动作是否发生。

Selenium自己不带浏览器,不支持浏览器的功能,它需要与第三方浏览器结合在一起才能使用。


二、浏览器驱动

浏览器驱动用于使用selenium操控本地浏览器执行自动化操作。这里我使用Chrome浏览器,因此下载ChromeDriver

2.1 下载

首先查看自己的Google Chrome版本。

在谷歌浏览器地址栏中输入 chrome://settings/help 查看版本信息

image.png

这里给出阿里的ChromeDriver下载镜像网站:

registry.npmmirror.com/binary.html…

找到自己浏览器以及系统的对应版本进行下载

image.png

对于更高版本的Google Chrome,使用这个网址:

googlechromelabs.github.io/chrome-for-…

2.2 配置环境变量(mac版)

先cd到自己chromeDriver所在的文件夹下,再将chromeDriver复制到/usr/local/bin目录下

image.png

输入chromedriver,如果显示下图说明配置成功

image.png


三、安装Selenium库

3.1 创建项目

先使用pycharm去创建一个普通的项目

image.png

3.2 安装Selenium库

  1. 选择pycharm右下角解释器设置

image.png

  1. 搜索Selenium并且安装

这里建议和我使用同一个版本,高版本每次运行都会去国外官网请求一遍。

image.png

image.png


四、思路 + 代码雏形

我们的大致思路是:通过定位网页元素获取点赞数目,将这些点赞数目作为数据收集起来。

4.1 定位网页元素

以点赞数为例,在微博的点赞按钮处右键,选择“检查”。我们可以看到他的一些CSS属性,像是class,id等。

image.png

image.png

4.2 在代码中使用网页元素

4.2.1 导入依赖库

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

4.2.2 拿到浏览器对象

driver = webdriver.Chrome()

4.2.3 访问微博页

# 访问微博页
driver.get("https://weibo.com/mygroups?gid=110007800021953")
# sleep 2s 确保网页能够加载完毕
sleep(2)
# 点击实时按钮, 切换到实时微博
driver.find_elements(By.CSS_SELECTOR, ".wbpro-textcut")[1].click()
# sleep 10s 确保网页能够加载完毕
sleep(10)

4.2.4 获取点赞数

# 找网页上的元素: 点赞数
likeCountList = driver.find_elements(By.CSS_SELECTOR, ".woo-like-count")
# 打印点赞数
for likeCount in likeCountList:
    if likeCount.text == "赞":
        print(0)
    else:
        print(likeCount.text)

4.3 运行结果

这是我们目前的运行结果,可以看到,虽然点赞数是被打印出来了,但是数据量很少,与我们的期望不符合。

image.png


五、优化

5.1 问题:为什么点赞数的数据量很少

通过f12检索元素发现,在用户不做任何操作的情况下,wrapper里面是只包括7个item的,刚好对应上我们刚才的打印结果。

image.png

而随着我们的下滑操作,item的数目也在跟着增加。所以我们需要模拟这个下滑操作。

image.png

5.2 代码实现

5.2.1 思路

  1. 不断下滑,获取新的item列表
  2. 比较「时间的href」,因为点击时间可以进入每条微博的详情页,所以每条微博的href是不相同的,当不相同的时候,说明是新的item,加入列表中。

image.png

5.2.2 完整代码

from time import sleep

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

# 将页面向下滑动px像素
def scroll_page(px):
    driver.execute_script("window.scrollTo(0, {});".format(px))

# 更新href列表
def refresh_href_list(href_element_list):
    hrefList.clear()
    for href_element in href_element_list:
        href = ""
        try:
            href = href_element.get_attribute("href")
        except:
            href = ""
        finally:
            hrefList.append(href)

# 访问微博实时页
def visit_weibo_live_page():
    # 访问微博页
    driver.get("https://weibo.com/mygroups?gid=110007800021953")
    # sleep 2s 确保网页能够加载完毕
    sleep(2)
    # 点击实时按钮, 切换到实时微博
    driver.find_elements(By.CSS_SELECTOR, ".wbpro-textcut")[1].click()
    # sleep 5s 确保网页能够加载完毕
    sleep(5)
    
# 拿到浏览器对象
driver = webdriver.Chrome()
# 访问微博实时页
visit_weibo_live_page()

# 找网页中时间的href
hrefList = []
refresh_href_list(driver.find_elements(By.CSS_SELECTOR, ".head-info_time_6sFQg"))
# 找网页上的元素: 点赞数
likeCountList = driver.find_elements(By.CSS_SELECTOR, ".woo-like-count")
# 找网页上的元素: 微博内容
wbContentList = driver.find_elements(By.CSS_SELECTOR, ".detail_wbtext_4CRf9")

totalCount = len(likeCountList) # 当前列表的总数

# 打印微博内容和点赞数
for i in range(totalCount):
    if likeCountList[i].text == "赞":
        print("微博内容:\n" + wbContentList[i].text + "\n点赞数:\n" + "0" + "\n")
    else:
        print("微博内容:\n" + wbContentList[i].text + "\n点赞数:\n" + likeCountList[i].text + "\n")


# 向下滑动100条微博的像素值
for i in range(200):
    scroll_page(i * 450)
    # 等待3s加载时间
    sleep(3)
    # 获取新的href list
    newHrefList = driver.find_elements(By.CSS_SELECTOR, ".head-info_time_6sFQg")
    # 获取新的item list
    newLikeCountList = driver.find_elements(By.CSS_SELECTOR, ".woo-like-count")
    newWbContentList = driver.find_elements(By.CSS_SELECTOR, ".detail_wbtext_4CRf9")
    # 通过比较href判断是否有新的item
    for j in range(len(newHrefList)):
        currentHref = ""
        # 这里得捕获异常, 不知道为什么会出现href属性拿不到的情况
        try:
            currentHref = newHrefList[j].get_attribute("href")
        except:
            currentHref = ""
        finally:
            if currentHref not in hrefList:
                # 表示是新的item, 加入列表中
                likeCountList.append(newLikeCountList[j])
                wbContentList.append(newWbContentList[j])
                # 打印一下内容
                if newLikeCountList[j].text == "赞":
                    print("微博内容:\n" + newWbContentList[j].text + "\n点赞数:\n" + "0" + "\n")
                else:
                    print("微博内容:\n" + newWbContentList[j].text + "\n点赞数:\n" + newLikeCountList[j].text + "\n")
    # 更新href list
    refresh_href_list(newHrefList)

sleep(500)

5.3 最终效果

可以看到我们已经能够不断地爬取数据了。

image.png