Python编程进阶知识之第二课学习网络爬虫(selenium)

selenium库是一种用于 Web 应用程序测试的工具,它可以驱动浏览器执行特定操作,自动按照脚本代码做点击、输入、打开、验证等操作,支持的浏览器包括 IE、Firefox、Safari、Chrome、Opera 等。而在办公自动化中如果经常需要使用浏览器操作某些内容,就可以使用selenium库来实现,例如将大量数据上传到网页中,与requests库不同的是,selenium库是基于浏览器的驱动程序来驱动浏览器执行操作的。且浏览器可以渲染网页代码,因此通过selenium库还可以轻松获取网页中渲染后的数据信息。

1.使用 selenium 库前的准备

1. selenium 库驱动浏览器的原理

浏览器是在浏览器内核基础之上开发而成的,浏览器内核主要负责对网页语法进行解释并渲染(显示)网页。例如 360 浏览器和 Chrome 浏览器都使用 Chrome 内核, 虽然浏览器内核可以被selenium库驱动,但还是需要安装对应版本的浏览器内核驱动程序,以便于控制 Web 浏览器的行为。每个浏览器都有一个特定的用于支持浏览器运行的 WebDriver,被称为驱动程序。

2.安装 WebDriver

这里以 edge浏览器为例,开始介绍安装浏览器内核驱动程序 WebDriver 的方法。

查看浏览器内核(版本)

打开Microsoft Edge WebDriver | Microsoft Edge Developer,选择自己对应版本进行下载。

下载后解压将 msedgedriver.exe给添加到自己Python的安装目录中Scripts中,如

C:\Users\DELL\AppData\Local\Programs\Python\Python39\Scripts

完成这几步就安装完成了

3.安装selenium库

在命令提示符窗口或终端中执行以下命令:

python 复制代码
pip install selenium

2.驱动浏览器

selenium库支持的浏览器包括 Chrome、IE 7~11、Firefox、Safari、Opera、Edge、HtmlUnit、PhantomJS 等,几乎覆盖了当前计算机端和手机端的所有类型的浏览器。在selenium库源代码文件夹下的webdriver中可查看所有支持的浏览器类型

python 复制代码
webdriver.浏览器类型名()

例如驱动 Chrome 浏览器的使用方法为webdriver.Edge(),当调用webdriver.Edge()时,会默认调用Edge/webdriver.py文件中的类WebDriverwebdriver.Edge()的使用形式如下:

python 复制代码
webdriver.Edge(executable_path = "chromedriver", port = 0, options = None)
  • 功能:创建一个新的edge浏览器驱动程序。
  • 参数executable_path:表示浏览器的驱动路径,默认为环境变量中的path,通常计算机中可能存在多个浏览器软件,当没有在环境变量中设置浏览器path时,可以使用参数options
  • 参数port:表明希望服务运行的端口,如果保留为 0,驱动程序将会找到一个空闲端口。
  • 参数options:表示由类Options(位于selenium/webdriver/edge/options.py)创建的对象,用于实现浏览器的绑定。
python 复制代码
from selenium import webdriver
from selenium.webdriver.edge.options import Options
edge_options = Options()
edge_options.binary_location = r"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe"                 
driver = webdriver.Edge(options=edge_options)

第 3 行代码使用类 Options 创建了一个对象 edge_options,使用 binary_location () 方法绑定了浏览器。

第 5 行代码使用 webdriver.Edge () 设置 options 参数值为绑定 edge浏览器的对象 edge_options。执行代码后将会自动打开 edge浏览器,实现驱动浏览器的第一步。

binary_location () 方法绑定了浏览器的路径是自己桌面上浏览器的位置。

3.加载网页

使用类 webdriver.Chrome 创建的驱动浏览器对象中包含大量操作浏览器的方法,类 webdriver.Chrome 基于基础类 WebDriver,该类位于 selenium 库webdriver\remote\webdriver.py 文件中。

类 WebDriver 的简洁定义:

