如何使用selenium指挥浏览器操作?

1,403 阅读8分钟

前言

有时当我们使用BeautifulSoup时,会出现获取的标签内容为空的情况。这可能是因为这是一个动态网页,单单使用BeautifulSoup不足以支持我们爬取想要的信息。于是selenium闪亮登场,我们可以利用它实现对动态网页的爬取,本文将通过一个小案例,教大家快速学会selenium的使用。

页面分析

本文目标是利用selenium完成对央视新闻的爬取,内容包括标题、简述、以及新闻的详情页URL。

image.png 右键->点击检查或按F12打开开发者工具:

image-20220719222013240.png

如图,我们可以找到想要的信息,在找出规律后,只需知道什么是selenium以及怎么使用selenium就能达成目的了。

什么是selenium

它是一个强大的Python库,能用几行代码,控制浏览器,做出自动打开、输入、点击等动作,模拟用户操作。

举几个例子:

当访问验证码很复杂的网站时,selenium允许使用者只需手动输入验证码,然后把剩下的操作交由机器完成。

而对于那些交互复杂、加密复杂的网站,selenium把问题简化,爬动态网页如爬静态网页一样简单。

那什么是动态网页,什么又是静态网页呢?

对于静态网页,网页地址栏的URL就是网页源代码的URL,而网页源代码包含着网页的所有信息,且不会随时间或者数据库操作结果而发生改变,例如以.htm.html.xml.shtml作为后缀的网页。我们可以通过requests以及BeautifulSoup这两个库直接爬取,得到想要的信息。

但是对于动态网页,上面所说的套路就行不通了。因为有的数据并没有存在HTML源代码中,网页显示的内容会随着时间、或者数据库操作的结果而发生改变,例如php,jsp,asp等作为后缀的页面。这种情况下,selenium就派上用场了。

selenium又是怎么实现把动态网页转成静态网页呢?

实际上不论数据存在哪里,浏览器总是在向服务器发起各式各样的请求,当这些请求完成后,它们会一起组成开发者工具的Elements(元素)中所展示的渲染完成的网页源代码。selenium可以真实地打开一个浏览器,等待所有数据都加载到Elements(元素)中之后,再把这个网页当做静态网页爬取。

凡事都有两面性,由于要真实地运行本地浏览器,打开浏览器以及等待网渲染完成需要一些时间,selenium牺牲了速度,消耗了资源,但这是值得的。

怎么用selenium

selenium这么好用,它的常规套路是什么呢?与BeautifulSoup在解析和提取数据上有什么差别呢?使用文档在此,可以深入学习一下。接下来将围绕提出的两个问题,结合实例讲述。

selenium的安装

首先,我们需要安装selenium,可以使用pip安装:

# Windows电脑安装selenium
pip install selenium 
# Mac电脑安装selenium
pip3 install selenium 

selenium的脚本可以控制大部分常用的浏览器的操作,在使用之前,还需要安装浏览器的驱动。

这里以Chrome浏览器为例,点击该链接,选择自己浏览器对应版本的压缩包下载。

在浏览器的设置中查看使用版本 image.png

选择对应的压缩包,windows、Linux和Mac都有 image.png

通过查看notes.txt这个文件查看该驱动支持的浏览器版本(大版本相同即可) image.png

下载到本地后,将压缩文件解压,把驱动放到需要运行的项目目录下即可

设置浏览器引擎

selenium有点不同,除了调用,还需要设置浏览器引擎。

from selenium import webdriver #从selenium库中调用webdriver模块
driver = webdriver.Chrome() # 设置引擎为Chrome,真实地打开一个Chrome浏览器

把Chrome浏览器设置为引擎,然后赋值给变量driverdriver是实例化的浏览器,这很容易理解,因为我们要控制这个实例化的浏览器为我们做一些事情。

我们还是按照以往爬虫的套路来讲解selenium的用法,看看selenium如何获取、解析与提取数据。

获取数据

首先看一下获取数据的代码怎么写。

import time
#从selenium库中调用webdriver模块
from selenium import webdriver 
# 设置引擎为Chrome,真实地打开一个Chrome浏览器
driver = webdriver.Chrome() 
 # 打开网页
driver.get('https://news.cctv.com/')
time.sleep(2)
driver.close() # 调用了浏览器之后记得关闭浏览器。

get(URL)webdriver的一个方法,它的作用是打开指定URL的网页。

刚才说过driver是一个实例化的浏览器,因此,就是通过这个浏览器打开网页。

当一个网页被打开,网页中的数据就加载到了浏览器中,也就是说,数据被我们获取到了。

driver.close()是关闭浏览器,每次调用了webdriver之后,都要在用完它之后加上一行driver.close()用来关闭它。

解析与提取数据

selenium库同样具备解析数据、提取数据的能力。它和BeautifulSoup的底层原理一致,但在一些细节和语法上有出入。

首先明显的一个不同即是:selenium所解析提取的是Elements中的数据,而BeautifulSoup所解析的则只是Network中第0个请求的响应。

