通过Cookie登录

很多网站只有用户登录后才能正常访问,比如淘宝搜索就需要登录账号后才可以使用。

每次使用selenium时,WebDriver会打开一个新的浏览器窗口,所以需要使用添加cookie的方法保持我们的登录状态

cookie方法

get_cookies() # 获得所有cookie信息。
get_cookie(name) # 返回字典的key为“name”的cookie信息。
add_cookie(cookie_dict) # 添加cookie。“cookie_dict”指字典对象,必须有name 和value 值。
delete_cookie(name,optionsString) # 删除cookie信息。“name”是要删除的cookie的名称,“optionsString”是该cookie的选项,目前支持的选项包括“路径”,“域”。
delete_all_cookies() # 删除所有cookie信息

使用Cookie登录淘宝

我们尝试使用cookie登录到淘宝。

先看一下add_cookie方法的源码:

def add_cookie(self, cookie_dict) -> None:
        """
        Adds a cookie to your current session.

        :Args:
         - cookie_dict: A dictionary object, with required keys - "name" and "value";
            optional keys - "path", "domain", "secure", "expiry", "sameSite"

        Usage:
            driver.add_cookie({'name' : 'foo', 'value' : 'bar'})
            driver.add_cookie({'name' : 'foo', 'value' : 'bar', 'path' : '/'})
            driver.add_cookie({'name' : 'foo', 'value' : 'bar', 'path' : '/', 'secure':True})
            driver.add_cookie({'name': 'foo', 'value': 'bar', 'sameSite': 'Strict'})

        """
        if 'sameSite' in cookie_dict:
            assert cookie_dict['sameSite'] in ['Strict', 'Lax', 'None']
            self.execute(Command.ADD_COOKIE, {'cookie': cookie_dict})
        else:
            self.execute(Command.ADD_COOKIE, {'cookie': cookie_dict})

这个方法需要按按照cookiename,value,path,domain格式逐个添加cookie,但是淘宝的cookie非常多,不可能手动复制,所以此时我们需要用到一个插件:EditThisCookie

image-20211228105317651

通过自带的导出功能,可以获得一个list格式的字符串

[
{
    "domain": ".taobao.com",
    "expirationDate": 1672224651,
    "hostOnly": false,
    "httpOnly": false,
    "name": "_cc_",
    "path": "/",
    "sameSite": "no_restriction",
    "secure": true,
    "session": false,
    "storeId": "0",
    "value": "UtASsssmfA%3D%3D",
    "id": 1
},
{
    "domain": ".taobao.com",
    "expirationDate": 1703731896,
    "hostOnly": false,
    "httpOnly": false,
    "name": "_ga",
    "path": "/",
    "sameSite": "unspecified",
    "secure": false,
    "session": false,
    "storeId": "0",
    "value": "GA1.2.1783414334.1640659896",
    "id": 2
},
{
    "domain": ".taobao.com",
    "expirationDate": 1703731917,
    "hostOnly": false,
    "httpOnly": false,
    "name": "_ga_YFVFB9JLVB",
    "path": "/",
    "sameSite": "unspecified",
    "secure": false,
    "session": false,
    "storeId": "0",
    "value": "GS1.1.1640659890.1.1.1640659917.0",
    "id": 3
}
] // 大概长这个样子,实际上非常长

Demo

这次我们通过第一次发送账户密码登录,获取cookie并保存,第二次使用保存的cookie绕过登录

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import json
import time

driver = webdriver.Chrome()
filename = "D:\\pyrepo\\tbcookie.json"
f = open(filename,'r',encoding='utf-8')
cookies = json.loads(f.read())
f.close()
driver.get('https://www.taobao.com/')

for cookie in cookies:
       driver.add_cookie(cookie)

time.sleep(5)
driver.refresh()       

结果发生了以下错误:

image-20211228151445117

提示说是一个断言错误。sameSite属性的值不正确。

这是Chrome浏览器对Cookie的跨域限制问题,从51版本开始,cookie新增了一个sameSite属性,用来防止CSRF攻击和用户追踪。

比如 Facebook在第三方网站插入一张看不见的图片:

<img src="facebook.com" style="visibility:hidden;">

那么浏览器加载这个代码后,就会像Facebook发送带有Cookie的请求,从而Facebook就会知道你是谁,访问了什么。