python 复制代码
class WebDriver(object):
    def __init__(self, ...):
        self.file_detector = ...
    def name(self):
        ...
    def start(self):
        ...
    def start_client(self):
        ...
    def stop_client(self):
        ...
    def start_session(self, ...):
        ...
    def create_web_element(self, ...):
        ...
    def execute(self, ...):
        ...
    def get(self, url):
        ...
    def title(self):
    ...
    # 返回当前网页的标题
    def find_element_by_id(self, id_):
    ...
    # 通过标签id获取网页中的一个元素
    def find_elements_by_id(self, id_):
    ...
    # 通过标签id获取网页中的多个元素
    def find_element_by_xpath(self, xpath):
    ...
    # 通过xpath获取网页元素,xpath是与正则表达式类似的一种语法规则
    def find_elements_by_xpath(self, xpath):
    ...
    # 通过xpath获取网页中的多个元素
    def find_element_by_link_text(self, link_text):
    ...
    # 通过链接文本获取网页中的一个元素
    def find_elements_by_link_text(self, link_text):
    ...
    # 通过链接文本获取网页中的多个元素
    def find_element_by_partial_link_text(self, link_text):
    ...
    # 通过元素链接文本的部分匹配来查找一个元素
    def find_elements_by_partial_link_text(self, link_text):
    ...
    # 通过元素链接文本的部分匹配来查找多个元素
    def find_element_by_name(self, name):
    ...
    # 通过标签name获取网页中的一个元素
    def find_elements_by_name(self, name):
    ...
    # 通过标签name获取网页中的多个元素
    def find_element_by_tag_name(self, name):
    ...
    # 通过标签名称获取网页中的一个元素
    def find_elements_by_tag_name(self, name):
    ...
    # 通过标签名称获取网页中的多个元素
    def find_element_by_class_name(self, name):
    ...
    # 通过标签class获取网页中的一个元素
    def find_elements_by_class_name(self, name):
    ...
    # 通过标签class获取网页中的多个元素
    def find_element_by_css_selector(self, css_selector):
    ...
    # 通过CSS选择器获取网页中的一个元素
    def find_elements_by_css_selector(self, css_selector):
    ...
    # 通过CSS选择器获取网页中的多个元素
    def execute_script(self, script, *args):
    ...
    # 同步执行当前窗口/框架中的JavaScript脚本
    def execute_async_script(self, script, *args):
    ...
    # 异步执行当前窗口/框架中的JavaScript脚本
    def current_url(self):
    ...
    # 获取当前网页的URL
    def page_source(self):
    ...
    # 获取当前网页的源代码
    def close(self):
    ...
    # 关闭当前窗口
    def quit(self):
    ...
    # 退出驱动程序并关闭所有相关的窗口
    def current_window_handle(self):
    ...
    # 返回当前窗口的句柄(浏览器中每个标签页为一个句柄)
    def window_handles(self):
    ...
    # 返回当前会话中所有窗口的句柄
    def maximize_window(self):
    ...
    # 最大化当前窗口
    def fullscreen_window(self):
    ...
    # 调用特定于窗口管理器的"全屏"操作
    def minimize_window(self):
    ...
    # 调用特定于窗口管理器的"最小化"操作
    def switch_to(self):
    ...
    # 返回一个包含所有可切换焦点的选项对象
    def back(self):
    ...
    # 在浏览器历史中倒退了一页
    def forward(self):
    ...
    # 在浏览器历史中前进了一页
    def refresh(self):
    ...
    # 刷新当前页面
    def get_cookies(self):
    ...
    # 返回一组字典,对应于当前会话中可见的cookie
    def get_cookie(self, name):
    ...
    # 按名称获取单个Cookie
    def delete_cookie(self, name):
    ...
    # 删除指定名称的单个Cookie
    def delete_all_cookies(self):
    ...
    # 删除该会话范围内的所有Cookie
    def add_cookie(self, cookie_dict):
    ...
    # 将Cookie添加到当前会话中
    def implicitly_wait(self, time_to_wait):
    ...
    # 设置超时以隐式等待找到元素或完成命令
    def set_script_timeout(self, time_to_wait):
    ...
    # 设置脚本等待时间
    def set_page_load_timeout(self, time_to_wait):
    ...
    # 设置页面加载完成的超时时间
    def find_element(self, by=By.ID, value=None):
    ...
    # 查找一个元素
    def find_elements(self, by=By.ID, value=None):
    ...
    # 查找多个元素
    def desired_capabilities(self):
    ...
    # 返回正在使用的驱动程序当前所需的功能
    def get_screenshot_as_file(self, filename):
    ...
    # 将当前窗口的截图保存为.png格式图片
    def save_screenshot(self, filename):
    ...
    # 将当前窗口的截图保存为.png格式图片
    def get_screenshot_as_png(self):
    ...
    # 以二进制数据的形式获取当前窗口的截图
    def get_screenshot_as_base64(self):
    ...
    # 获取当前窗口的截图
    def set_window_size(self, width, height, windowHandle='current'):
    ...
    # 设置当前窗口的宽度和高度
    def get_window_size(self, windowHandle='current'):
    ...
    # 获取当前窗口的宽度和高度
    def set_window_position(self, x, y, windowHandle='current'):
    ...
    # 设置当前窗口的位置