# 从selenium库中调用webdriver模块
from selenium import webdriver
# 导入By模块,用来定位元素
from selenium.webdriver.common.by import By
import time
# 设置引擎为Chrome,真实地打开一个Chrome浏览器
driver = webdriver.Chrome()
# 打开网页
driver.get('https://news.cctv.com/')
time.sleep(2)
# 根据id属性值定位到网页中的<ul>标签
element_ul = driver.find_element(By.ID, 'newslist')
# 提取<ul>标签中的所有<li>标签
elements_li = element_ul.find_elements(By.TAG_NAME, 'li')
# 打印element_ul
print(element_ul)
# 关闭浏览器
driver.close()

这里用time.sleep(2)等待两秒,是由于浏览器缓冲加载网页需要耗费一些时间,等待两秒再去解析和提取比较稳妥。

对于解析与提取数据,其实只用了两行代码:

# 根据id属性值定位到网页中的<ul>标签
element_ul = driver.find_element(By.ID, 'newslist')
# 提取<ul>标签中的所有<li>标签
elements_li = element_ul.find_elements(By.TAG_NAME, 'li') 

你觉得哪部分在做解析,哪部分在做提取?

使用BeautifulSoup解析提取数据时,首先要把Response对象解析为BeautifulSoup对象,然后再从中提取数据。

而在selenium中,获取到的网页存在了driver里面,之后,解析与提取是同时做的,都是由driver这个实例化的浏览器完成。

所以,答案是:解析数据是由driver自动完成的,提取数据是driver的一个方法。

清楚了解析与提取的本质,列举几个用来查找和提取元素的常用方法,用法都是类似的:

方法作用
driver.find_element(By.CSS_SELECTOR, '属性值')定位 CSS 选择器匹配的元素
driver.find_element(By.ID, '属性值')定位 id 属性与搜索值匹配的元素
driver.find_element(By.CLASS_NAME, '属性值')定位 class 属性与搜索值匹配的元素
driver.find_element(By.TAG_NAME, '标签名')定位标签名称与搜索值匹配的元素
driver.find_element(By.XPATH, '表达式值')定位与 XPath 表达式匹配的元素

selenium中的find_elementBeautifulSoup中的find类似,可以提取出网页中第一个符合要求的元素。

BeautifulSoup有提取所有元素的方法find_allselenium也同样有对应的方法,把刚才的element换成复数elements就行了,这里不再赘述。

提取出的数据(如:element_ulelements_li)属于WebElement类对象,如果直接打印它,返回的是一串对它的描述<class'selenium.webdriver.remote.webelement.WebElement'>

它与BeautifulSoup中的Tag对象类似,也有一个属性.text,可以把提取出的元素以字符串的形式显示。

它同样有一个方法,可以通过属性名提取属性的值,这个方法是.get_attribute()

WebElement类对象与Tag对象用法对比

WebElementTag作用
WebElement.textTag.text提取文字
WebElement.get_attribute(' ')Tag[' ']输入参数(属性名),可以提取属性值

以上就是selenium的基本用法,完善一下示例:

# 从selenium库中调用webdriver模块
from selenium import webdriver
# 导入入By模块,用来定位元素
from selenium.webdriver.common.by import By
import time
# 设置引擎为Chrome,真实地打开一个Chrome浏览器
driver = webdriver.Chrome()
# 打开网页
driver.get('https://news.cctv.com/')
time.sleep(2)

element_ul = driver.find_element(By.ID, 'newslist')

elements_li = element_ul.find_elements(By.TAG_NAME, 'li')

# 创建一个空列表,用于存储信息
list_all = []
# 遍历网页列表中的所有新闻
for li in elements_li:
    element_div = li.find_element(By.CLASS_NAME, 'text_con')
    element_a = element_div.find_element(By.TAG_NAME, 'h3').find_element(By.TAG_NAME,'a')
    title = element_a.text
    url = element_a.get_attribute('href')
    element_a2 = element_div.find_element(By.TAG_NAME, 'p').find_element(By.TAG_NAME, 'a')
    brief = element_a2.text
    list_all.append([title, brief, url])
# 关闭浏览器
driver.close()

for循环中反复利用关联查询,根据元素间的关系定位到想要的标签。这就完成了文章开头所说的任务,与使用BeautifulSoup相比,套路是类似的。

TIPS

# 本地Chrome浏览器的可视模式设置
from selenium import webdriver #从selenium库中调用webdriver模块
driver = webdriver.Chrome() # 设置引擎为Chrome,打开一个Chrome浏览器

对于本文所示的设置方法,我们可以看到浏览器的操作过程。

image.png

但在做爬虫时,通常不需要打开浏览器,爬虫的目的是爬到数据,而不是观看浏览器的操作过程,在这种情况下,就可以使用浏览器的静默模式,也就是说,让浏览器只在后台运行。

它的设置方法是这样的:

# 本地Chrome浏览器的静默模式设置:
# 从selenium库中调用webdriver模块
from selenium import webdriver
# 从options模块中调用Options类
from selenium.webdriver.chrome.options import Options

# 实例化Option对象
chrome_options = Options() 
# 对浏览器的设置
chrome_options.add_argument('--headless') 
# 设置浏览器引擎
driver = webdriver.Chrome(options=chrome_options) 

END

以上就是这篇文章的主要内容,本人水平有限,难免有遗漏或出错,烦请各位掘友多多指教。