「Python爬虫系列讲解」十一、基于登录分析的 Selenium 微博爬虫

本专栏是以杨秀璋老师爬虫著作《Python网络数据爬取及分析「从入门到精通」》为主线、个人学习理解为主要内容,以学习笔记形式编写的。
本专栏不光是自己的一个学习分享,也希望能给您普及一些关于爬虫的相关知识以及提供一些微不足道的爬虫思路。
专栏地址:Python网络数据爬取及分析「从入门到精通」
更多爬虫实例详见专栏:Python爬虫牛刀小试

前文回顾:
「Python爬虫系列讲解」一、网络数据爬取概述
「Python爬虫系列讲解」二、Python知识初学 
「Python爬虫系列讲解」三、正则表达式爬虫之牛刀小试 
「Python爬虫系列讲解」四、BeautifulSoup 技术
「Python爬虫系列讲解」五、用 BeautifulSoup 爬取电影信息
「Python爬虫系列讲解」六、Python 数据库知识
「Python爬虫系列讲解」七、基于数据库存储的 BeautifulSoup 招聘爬取
「Python爬虫系列讲解」八、Selenium 技术
「Python爬虫系列讲解」九、用 Selenium 爬取在线百科知识
「Python爬虫系列讲解」十、基于数据库存储的 Selenium 博客爬虫


目录

1 登录验证

1.1 定位元素

1.2 打开 Chrome 浏览器

1.3 利用 Selenium 获取元素

1.4 设置暂停输入验证码并登录

2 初识微博爬虫

2.1 微博

2.2 登录入口

2.2.1 新浪微博常用登录入口

2.2.2 新浪微博手机端登录入口

2.3 微博自动登录

3 爬取微博热门信息

3.1 搜索所需的微博主题

3.2 爬取微博内容

3.2.1 需求分析

3.2.2 分析微博的 HTML 源码规律

3.2.3 定位用户名

4 本文小结


Python 在编写网络爬虫的过程中,通常会遇到登录验证才能爬取数据的情况,比如 QQ 空间数据、新浪微博数据、邮箱等。如果不进行验证,则有的网站智能爬取首页数据,甚至很多网站是无法爬取的。同时,随着社交网络变得越来越热门,它们所带来的海量数据也越来越有应用价值,常常被用于舆情分析、文本分析、推荐分析、推荐系统等领域。

本文主要介绍基于登录验证的 Selenium 技术,同时讲解 Selenium 爬取微博数据的实例。

这此之前,我也写过一篇类似的文章,可点击查看→从登陆到爬取:Python反反爬获取某宝成千上万条公开商业数据

1 登录验证

目前,很多网站都有一个登录验证的页面,这一方面提高了网站的安全性,另一方面根据用户权限的不同,可以对网站进行差异性管理和调度。比如,百度登录验证页面,需要输入用户名,密码及验证码。那么如果用户想要的数据需要登录之后才能爬取,甚至需要输入验证码才能爬取,那么该怎么解决呢?

Python 爬虫解决登陆验证的方法很多,常见的包括设置登录时的消息头,模拟登陆、绕过登录界面等。本文主要结合 Selenium 技术来讲解登陆验证的方法。

由于 Selenium 技术被应用于爬虫的同时,也被广泛应用于网站自动化测试,它可以自动操控键盘和鼠标来模拟单击操作,所以,这里采用该技术来模拟登陆。当然,有时候模拟登陆并不是一帆丰顺的,还需要人机验证:比如需要移动滑块到正确位置才能登陆,再比如需要填验证码才能登陆等。

假设现在需要编写 Python 代码来实现自动登录 163 邮箱的功能,只有登录后才能爬取邮箱的接收、发送邮件情况,从而进行相关的数据分析实验。

1.1 定位元素

首先访问 163 网站,定位登录用户名、密码等元素。通常 F12 键用 “元素选择器” 即可快速定位目标元素对应的 HTML 源码。

由上图可见,需要定位的元素源码为 “<input name="email">” 和 “<input name="password">”,分别对应用户名和密码。 

1.2 打开 Chrome 浏览器

调用 driver = webdriver.Chrome() 定义的 Chrome 浏览器驱动,然后通过 driver.get(ur) 函数在浏览器中打开目标页面网址。