下面介绍两种常用的加载浏览器网页的方法。

**1.**get () 方法

get () 方法用于打开指定的网页。其使用形式如下:

python 复制代码
driver.get(url)
python 复制代码
from selenium import webdriver
from selenium.webdriver.edge.options import Options
edge_options = Options()
edge_options.binary_location = r""
driver = webdriver.Edge(options=edge_options)
driver.get("https://www.ptpress.com.cn/periodical")

第 6 行代码使用 get () 方法加载人民邮电出版社官网的期刊页,执行代码后将会自动启动 edge 浏览器并加载出相应网页

2.execute_script () 方法

execute_script () 方法用于打开多个标签页,即在同一浏览器中打开多个网页。其使用形式如下:

python 复制代码
driver.execute_script(script, *args)

功能:打开标签页,同步执行当前页面中的 JavaScript 脚本。JavaScript 是网页中的一种编程语言。

参数 script:表示将要执行的脚本内容,数据类型为字符串类型。使用 JavaScript 语言实现打开一个新标签页的语法形式为 "window.open (' 网址 url','_blank');"。

python 复制代码
from selenium import webdriver
from selenium.webdriver.edge.options import Options
edge_options = Options()
edge_options.binary_location = r""
driver = webdriver.Edge(options=chrome_options)
driver.execute_script("window.open('https://www.ptpress.com.cn/login', '_blank');")
driver.execute_script("window.open('https://www.shuyishe.com/', '_blank');")
driver.execute_script("window.open('https://www.shuyishe.com/course', '_blank');")

第 7~9 行代码使用 execute_script () 方法执行括号中的 JavaScript 脚本,打开的新标签页分别为人民邮电出版社登录页面、数艺设的主页、数艺设的课程页面。

4.获取渲染后的网页代码

通过 get () 方法获取浏览器中的网页资源后,浏览器将自动渲染网页源代码内容,并生成渲染后的网页。此时使用 page_source () 方法即可获取渲染后的网页代码。

python 复制代码
from selenium import webdriver
from selenium.webdriver.edge.options import Options
edge_options = Options()
edge_options.binary_location = r""
driver = webdriver.Edge(options=edge_options)
driver.get('https://www.ptpress.com.cn/')
print(driver.page_source)

第 7 行代码使用 driver 对象中的 page_source () 方法获取被 get () 方法获取到的渲染后的网页源代码。

5.获取和操作网页元素

1.获取网页中的指定元素

在获取了网页端某个元素后,就可以使用一下方法对此元素进行相应的操作

tag_name () 方法:获取元素的名称。

text () 方法:获取元素的文本内容。

click () 方法:单击此元素。

submit () 方法:提交表单。

send_keys () 方法:模拟输入信息。

size () 方法:获取元素的尺寸。

可进入 selenium 库文件夹下的 webdriver\remote\webelement.py 中查看更多的操作方法。

2.在元素中输入信息

send_keys () 方法可以实现在元素中输入信息,例如在窗口标签中输入信息。其使用形式如下:

python 复制代码
send_keys(value)
python 复制代码
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.keys import Keys
edge_options = Options()
edge_options.binary_location = r""
driver = webdriver.Edge(options=edge_options)
driver.get('https://www.ptpress.com.cn/')
driver.find_element_by_tag_name("input").send_keys("Python")

