【Python爬虫】Selenium自动化框架


准备工作

Selenium是当下较为流行的Python自动化处理框架,适配多种主流浏览器,可以用来处理爬虫过程中的各类反爬验证操作。在使用前首先要安装Selenium库、浏览器以及对应浏览器的驱动程序。

一、安装库

可以使用pipconda安装。

# pip安装
pip install selenium

# pip镜像安装
pip install selenium -i https://pypi.tuna.tsinghua.edu.cn/simple

# conda安装
conda install selenium

二、安装浏览器与驱动程序

兼容浏览器 Mozilla Firefox / Google Chrome / Microsoft Edge / Safari 等主流浏览器,默认电脑已经安装,必须有对应的浏览器才可以进行自动化控制。

下面以Chrome为例演示谷歌浏览器的驱动程序安装过程。

方式一:手动安装

  • 查看浏览器版本

    在浏览器的地址栏键入Chrome://version

  • 选择对应版本号的驱动版本

    下载地址:CNPM Binaries Mirror (npmmirror.com)

    下载地址:https://chromedriver.chromium.org/home

  • 配置环境变量(可不配,直接使用驱动的绝对路径)

方式二:自动安装

  • 安装第三方库webdriver_manager

    pip install webdriver_manager
    
  • 调用第三方库的方法

    from selenium import webdriver
    from selenium.webdriver.common.keys import Keys
    from webdriver_manager.chrome import ChromeDriverManager
    
    # 自动安装驱动,会自动获取当前浏览器的版本并去下载对应的驱动到本地
    # 如果本地已经有该浏览器渠道,则会提示其已存在
    browser = webdriver.Chrome(ChromeDriverManager().install())
    
    browser.get('http://www.baidu.com')
    search = browser.find_element_by_id('kw')
    search.send_keys('python')
    search.send_keys(Keys.ENTER)
    
    # 关闭浏览器
    browser.close()
    

基本用法

一、浏览器对象

浏览器对象是自动化程序的锚点,所有操作都绑定在浏览器对象上进行,需根据对应的浏览器和浏览器驱动生成对应的浏览器对象。

from selenium import webdriver

# 初始化浏览器为chrome浏览器
browser = webdriver.Chrome()

# 指定绝对路径的方式
path = r'C:\Users\Gdc\.wdm\drivers\chromedriver\win32\96.0.4664.45\chromedriver.exe'
browser = webdriver.Chrome(path)

# 关闭浏览器
browser.close()

"""
拓展:通过option参数指定浏览器对象的形式
1. 初始化无界面chrome浏览器
    option = webdriver.ChromeOptions()
    option.add_argument("--headless")
    browser = webdriver.Chrome(options=option)
2. 设置编码格式
	options = webdriver.ChromeOptions()
    options.add_argument('lang=zh_CN.UTF-8')
    browser = webdriver.Chrome(options=options)
3. 添加请求头
	options = webdriver.ChromeOptions()
    options.add_argument('user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.182 Safari/537.36"')
    browser = webdriver.Chrome(options=options)
4. 禁止加载图片
	options = webdriver.ChromeOptions()
    options.add_argument('blink-settings=imagesEnabled=false')
    browser = webdriver.Chrome(options=options)
5. 禁用浏览器弹窗
	options = webdriver.ChromeOptions()
    prefs = {
        'profile.default_content_setting_values': {
            'notifications': 2
        }
    }
	options.add_experimental_option('prefs', prefs)
    browser = webdriver.Chrome(options=options)
6. 禁用JavaScript
	options = webdriver.ChromeOptions()
    options.add_argument('--disable-javascript')
    browser = webdriver.Chrome(options=options)
7. 隐藏滚动条
	options = webdriver.ChromeOptions()
    options.add_argument('--hide-scrollbars')
    browser = webdriver.Chrome(options=options)
8. 以最高权限运行
	options = webdriver.ChromeOptions()
    options.add_argument('--no-sandbox')
    browser = webdriver.Chrome(options=options)
9. 添加指定插件运行
	options = webdriver.ChromeOptions()
    extension_path = '想要加载的插件路径'
    options.add_extension(extension_path)
    browser = webdriver.Chrome(options=options)
""" 