1.3 利用 Selenium 获取元素

通过 Selenium 调用 find_element_by_name() 或 find_element_by_path() 函数定位 163 邮箱登录用户名和密码对应的元素,在通过 send_keys() 函数输入正确的用户名和密码。核心代码如下:

elem_user = driver.find_element_by_name("email")
elem_user.send_keys("这里填用户名")
elem_pwd = driver.find_element_by_name("password")
elem_pwd.send_keys("这里填密码")

1.4 设置暂停输入验证码并登录

如果该网站需要输入验证码,则需调用 time.sleep(3) 设置暂停时间 3 秒,并手动输入验证码等待自动登录;如果需要滑块验证,可参考前文所讲,调用模拟鼠标、键盘等操作进一步实现全自动化。登陆之后就可以获取所需要的数据了。

import time
import os
from selenium import webdriver
from selenium.webdriver.common.keys import Keys

# 打开 Chrome 浏览器,这顶等待加载时间
chromedriver = 'E:/software/chromedriver_win32/chromedriver.exe'
os.environ["webdriver.chrome.driver"] = chromedriver
driver = webdriver.Chrome(chromedriver)

# 模拟登录 163 邮箱
url = 'https://mail.163.com/'
driver.get(url)

# 用户名、密码
driver.find_element_by_xpath('//*[@id="auto-id-1594007552696"]').send_keys('用户名')
time.sleep(1)
driver.find_element_by_xpath('//*[@id="auto-id-1594002566766"]').send_keys('密码')
time.sleep(2)
driver.send_keys(Keys.RETURN)

time.sleep(3)
driver.close()
driver.quit()

比如像上述代码一样,会发现仍然不能登录,甚至会报错。这是由于很多网站的登录页面都是动态加载的,我们无法捕获其 HTML 节点,Selenium 也无法定位该节点,所以无法实施后续操作。同时,开发网站的程序员为了防止恶意攻击和爬取通常会不定期地修改网站的 HTML 源码。但是,这种思想已经提供给大家了,希望大家不断完善,以爬取自己所需的数据。 

2 初识微博爬虫

2.1 微博

微博(Weibo),即微型博客(MicroBlog)的简称,也是一种基于用户关系信息分享、传播以及获取的通过关注机制分享简短实时信息的广播式的社交媒体、网络平台,允许用户通过Web、Wep、Mail、App、IM、SMS以及用户可以通过PC、手机等多种移动终端接入,以文字、图片、视频等多媒体形式,实现信息的即时分享、传播互动。

微博作为一种分享和交流平台,更注重时效性和随意性,更能表达出每时每刻使用自己的思想和最新动态,而博客则更偏重于梳理自己在一段时间内的所见、所闻、所感。常见的微博包括:新浪微博、腾讯微博、网易微博、搜狐微博等,若没有特别的说明,微博是指新浪微博。

新浪微博网页端的官方地址为https://weibo.com/,登录后的界面如下图所示,可以看到热门微博、特别关注的微博、动态信息等。每条微博通常包括用户名、微博内容、阅读量、评论数和点赞数等。

当点击个人信息时,可以查看个人资料、基本信息、所关注明星或自己的粉丝,这些信息再做社交网络分析、舆情分析、图谱关系分析、微博用户画像时都能提供很大的价值。

2.2 登录入口

为什么要登录呢?因为如果不登录,新浪微博中的很多数据是不能获取或访问的,如微博的粉丝列表、个人信息等。当单机这些超链接时就会在自动跳转到登录界面,这啥事开发者对微博进行的保护措施。同时,软件公司通常会提供 API 接口让开发者访问微博数据或进行操作,但这里使用 Selenium 模拟浏览器操作进行登录验证。

首先需要找到微博登录入口。打开网址:“https://weibo.com/”,显示如下图所示的首页,其右边就是登录的地方。但是,该网址采取了 HTTPS 验证,使其安全系数较高,另外动态加载登录按钮使得我们无法使用 Selenium 进行定位,所以需要寻找新的登录入口。

2.2.1 新浪微博常用登录入口