第 8 行代码使用 find_element_by_tag_name () 方法找到标签名为 input 的元素(通过网页源代码可知搜索框的标签名为 input)。获取到标签后使用 send_keys () 方法实现在搜索框内输入字符串 "Python"。

对于不同的搜索框标签,其标签名可能不同,需要提前在网页源代码中确定标签名。

实现在搜索框中输入信息的代码程序后,还可以模拟用户的按键操作,其使用方法为在字符串后面继续追加按键转义字符串信息。

python 复制代码
from selenium import webdriver
from selenium.webdriver.edge.options import Options
from selenium.webdriver.common.keys import Keys
edge_options = Options()
edge_options.binary_location = r""
driver = webdriver.Edge(options=edge_options)
driver.get("https://www.ptpress.com.cn/")
driver.find_element_by_tag_name("input").send_keys("Python" + Keys.RETURN)

上述代码在之前代码的基础上仅对第 8 行进行了修改,新行代码在 send_keys () 方法中增加了 Keys.RETURN。Keys.RETURN 表示按 Enter 键,这源于第 3 行代码导入的类 Keys,类 Keys 中定义了大部分按键的转义字符串。下面展示了类 Keys 在源代码中对按键的定义

类 Keys 的定义:

python 复制代码
class Keys(object):
    """
    Set of special keys codes.
    """
    NULL = '\ue000'
    CANCEL = '\ue001'  # ^break
    HELP = '\ue002'
    BACKSPACE = '\ue003'
    TAB = '\ue004'
    CLEAR = '\ue005'
    RETURN = '\ue006'
    ENTER = '\ue007'
    SHIFT = '\ue008'
    LEFT_SHIFT = '\ue009'
    CONTROL = '\ue00a'
    LEFT_CONTROL = '\ue00b'
    ALT = '\ue00c'
    LEFT_ALT = '\ue00d'
    PAUSE = '\ue00e'
    ESCAPE = '\ue00f'
    SPACE = '\ue010'
    PAGE_UP = '\ue011'
    PAGE_DOWN = '\ue012'
    END = '\ue013'
    HOME = '\ue014'
    LEFT = '\ue015'
    ARROW_LEFT = '\ue015'
    UP = '\ue016'
    ARROW_UP = '\ue016'
    RIGHT = '\ue017'
    ARROW_RIGHT = '\ue017'
    DOWN = '\ue018'
    ARROW_DOWN = '\ue018'
    INSERT = '\ue019'
    DELETE = '\ue01a'
    SEMICOLON = '\ue01b'
    EQUALS = '\ue01c'
    NUMPAD0 = '\ue01d'
    NUMPAD1 = '\ue01e'
    NUMPAD2 = '\ue01f'
    NUMPAD3 = '\ue020'
    NUMPAD4 = '\ue021'
    NUMPAD5 = '\ue022'
    NUMPAD6 = '\ue023'
    NUMPAD7 = '\ue024'
    NUMPAD8 = '\ue025'
    NUMPAD9 = '\ue026'
    MULTIPLY = '\ue027'
    ADD = '\ue028'
    SEPARATOR = '\ue029'
    SUBTRACT = '\ue02a'
    DECIMAL = '\ue02b'
    DIVIDE = '\ue02c'
    F1 = '\ue031'
    F2 = '\ue032'
    F3 = '\ue033'
    F4 = '\ue034'
    F5 = '\ue035'
    F6 = '\ue036'
    F7 = '\ue037'
    F8 = '\ue038'
    F9 = '\ue039'
    F10 = '\ue03a'
    F11 = '\ue03b'
    F12 = '\ue03c'
    META = '\ue03d'
    COMMAND = '\ue03d'

6.实现上传图片

实现在百度识图官网中上传一张图片。

python 复制代码
from selenium import webdriver
from selenium.webdriver.edge.options import Options
edge_options = Options()
edge_options.binary_location = r""
driver = webdriver.Edge(options=edge_options)
driver.get("https://graph.baidu.com/pcpage/index?tpl_from=pc")
# 找到文件上传元素
file_input = driver.find_element_by_name("file")
# 输入图片路径
file_input.send_keys(r"E:\书\代码\识图.jpg")