二、浏览器窗口操作

用户在生成浏览器对象之后可以对浏览器窗口进行一定的基础调整,例如调整窗口大小、使用代码刷新页面、使用代码前翻页面后翻页面等。

2.1 调整窗口大小

调用浏览器对象set_window_size()方法可以用来设置浏览器大小(分辨率)。
调用浏览器对象maximize_window()方法可以设置浏览器为全屏。

from selenium import webdriver
import time  

browser = webdriver.Chrome()

# 设置浏览器大小为全屏
browser.maximize_window()   
browser.get(r'https://www.baidu.com')  
time.sleep(2)

# 设置分辨率为500*500
browser.set_window_size(500,500)  
time.sleep(2)

# 设置分辨率为1000*800
browser.set_window_size(1000,800) 
time.sleep(2)

# 关闭浏览器
browser.close()

2.2 页面刷新

调用浏览器对象refresh()方法用以进行浏览器对象的页面刷新,相当于F5键。

from selenium import webdriver
import time  

browser = webdriver.Chrome()

# 设置浏览器全屏
browser.maximize_window()   
browser.get(r'https://www.baidu.com')  
time.sleep(2)

try:
    # 刷新页面
    browser.refresh()  
    print('刷新页面')
except Exception as e:
    print('刷新失败')

# 关闭浏览器
browser.close()

2.3 前进与后退

调用浏览器对象forward()方法可以用来实现前进。
调用浏览器对象back()方法可以用来实现后退。
读者可自行尝试,这里不做代码示例。

2.4 窗口切换

  • Frame切换

    使用浏览器对象switch_to_frame()方法进行指定id的切换,需要传入切换目标的id作为参数。

    若想回到父页面,需要使用浏览器对象switch_to.parent_frame()方法。

  • 选项卡切换

    """
    current_window_handle:获取当前窗口的句柄。
    window_handles:返回当前浏览器的所有窗口的句柄。
    switch_to_window():用于切换到对应的窗口。
    """
    # 打开百度
    browser.get('http://www.baidu.com')
    # 新建一个选项卡
    browser.execute_script('window.open()')
    # 将操作焦点切换到新建的选项卡并跳转到知乎
    browser.switch_to.window(browser.window_handles[1])
    browser.get('http://www.zhihu.com')
    # 回到第一个选项卡并打开淘宝(原来的百度页面改为了淘宝)
    browser.switch_to.window(browser.window_handles[0])
    browser.get('http://www.taobao.com')
    

三、获取页面属性

此小节为操作重点,在生成浏览器对象之后需要通过各种方式定位网页标签并获取用户所需的内容和数据。

3.1 获取页面的基础属性

有一些基础属性如网页标题、网址、浏览器名称、页面源码等信息均可以通过浏览器对象的属性获取。

from selenium import webdriver

browser = webdriver.Chrome()
browser.get(r'https://www.baidu.com') 

# 网页标题
# 输出“百度一下,你就知道”
print(browser.title)

# 当前网址
# 输出https://www.baidu.com/
print(browser.current_url)

# 浏览器名称
# 输出chrome
print(browser.name)

# 网页源码
# 输出html源码,可以继续通过xml解析
print(browser.page_source)