新浪微博常用登录入口网址:https://login.sina.com.cn/ 或 https://login.sina.com.cn/signup/signin.php

2.2.2 新浪微博手机端登录入口

新浪微博移动端存储的是手机微博 APP 的数据,其数据更为精炼、图片更小、加载速度更快,适合手机端实时访问,其入口地址为:https://weibo.cn/ 或 https://weibo.cn/pub/。可以看到新浪微博手机端页面看到的信息还是非常精炼的。

接下来讲解如何自动登录微博,如何爬取热门话题、某个人的微博信息等内容。 

2.3 微博自动登录

首先,在浏览器页面输入目标网址,点击键盘 F12 键,通过 “元素选择器” 定位到 “登录名” 和 “密码”,查看相关按钮的 HTML 源码位置,如下图所示。

我们可以定位 id 属性为 “username”、name 属性为 “username” 的节点,找到 “登录名” 文本框,或者通过定位 <li class="item"> 路径下第二个 input 节点实现。这里使用 Selenium 库的相关函数定位该节点,核心代码如下:

elem_user = driver.find_element_by_name("username")
elem_user.send_keys("登录名")

同理,我们接着定位 “密码” 文本框的 HTML 源码,此处给出核心代码:

elem_pwd = driver.find_element_by_name("password")
elem_pwd.send_keys("密码")

 调用 find_element_by_xpath() 函数可以定位 “登录” 按钮节点,再调用 click() 函数单击 “登录” 按钮实现登录,代码如下:

elem_sub = driver.find_element_by_xpath("//input[@class='W_btn_a btn_34px']")
elem_sub.click()    # 单击登录

同时,可以采用按回车键登录的方式,即 elem_pwd.send_keys(Keys.RETURN)。最后给出了利用 Selenium 技术自动登录新浪微博的完整代码,输入账户和密码后单击登录。

import time
import os
from selenium import webdriver
from selenium.webdriver.common.keys import Keys

# 打开 Chrome 浏览器,这顶等待加载时间
chromedriver = 'E:/software/chromedriver_win32/chromedriver.exe'
os.environ["webdriver.chrome.driver"] = chromedriver
driver = webdriver.Chrome(chromedriver)

# 模拟登录新浪微博
url = 'https://login.sina.com.cn/signup/signin.php'
driver.get(url)

driver.implicitly_wait(10) # 隐式等待(单位是秒) 等到页面渲染完之后就不再等待
driver.maximize_window() # 最大化浏览器

# 用户名、密码
elem_user = driver.find_element_by_name("username")
elem_user.send_keys("账户")
elem_pwd = driver.find_element_by_name("password")
elem_pwd.send_keys("密码")
elem_pwd.send_keys(Keys.RETURN)

# 暂停20s,人为输入验证码
time.sleep(20)
elem_sub = driver.find_element_by_xpath('//input[@class="W_btn_a btn_34px"]')
elem_sub.click()    # 单击登录

print("登陆成功!")
driver.close()
driver.quit()

:由于微博登录时需要输入验证码,而验证码是在单击 “登录” 按钮之后才能看到的,所以用户在自动输入完账户密码后紧接着按回车键,弹出验证码提示,然后用 time.sleep(20) 函数设置暂停 20 s,并人为地输入验证码,方能成功登陆微博。下图给出输入账户、密码、验证码之后登陆成功的过程。

3 爬取微博热门信息

下面将讲解如何利用 Python 爬取微博某个主题的数据。

3.1 搜索所需的微博主题

在登陆微博之后,页面顶端会出现一个微博搜索框,用于关键字的微博搜索。同样,键盘按下 F12 键,用 “元素选择器” 选择目标位置查看其 HTML 源码。可以看到,位于 <input in="search_input"> 位置。

接着采用 driver. find_element_by_xpath() 函数定位搜索文本框的位置,核心代码如下:

elem_topic = driver.find_element_by_xpath("//input[@id='search_input']")
elem_topic.send_keys("高考")
elem_topic.send_keys(Keys.RETURN)