第 7 行代码使用 find_element_by_name () 方法找到标签名为 file 的元素。

第 9 行代码直接使用 send_keys () 方法将图片路径以字符串的形式写入标签名为 file 的元素中,至此即可实现上传图片。执行代码后将自动打开百度识图官网,并将 "E:\ 书 \ 代码 \ 识图.jpg" 图片上传到网站中自动进行识别.

7.更多操作

1.模拟单击

获取网页元素后可以使用 click () 方法模拟单击元素,即模拟单击网页中的某个元素所在的位置。为了更方便且快速地进入用户需要访问的网页,接下来将使用 click () 方法实现单击人民邮电出版社官网中的 "图书"

python 复制代码
from selenium import webdriver
from selenium.webdriver.edge.options import Options
edge_options = Options()
edge_options.binary_location = r""
driver = webdriver.Edge(options=edge_options)
driver.get("https://www.ptpress.com.cn/periodical")
elements = driver.find_elements_by_class_name("item")
for element in elements:
    print(element.text)

第 7 行代码使用 find_elements_by_class_name () 找到所有 class 名为 item 的元素。通过分析网页代码可知,要单击的位置处存在多个元素名称及 class 名称相同的元素,因此在使用 find_elements_by_class_name () 前要先获取 class 名称为 item 的所有元素。

第 8~11 行代码使用 for 循环分别遍历输出每个元素的内容,以便于找到需要的标签索引。

第 12 行代码确定了 "图书" 在 elements 列表中的索引为 3,并执行 click () 方法实现单击。

2.WebDriver 对象中的方法

python 复制代码
back()

功能:返回到上一个页面。

python 复制代码
forward()

功能:前进到下一个页面。

python 复制代码
refresh()

功能:刷新当前页面。

python 复制代码
quit()

功能:关闭当前浏览器。

python 复制代码
close()

功能:关闭当前标签页(一个浏览器窗口中展示的每一个网页为一个标签页,当前标签页指当前正在显示的网页)。

python 复制代码
from selenium import webdriver
from selenium.webdriver.edge.options import Options
import time
edge_options = Options()
edge_options.binary_location = r""
driver = webdriver.Edge(options=edge_options)
driver.get('https://www.ptpress.com.cn/')
elments = driver.find_elements_by_class_name("item")
elments[3].click()      #点击图书
driver.back()           #返回上一页
time.sleep(5)           
driver.forward()        #前进一页
time.sleep(5)           
driver.refresh()        #刷新网页
time.sleep(5)   
driver.quit()           #关闭浏览器

第 10 行代码使用 back () 方法实现返回上一个页面,即从图书页返回到官网主页。

第 12 行代码使用 forward () 方法再次从官网主页前进到图书页。

第 14 行代码使用 refresh () 方法实现刷新页面。

第 16 行代码使用 quit () 方法自动关闭当前的浏览器

而 sleep (5) 函数,这是为了避免代码执行过快而加入的暂停操作,便于观察显示效果。

3.不启动浏览器也能获取网页资源

在通过代码获取网页中的资源时,往往并不需要启动浏览器,因为用户需要获取的是处理后的结果,而不是展现的过程。因此在驱动浏览器时,可以设置无窗口模式,即驱动浏览器后并不会打开浏览器窗口,而是将网页代码在内存中处理,类 Options 中的 add_argument () 方法即可实现在不启动浏览器的情况下获取网页资源。其使用形式如下(写入参数 '--headless' 即表明不启动浏览器窗口):

python 复制代码
chrome_options.add_argument('--headless')
python 复制代码
from selenium import webdriver
from selenium.webdriver.edge.options import Options
edge_options = Options()
edge_options.add_argument('--headless')
edge_options.binary_location = r""
driver = webdriver.Chrome(options=edge_options)
driver.get("https://www.ptpress.com.cn/")
elements = driver.find_elements_by_tag_name("a")
for element in elements:
    print(element.text)

第 4 行代码设置浏览器启动无窗口模式。因此执行代码后虽然不会显示浏览器,但浏览器仍然会在内存中进行网页数据处理。

第 9~10 行代码获取人民邮电出版社官网中所有标签名为 a 的文本内容。读者可自行实践操作并观察执行代码后的显示效果。