3.2 定位页面元素

  • 通过id定位元素

    使用浏览器对象find_element_by_id()方法,传入页面元素的id,返回值即为该元素。

    # 获取百度的搜索框,对应id为kw
    browser.get(r'https://www.baidu.com')
    input_obj = browser.find_element_by_id('kw')
    
  • 通过name定位元素

    使用浏览器对象find_element_by_name()方法,传入页面元素的name,返回值即为该元素。

    多个相同name元素不一定能定位成功。

    # 获取百度的搜索框,对应name为wd
    browser.get(r'https://www.baidu.com')
    input_obj = browser.find_element_by_name('wd')
    
  • 通过class定位元素

    使用浏览器对象find_element_by_class_name()方法,传入页面元素的class,返回值即为该元素。

    多个相同class元素不一定能定位成功。

    # 获取百度的搜索框,对应class为s_ipt
    browser.get(r'https://www.baidu.com')
    input_obj = browser.find_element_by_class_name('s_ipt')
    
  • 通过tag定位元素

    tag是指HTML元素的类型,常见有inputtablesubmit等,使用浏览器对象find_element_by_tag_name()方法,传入页面元素的tag,返回值即为该元素。

    由于同个页面中会出现很多相同类型的元素,该方法不常用。

    # 获取百度的搜索框,对应tag为input
    browser.get(r'https://www.baidu.com')
    input_obj = browser.find_element_by_tag_name('input')
    
  • 通过链接文本定位元素

    使用浏览器对象find_element_by_link_text()方法,传入对应的链接文本,返回值即为该元素。

    若对应的链接文本过长,可以使用模糊匹配find_element_by_partial_link_text()

    # 获取百度的新闻导航(全匹配)
    browser.get(r'https://www.baidu.com')
    news_nav = browser.find_element_by_link_text('新闻')
    
    # 获取百度的新闻导航(模糊匹配)
    news_nav = browser.find_element_by_partial_link_text('闻')
    
  • 通过xpath定位元素

    以上几种方法都是通过唯一的属性值来定位元素,除id外,其余属性并不是一直都是唯一的,因此使用以上方法定位元素都显得过于理想,而xpath是通过元素在HTML代码中的位置定位的,相较以上几种定位元素的方法在实际场景中更为常用。

    使用浏览器对象find_element_by_xpath()方法,传入对应的xpath,返回值即为该元素。

    # 获取百度的搜索框
    browser.get(r'https://www.baidu.com')
    input_obj = browser.find_element_by_xpath("//*[@id='kw']")
    
  • 通过css筛选器定位元素

    相比xpath更好理解,定位速度也更快。

    使用浏览器对象find_element_by_css_selector()方法,传入对应的css筛选条件,返回值即为该元素。

    # 获取百度的搜索框
    browser.get(r'https://www.baidu.com')
    # css筛选条件需要补充对应的css知识,此处根据id筛选
    input_obj = browser.find_element_by_css_selector('#kw')
    
  • 通用方法find_element()定位

    需传入两个参数:定位方式以及定位属性值

    from selenium.webdriver.common.by import By
    from selenium import webdriver
    
    browser = webdriver.Chrome()
    browser.get(r'https://www.baidu.com')
    
    # 以下代码与上述几种定位方式等同
    browser.find_element(By.ID,'kw')
    browser.find_element(By.NAME,'wd')
    browser.find_element(By.CLASS_NAME,'s_ipt')
    browser.find_element(By.TAG_NAME,'input')
    browser.find_element(By.LINK_TEXT,'新闻')
    browser.find_element(By.PARTIAL_LINK_TEXT,'闻')
    browser.find_element(By.XPATH,'//*[@id="kw"]')
    browser.find_element(By.CSS_SELECTOR,'#kw')
    
  • 定位多个元素

    使用浏览器对象find_elements()方法,得到的结果会是列表形式,其余操作与以上find_element一致,取对应第几个元素时仅需对返回的列表切片。

3.3 获取页面元素的属性

  • get_attribute()方法

    只要对应的元素中有属性,即可将该属性作为参数传入获取。

    browser.get(r'https://www.baidu.com')  
    logo = browser.find_element_by_css_selector('#hotsearch-content-wrapper > li:nth-child(1) > a')
    
    # 获取logo的链接
    print(logo.get_attribute('href'))
    
  • 点方法

    • id: 获取元素的id
    • location:获取元素在页面上距离左上(0,0)的位置
    • size:获取元素在页面上显示的宽和高
    • tag_name:获取元素的标签属性
    browser.get(r'https://www.baidu.com')  
    logo = browser.find_element_by_css_selector('#hotsearch-content-wrapper > li:nth-child(1) > a')
    
    print(logo.id)  # 6af39c9b-70e8-4033-8a74-7201ae09d540
    print(logo.location)  # {'x': 490, 'y': 46}
    print(logo.size)  # {'height': 129, 'width': 270}
    print(logo.tag_name)  # img
    

四、交互操作