sameSite有三个值:

  • Strict:严格,完全禁用第三方Cookie,跨站点时,不会发送Cookie,只有当前页面的URL与请求目标一致时候才会带上Cookie
  • Lax:宽松,大多数情况不会发送第三方Cookie,除了'链接'、'预加载'、'Get表单'。
  • None:关闭same属性,但是前提是必须同时设置Secure属性(Cookie智能通过HTTPS协议发送),即sameSite=None: Secure才有效

我们修改以下代码,将Cookie中的sameSite属性修改为Lax

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import json
import time

driver = webdriver.Chrome()
filename = "D:\\pyrepo\\tbcookie.json"
f = open(filename,'r',encoding='utf-8')
cookies = json.loads(f.read())
f.close()
driver.get('https://www.taobao.com/')

for cookie in cookies:
       if 'sameSite' in cookie:
              if cookie['sameSite'] != 'Strict':
                     cookie['sameSite'] ='Lax'
       driver.add_cookie(cookie)

time.sleep(5)
driver.refresh()

结果:

image-20211228153441448
登录成功。

其他操作

获取断言信息

不管是在做功能测试还是自动化测试,最后一步需要拿实际结果与预期进行比较。这个比较称之为断言

title = driver.title # 打印当前页面title
now_url = driver.current_url # 打印当前页面URL
user = driver.find_element_by_class_name('nums').text # 获取结果数目

等待页面加载完成

显示等待

显示等待是使WebDriver等待某个条件成立时继续执行,否则在达到最大时长时抛出异常(TimeoutException)。

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

driver = webdriver.Chrome() 
options = Options()
options.binary_location = "C:\Program Files\Google\Chrome\Application\chrome.exe"
driver.get('https://www.baidu.com')

element = WebDriverWait(driver, 5, 0.5).until(
                      EC.presence_of_element_located((By.ID, "kw"))
                      )
element.send_keys('selenium')
driver.quit()
# WebDriverWait类是由WebDriver提供的等待方法,在设置的时间内,每隔一段时间检测某个元素是否存在,如果超时则抛出异常
# 源格式:WebDriverWait(driver, timeout, poll_frequency=0.5, ignored_exceptions=None)
# timeout:超时事件,单位秒
# poll_frequency:检测间隔,默认0.5秒
# ignored_exceptions:超时后的异常信息,默认情况下抛NoSuchElementException异常。
# until(method,message='') 调用提供一个方法作为参数,直到返回值为True
# until_not(method,message='') 调用提供一个方法作为参数,直到返回值为False

隐式等待

如果某些元素不是立即可用的,就要用到隐式等待告诉WebDriver去等待一定时间后去查找元素,默认为0秒,一旦设置该值,则设置该WebDriver实例的生命周期

from selenium import webdriver
driver = webdriver.Firefox()    
driver.implicitly_wait(10)   
driver.get("http://somedomain/url_that_delays_loading")    
myDynamicElement = driver.find_element_by_id("myDynamicElement") 

在不同窗口和框架之间移动

driver.switch_to_window("windowName")
driver.switch_to_window("frameName")

通过Xpath定位iframe

xf = driver.find_element_bt_xpath('//*[@id="x-URS-iframe"]')
driver.swithc_to_frame(xf)

返回父frame

driver.switch_to_default_content()

警告框

alert = driver.switch_to_alert() # 获取警告框
alert.text # 返回文字信息
alert.accept() # 接受现有警告框
alert.dismiss() # 关闭现有警告框
alert.send_keys(KeysToSend) # 发送文本至警告框

下拉框选项

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.select import Select

driver = webdriver.Chrome() 
options = Options()
options.binary_location = "C:\Program Files\Google\Chrome\Application\chrome.exe"
driver.implicitly_wait(10) # 隐式等待
driver.get('http://sahitest.com/demo/selectTest.htm')
sel = driver.find_element_by_xpath('//*[@id="s1"]')
Select(sel).select_by_value('49') # 选择value值为49

上传文件

driver.find_element_by_name("file").send_keys('D:\\upload_file.txt')  # 定位上传按钮,添加本地文件

调用JavaScript代码

js="window.scrollTo(100,450);" # JS代码
driver.execute_script(js) # 通过JS设置浏览器窗口的滚动条位置

窗口截图

driver.get_screenshot_as_file("D:\\baidu_img.jpg") # 截取当前窗口,并指定截图图片的保存位置

关闭浏览器

close() # 关闭单个窗口
quit() # 关闭所有窗口