但是这里采用另一种方法输入关键字并搜索微博主题,即访问 “微博搜索” 页面(网址为:https://s.weibo.com/) ,定位搜索文本框的 HTML 源码如下:

调用 find_element_by_xpath() 函数定位搜索文本框,并按回车键进行搜索跳转,核心代码如下:

elem_topic = driver.find_element_by_xpath('//*[@id="pl_homepage_search"]/div/div[2]/div/input')
elem_topic.send_keys("高考")
elem_topic.send_keys(Keys.RETURN)

 微博搜索部分完整代码如下:

import time
import os
from selenium import webdriver
from selenium.webdriver.common.keys import Keys

# 打开 Chrome 浏览器,这顶等待加载时间
chromedriver = 'E:/software/chromedriver_win32/chromedriver.exe'
os.environ["webdriver.chrome.driver"] = chromedriver
driver = webdriver.Chrome(chromedriver)

try:
    # 访问新浪微博搜索页面
    url = 'https://s.weibo.com/'
    driver.get(url)

    driver.implicitly_wait(10) # 隐式等待(单位是秒) 等到页面渲染完之后就不再等待
    driver.maximize_window() # 最大化浏览器

    # 按回车键搜索主题
    elem_topic = driver.find_element_by_xpath('//*[@id="pl_homepage_search"]/div/div[2]/div/input')
    elem_topic.send_keys("高考")
    elem_topic.send_keys(Keys.RETURN)
    time.sleep(5)

except Exception as e:
    print('Error: ', e)

finally:
    print('爬取结束!')

3.2 爬取微博内容

当获得反馈搜索结果后就可以爬取对应的微博内容了。同样采用浏览器审查元素定位节点的技术,由于该技术可以识别所需爬取内容的 HTML 源码,所以被广泛应用于网络爬虫中。

3.2.1 需求分析

确定所获取微博内容的信息,如下图所示,获得的信息包括用户名、内容、发布时间、转发量、评论数和点赞数。其中,转发量、评论数和点赞数可以用来分析微博热门情况及用户画像等。

3.2.2 分析微博的 HTML 源码规律

分析微博 HTML 源码的分布规律时通常采用列表的形式反馈。比如搜索 “高考” 主题,他会反馈很多该主题的微博,然后依次分布,如下图所示。其中,每条微博的布局都是一样的,如上图所示,我们需要审查其源码,看其存在什么规律。按照之前所述的方法查看目标位置对应的 HTML 源码。

每条微博信息都位于 <div class="card-feed">...</div> 节点下,通过 find_elements_by_xpath() 函数可以获取多条微博信息,然后一次提取核心信息,如用户名、内容、发布时间、转发量、评论数和点赞数等。核心代码如下:

info = driver.find_elements_by_xpath('//div[@class="card-feed"]')

for value in info:
    print(value.text)
    content = value.text

 此时爬取的内容如下图所示,只需要使用正则表达式和字符串操作就可以依次提取所需的字段内容。

3.2.3 定位用户名

位于节点 <div class="info">...</div> 下的第一个超链接,其对应源码如下图所示:

Python 定位用户名的核心代码为:

YHM = driver.find_element_by_xpath('//*[@id="pl_feedlist_index"]/div[1]/div[6]/div[2]/div[1]/div[2]/div[1]/div[2]/a[1]')

最后,给出本文的所有代码,仅供参考:

import time
import os
from selenium import webdriver
from selenium.webdriver.common.keys import Keys

# 打开 Chrome 浏览器,这顶等待加载时间
chromedriver = 'E:/software/chromedriver_win32/chromedriver.exe'
os.environ["webdriver.chrome.driver"] = chromedriver
driver = webdriver.Chrome(chromedriver)


# 登录函数
def LoginWeibo(username, password):
    print('准备登录微博...')
    driver.get('https://login.sina.com.cn/')
    # 用户名、密码
    elem_user = driver.find_element_by_name("username")
    elem_user.send_keys(username)
    elem_pwd = driver.find_element_by_name("password")
    elem_pwd.send_keys(password)
    elem_pwd.send_keys(Keys.RETURN)

    # 暂停20s,人为输入验证码
    time.sleep(20)
    elem_sub = driver.find_element_by_xpath('//input[@class="W_btn_a btn_34px"]')
    elem_sub.click()    # 单击登录

    print("登陆成功!")

# 函数搜索主题
def SearchWeibo(topic):
    try:
        # 访问新浪微博搜索页面
        url = 'https://s.weibo.com/'
        driver.get(url)

        driver.implicitly_wait(10)  # 隐式等待(单位是秒) 等到页面渲染完之后就不再等待
        driver.maximize_window()  # 最大化浏览器

        # 按回车键搜索主题
        elem_topic = driver.find_element_by_xpath('//*[@id="pl_homepage_search"]/div/div[2]/div/input')
        elem_topic.send_keys(topic)
        elem_topic.send_keys(Keys.RETURN)
        time.sleep(5)

        # 获取用户名
        for i in range(1,11):
            elem_name = driver.find_elements_by_xpath('//*[@id="pl_feedlist_index"]/div[1]/div[{}]/div[2]/div[1]/div[2]/div[1]/div[2]/a[1]'.format(i))
            for value in  elem_name:
                print(value.text)

        # 获取内容
        for i in range(1,11):
            elem_content = driver.find_elements_by_xpath('//*[@id="pl_feedlist_index"]/div[1]/div[{}]/div[2]/div[1]/div[2]/p[1]'.format(i))
            for value in  elem_content:
                print(value.text)

        # 获取时间
        for i in range(1,11):
            elem_time = driver.find_elements_by_xpath('//*[@id="pl_feedlist_index"]/div[1]/div[{}]/div[2]/div[1]/div[2]/p[3]/a[1]'.format(i))
            for value in  elem_time:
                print(value.text)

        # 获取来自
        for i in range(1,11):
            elem_from = driver.find_elements_by_xpath('//*[@id="pl_feedlist_index"]/div[1]/div[{}]/div[2]/div[1]/div[2]/p[3]/a[2]'.format(i))
            for value in  elem_from:
                print(value.text)

        # 获取评论数
        for i in range(1, 11):
            elem_PLnumber = driver.find_elements_by_xpath('//*[@id="pl_feedlist_index"]/div[1]/div[{}]/div[2]/div[2]/ul/li[3]/a'.format(i))
            for value in elem_PLnumber:
                print(value.text)

        # 获取转发数
        for i in range(1, 11):
            elem_ZFnumber = driver.find_elements_by_xpath('//*[@id="pl_feedlist_index"]/div[1]/div[{}]/div[2]/div[2]/ul/li[2]/a'.format(i))
            for value in elem_ZFnumber:
                print(value.text)

        # 获取点赞数
        for i in range(1, 11):
            elem_DZnumber = driver.find_elements_by_xpath('//*[@id="pl_feedlist_index"]/div[1]/div[{}]/div[2]/div[2]/ul/li[4]/a/em'.format(i))
            for value in elem_DZnumber:
                print(value.text)

    except Exception as e:
        print('Error: ', e)

    finally:
        print('爬取结束!')

# 主函数
if __name__ == '__main__':
    # 定义用户名、密码
    username = '账户'
    password = '密码'
    topic = '高考'
    # 调用函数登录微博
    LoginWeibo(username, password)
    # 调用函数搜索热门主题
    SearchWeibo(topic)

4 本文小结

在使用 Python 设计网络爬虫的过程中,往往会遇到需要登录验证才能爬取数据的情况,甚至有的还需要输入验证码,比如微博、知乎、邮箱、QQ空间等。常见的解决方法是通过设置消息头 Headers 来实现模拟登录。本文介绍的是另一种方法,通过Selenium 技术访问浏览器,并操作鼠标和键盘自动输入用户名和密码,然后提交表单实现登录。如果在登录过程中需要输入验证码,则可以通过 time.sleep() 代码实现暂停,手动输入验证码后,实现登录再爬取所需要的信息,该方法可以解决微博登录、邮箱登录、百度登录、淘宝登录等问题。特别注意的是,在短时间内爬取海量数据时,有些网站的反爬虫技术会检测到你的爬虫,并封锁你当前的 IP,比如微博或者淘宝等,这就需要通过IP代理来实现。当然,更多实际情况下的应用还需进行深入研究分析。


欢迎留言,一起学习交流~

感谢阅读

END

猜你喜欢

转载自blog.csdn.net/IT_charge/article/details/107149950