此小节为操作重点,在生成浏览器对象之后需要通过各种方式对网页标签进行交互以模拟真实用户的操作。

4.1 网页标签交互

定位至指定网页标签元素后,即可对其进行交互操作。

  • 输入文本

    使用元素对象send_keys()方法对输入框等元素进行文本输入。

    # 定位搜索框,并在其中输入'python'
    input_obj = browser.find_element_by_class_name('s_ipt')
    input_obj.send_keys('python')
    
  • 清除文本

    使用元素对象clear()方法对输入框等元素进行文本清除。

    # 定位搜索框,清除当前的输入
    input_obj = browser.find_element_by_class_name('s_ipt')
    input_obj.clear()
    
  • 点击

    使用元素对象click()方法对按钮等元素进行点击。

    # 定位新闻导航,并点击跳转
    news_nav = browser.find_element_by_link_text('新闻')
    news_nav.click()
    
  • 回车

    回车可以用于表单控件的提交(其实也可以定位到提交按钮然后通过click()点击。

    使用元素对象submit()方法对表单控件的输入进行提交。

    # 定位搜索框,在其中输入'python',回车查找
    input_obj = browser.find_element_by_class_name('s_ipt')
    input_obj.send_keys('python')
    input_obj.submit()
    
  • 单选

    定位某一单个元素,通过click()点击选中。

  • 多选

    依次定位某些元素,通过click()点击选中。

  • 下拉框

    假设下拉框HTML代码为:

    <form>
        <select name="selection">
        <option value="1" selected></option>
        <option value="2"></option>
        <option value="3"></option>
        <option value="4"></option>
        </select>
    </form>
    

    使用Select类对其进行处理。

    # 需要引入Select类
    from selenium.webdriver.support.select import Select
    
    # 定位到需要操作的下拉框,初始化Select类
    select_obj = Select(browser.find_element_by_id("selection"))
    
    """
    三种选择某一选项项的方法
    select_by_index()           # 通过索引选中;注意:index索引是从“0”开始。
    select_by_value()           # 通过value值选中,value标签的属性值。
    select_by_visible_text()    # 通过文本值选中,即显示在下拉框的文本值。
    """
    select_obj.select_by_index(1)   # 选中第二个下拉选项
    select_obj.select_by_value("3")  # 选中第三个下拉选项
    select_obj.select_by_visible_text("四")  # 选中第四个下拉选项
    
    """
    四种取消选中的方法
    deselect_by_index()           # 通过索引取消选中,注意:index索引是从“0”开始。
    deselect_by_value()           # 通过value值取消选中,value标签的属性值。
    deselect_by_visible_text()    # 通过文本值取消选中,即显示在下拉框的文本值。
    deselect_all()                # 取消全部选中。
    """
    select_obj.deselect_by_index(1)  # 取消第二个下拉框的选中
    select_obj.deselect_by_value("3")  # 取消选中第三个下拉选项
    select_obj.deselect_by_visible_text("四")  # 取消选中第四个下拉选项
    select_obj.deselect_all()  # 取消全部选中
    
    """
    查看四种下拉框属性
    all_selected_options        # 查看所有已选。
    first_selected_option       # 查看第一个已选。
    is_multiple                 # 查看该下拉框是否是多选状态。
    options                     # 查看选项元素列表。
    """
    

4.2 模拟鼠标交互

在模拟鼠标交互操作前,首先需要导入ActionChains 类。

from selenium.webdriver.common.action_chains import ActionChains
  • 右键点击

    # 定位到要右击的元素
    right_click_obj = browser.find_element_by_link_text('新闻')
    
    # 执行鼠标右键操作
    ActionChains(browser).context_click(right_click_obj).perform()
    
  • 双击

    # 定位到要双击的元素
    double_click_obj = browser.find_element_by_css_selector('#bottom_layer > div > p:nth-child(8) > span')
    
    # 执行双击操作
    ActionChains(browser).double_click(double_click_obj).perform()
    
  • 拖拽

    drag_and_drop(source,target)进行元素拖拽,常用于滑块验证等操作。

    # 开始位置
    source = browser.find_element_by_css_selector("#draggable")
    
    # 结束位置
    target = browser.find_element_by_css_selector("#droppable")
    
    # 执行元素的拖放操作
    actions = ActionChains(browser)
    actions.drag_and_drop(source, target)
    actions.perform()
    
  • 鼠标悬停

    # 定位到要悬停的元素
    hover_obj = browser.find_element_by_css_selector("#form > span.bg.s_ipt_wr.new-pmd.quickdelete-wrap > span.soutu-btn")
    
    # 执行鼠标悬停操作
    ActionChains(browser).move_to_element(hover_obj).perform()
    
  • 单击并保持

    # 定位到要点击并保存的元素
    button = browser.finde_element_by_class_name('geetest_slider_button')
    
    # 单击元素并保持
    ActionChains(browser).click_and_hold(button).perform()
    
  • 鼠标移动

    # 经常在点击并保持后移动,等价于拖拽效果,但不同于需要两个元素对象,此处只需要指定轨迹像素
    # 续单击并保持的样例代码
    x = 100
    y = 50
    # 将对应元素向x轴方向移动100像素,向y轴方向移动50像素
    ActionChains(browser).move_by_offset(xoffset=x, yoffset=y).perform()
    
  • 鼠标松开

    # 点击并保持后续操作,松开点击保持
    ActionChains(browser).release().perform()
    

4.3 模拟键盘交互

selenium中的Keys()类提供了大部分的键盘操作方法,通过send_keys()方法来模拟键盘上的按键。

常见的键盘操作:

send_keys(Keys.BACK_SPACE):删除键(BackSpace)

send_keys(Keys.SPACE):空格键(Space)

send_keys(Keys.TAB):制表键(TAB)

send_keys(Keys.ESCAPE):回退键(ESCAPE)

send_keys(Keys.ENTER):回车键(ENTER)

send_keys(Keys.CONTRL,'a'):全选(Ctrl+A)

send_keys(Keys.CONTRL,'c'):复制(Ctrl+C)

send_keys(Keys.CONTRL,'x'):剪切(Ctrl+X)

send_keys(Keys.CONTRL,'v'):粘贴(Ctrl+V)

send_keys(Keys.F1):键盘F1

send_keys(Keys.F12):键盘F12

4.4 运行JavaScript

通过使用浏览器对象execute_script()方法来实现JS的操作。

from selenium import webdriver

browser = webdriver.Chrome()
# 知乎发现页
browser.get('https://www.zhihu.com/explore')
# 操作JS让浏览器的下拉进度条拉动至最底,并弹出弹窗提醒
browser.execute_script('window.scrollTo(0, document.body.scrollHeight)')
browser.execute_script('alert("To Bottom")')

4.5 操作Cookie

通过使用浏览器对象get_cookies()方法获取指定key的值。

通过使用浏览器对象add_cookie()方法添加指定键值的Cookie。

通过使用浏览器对象delete_all_cookies()方法删除所有的Cookie。

from selenium import webdriver

browser = webdriver.Chrome()
# 知乎发现页
browser.get('https://www.zhihu.com/explore')
# 获取cookie
print(f'Cookies的值:{browser.get_cookies()}')
# 添加cookie
browser.add_cookie({'name':'宇后初晴_da', 'value':'帅哥'})
print(f'添加后Cookies的值:{browser.get_cookies()}')
# 删除cookie
browser.delete_all_cookies()
print(f'删除后Cookies的值:{browser.get_cookies()}')

五、延迟等待

如果遇到使用ajax加载的网页,页面元素可能不是同时加载出来的,这个时候尝试在get方法执行完成时获取网页源代码可能并非浏览器完全加载完成的页面。所以,这种情况下需要设置延时等待一定时间,确保全部网页元素都被加载出来。

  • 强制等待

    time.sleep(n)强制等待n秒,在执行get方法之后执行。

  • 隐式等待

    使用浏览器对象implicitly_wait()方法设置等待时间,传入秒作为参数,若到时间有元素节点没有加载出来,就会抛出异常。

    from selenium import webdriver
    
    browser = webdriver.Chrome()
    
    # 隐式等待,等待时间10秒
    browser.implicitly_wait(10)  
    
    browser.get('https://www.baidu.com')
    print(browser.current_url)
    print(browser.title)
    
    # 关闭浏览器
    browser.close()
    
  • 显式等待

    引入WebDriverWait,设置一个等待时间和一个条件,在规定时间内,每隔一段时间查看下条件是否成立,如果成立那么程序就继续执行,否则就抛出一个超时异常。

    from selenium import webdriver
    from selenium.webdriver.support.wait import WebDriverWait
    from selenium.webdriver.support import expected_conditions as EC
    from selenium.webdriver.common.by import By
    import time
    
    browser = webdriver.Chrome()
    browser.get('https://www.baidu.com')
    # 设置显示等待时间10s
    wait = WebDriverWait(browser, 10)
    # 设置判断条件:等待id='kw'的元素加载完成
    input_obj = wait.until(EC.presence_of_element_located((By.ID, 'kw')))
    # 在输入框输入关键词'Python'
    input_obj.send_keys('Python')
    
    # 关闭浏览器
    time.sleep(2)
    browser.close()
    

    WebDriverWait参数说明:WebDriverWait(driver,timeout,poll_frequency=0.5,ignored_exceptions=None)

    driver:浏览器驱动

    timeout:超时时间,等待的最长时间(同时要考虑隐性等待时间)

    poll_frequency:每次检测的间隔时间,默认是0.5秒

    ignored_exceptions:超时后的异常信息,默认情况下抛出NoSuchElementException异常

    判断条件参数说明:

    until(method,message='')

    method: 在等待期间,每隔一段时间调用这个传入的方法,直到返回值不是False

    message: 如果超时,抛出TimeoutException,将message传入异常

    until_not(method,message='')

    method: 在等待期间,每隔一段时间调用这个传入的方法,直到返回值不是False

    message: 如果超时,抛出TimeoutException,将message传入异常

    until_notuntil相反,until是当某元素出现或什么条件成立则继续执行,until_not是当某元素消失或什么条件不成立则继续执行,二者需要传入的参数相同。

    其他等待条件:

    from selenium.webdriver.support import expected_conditions as EC
    
    # 判断标题是否和预期的一致
    title_is
    # 判断标题中是否包含预期的字符串
    title_contains
    
    # 判断指定元素是否加载出来
    presence_of_element_located
    # 判断所有元素是否加载完成
    presence_of_all_elements_located
    
    # 判断某个元素是否可见. 可见代表元素非隐藏,并且元素的宽和高都不等于0,传入参数是元组类型的locator
    visibility_of_element_located
    # 判断元素是否可见,传入参数是定位后的元素WebElement
    visibility_of
    # 判断某个元素是否不可见,或是否不存在于DOM树
    invisibility_of_element_located
    
    # 判断元素的 text 是否包含预期字符串
    text_to_be_present_in_element
    # 判断元素的 value 是否包含预期字符串
    text_to_be_present_in_element_value
    
    #判断frame是否可切入,可传入locator元组或者直接传入定位方式:id、name、index或WebElement
    frame_to_be_available_and_switch_to_it
    
    #判断是否有alert出现
    alert_is_present
    
    #判断元素是否可点击
    element_to_be_clickable
    
    # 判断元素是否被选中,一般用在下拉列表,传入WebElement对象
    element_to_be_selected
    # 判断元素是否被选中
    element_located_to_be_selected
    # 判断元素的选中状态是否和预期一致,传入参数:定位后的元素,相等返回True,否则返回False
    element_selection_state_to_be
    # 判断元素的选中状态是否和预期一致,传入参数:元素的定位,相等返回True,否则返回False
    element_located_selection_state_to_be
    
    #判断一个元素是否仍在DOM中,传入WebElement对象,可以判断页面是否刷新了
    staleness_of
    

总结

以上就是今天要讲的内容,本文用万字详解了Python爬虫中常见的自动化WEB框架Selenium,简单介绍了使用Python进行自动化操作的准备工作和常用的交互指令,如果觉得对你有帮助的话不妨点个关注点个收藏,我们下期再见~

参考:2 万字带你了解 Selenium 全攻略 - 知乎 (zhihu.com)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值