通过selenium来获取Cookie认证信息

kie来标记用户,通过特地的header首部信息(token)来鉴别用户等,当然这些信息都是用户在登录之后生成/交换的。有了认证机制之后,最基础的反爬手段就是定期来失效cookie或者token。 所以如何自动的获取/更新Cookie数值就成为基础的一环了。

自动获取Cookie信息

通过浏览器的devtool上可以通过手动方式来获取Cookie信息,但是为了能够在出现错误的时候即使更新,就需要自动获取Cookie等关键的认证信息。在这个过程中有两个关键的过程:

  • 通过selenium来完成登录
  • 设置使用无界面浏览器

无界面浏览器

在最开始接触到这一领域的时候,当时还是phantomJS的领域。 随着时间的推移,现在已经进入到的了headless-Chrome的时代,因为phantomJS已经不再维护。

headless chrome

本来以为headless chrome是完全不同的一款浏览器,不过经过一段时间的探索后发现只是添加一个参数。 chrome-driver的下载地址

1
2
3
4
5
6
7
8
from selenium import webdriver  
from selenium.webdriver.chrome.options import Options

chrome_options = Options()
chrome_options.add_argument("--headless") # 定义--deadless模式

driver = webdriver.Chrome( "./path/to/chromedriver", chrome_options = chrome_options)
driver.get("http://www.duo.com")

Selenium完成登录验证

Selenium 和 Puppeteer关系

在查询headless chrome的时候,有不少的文章提到了Puppeteer。本来以为这两者是相互竞争的关系,结果发现并非如此,Puppeteer是驱动headless chrome来进行测试的。所以Puppeteer的工作是和Selenium有较大的重合,可以替代。

不过Puppeteer是工作在Node环境下,而Selenium通常工作在python环境下。

Selenium工作模式

从需要解决的问题,Selenium和BeautifulSoup库是有着较大的差异。前者最本质要解决的是web页面的自动化测试,而并非筛选特定的元素内容,所以其最基本的工作模式的即使模拟真实的web页面上的操作。

1
2
3
4
5
6
7
8
driver = webdriver.Chrome('../chromedriver',chrome_options = chrome_options)  
driver.get('http://zhouchen.tech') # 不会返回任何内容
time.sleep(5) # Let the user actually see something!
search_box = driver.find_element_by_name('q')
search_box.send_keys('ChromeDriver')
search_box.submit()
time.sleep(5) # Let the user actually see something!
driver.quit()

如上就是模拟了查找元素q,然后点击发送表单的动作。

提交登录信息

通过selenium来实现登录的关键有:

  • 找到登录的元素
  • 在登录框上添加对应的内容
  • 完成提交

下面就在爱听的后台上来尝试完成登录工作。

1
2
3
4
5
6
7
8
9
10
11
12
13
from selenium import webdriver  
from selenium.webdriver.chrome.options import Options

driver = webdriver.Chrome('../chromedriver',chrome_options = chrome_options)
driver.get('https://editor.tingmall.com/MEditWS/main_2.x/main.html')

username = driver.find_element_by_id("username")
password = driver.find_element_by_id("password")
login = driver.find_element_by_id("login")

username.send_keys("username") ## 向表单上添加内容
password.send_keys("password")
login.click() # 完成元素的点击动作
获取cookie

在完成了登录操作的之后,获取cookie内容的操作就容易了。

1
2
print(driver.get_cookies())     # 获取全部的cookie 
print(driver.get_cookie("target")) # 获取对应的cookie
selenium的关键数据结构和api

在Selenium中关键的数据结构有:

  • WebDriver :代表了目标页面
  • WebElement:代表了目标页面中的元素

对于WebDriver而言有如下关键的方法和属性可以查看:

  • current_url :当前页面的url,非输入页面,默认支持302跳转;
  • get_cookies() :获取页面上的cookie信息 ,以列表形式输出;
  • close() :在一个driver关闭之后,需要重新定义后才能访问/加载页面,
  • get_screenshot_as_file() :截屏当前页面,并且保存到指定文件中
  • get_element(s)_by_xxxx :根据各种规则来筛选页面目标元素

对于WebElement对象,常用到的方法和属性有:

  • location:输出在网页坐标系上的位置,只有x和y坐标,没有z轴坐标
  • send_keys() : 在input类型组件上输入目标的内容
  • click() :在目标元素上执行点击动作

注意WebElement是对页面上各种元素的一个抽象,而完全没有考虑各种元素之间的差异,例如非input类型的组件执行send_keys是没有意义的等等。

检测页面跳转

在通过driver来获取到cookies的时候需要在登录页面完成数据认证,跳转到登录后的页面才能获取到cookie内容。一种方式是添加sleep语句,强制等待N秒之后来获取数据;另一个种更优雅的方式是利用条件触发,在特定的条件的触发下执行目标代码。

为了完成条件触发,需要掌握以下两个内容:

  • WebDriverWait :一个条件阻塞的浏览器
  • expected_conditions :各种条件
1
2
3
4
5
6
7
8
9
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By

driver = webdriver.Chrome('../chromedriver',chrome_options = chrome_options)
waiter = WebDriverWait(driver, timeout)
username = waiter.until(EC.presence_of_element_located((By.ID, 'txtUserName')))
password = waiter.until(EC.presence_of_element_located((By.ID, 'txtPassword')))
submit = waiter.until(EC.element_to_be_clickable((By.ID, 'btnLogin')))
  • presence_of_all_elements_located :至少有1个元素存在于dom树中;
  • title_contains :当前页面的title是否包含预期字符串

    1
    2
    ec = EC.title_contains("百度")
    ec(target_driver) # 会返回True 或者False 信息

小结

如上就完成了通过Selenium自动登录,同时在登录完成后获取cookie信息。如果爬取的所需的验证信息存放在cookie中,那么则就完美的解决用户认证的问题。但是在有些后端设计中,用户的认证可能是通过response header中的自定义字段来传递到前端的JS,而这就超出了Selenium的处理范围,因为没有提供相关的api。

在网络上的也有通过一些奇怪的方法来hack这个缺陷,例如通过chromedriver的har log,或者通过嵌入js代码来实现。不过就会太过于的麻烦了,这个时候puppeteer可能就是更好的解决方案了。不过这个问题本质上是为了解决爬虫时碰到的问题,但是P是Node/JS下的解决方案,这个时候爬虫也要用Nodejs重写?[摊手]

参考文档

Getting started with Headless Chrome on Windows

phantomJs之殇,chrome-headless之生 Headless Chrome正在迅速取代这个由JavaScript驱动的WebKit方法。 Headless Chrome浏览器的测试运行速度要快得多,而且行为上更像一个真正的浏览器

puppeteer a high-level API to control Chrome or Chromium over the DevTools Protocol

Chrome DevTools Protocol to instrument, inspect, debug and profile Chromium, Chrome and other Blink-based browsers

Puppeteer VS Selenium 这两者是竞争的关系

how-to-login-in-puppeteer 展示了最基本的如何在Puppeteer上进行基础的页面操作

puppeteer-examples github上的一个项目,系统的展示了如何利用Puppeteer来完成页面操作

DRIVING HEADLESS CHROME WITH PYTHON 这个示例代码揭示了,headless chrome的使用模式和之前相同,只不过是在之前的webdriver上的添加一个–headless的参数标志。

webdriver for chrome 各个版本的chrome驱动下载地址

WebDriver API selenium-python下webdriver的api。比官网文档更齐全

selenium跳过webdriver检测并模拟登录淘宝 使用seleniums时,window.navigator.webdriver属性为Ture,从而可能被屏蔽;从这个文章也可以看出,页面的测试也

fill-username-and-password-using-selenium-in-python 填写表单并且提交的方法

WebDriver lacks HTTP response header and status code methods

how-do-i-get-the-response-headers-in-selenium Their ‘schtick’ is that selenium helps you automate what a user does,按照这个理由,不提供普通用户不关心的response header 信息。

如何通过Python+Selenium+PhantomJS/Chrome获取HTTP状态和Response Headers

possible-to-get-http-response-headers-with-nodejs-and-puppeteer 通过Puppeteer可以更好的获取目标内容

How to install PhantomJS on Ubuntu 中间介绍了将可执行文件添加到 /usr/local/share等目录来实现添加到执行环境上

基于 Selenium WebDriver 的 Web 应用自动化测试 Selenium RC 在浏览器中运行 JavaScript 应用,而 WebDriver 通过原生浏览器支持或者浏览器扩展直接控制浏览器 ,介绍了Seleninum2和之前版本的差异

Python selenium —— 一定要会用selenium的等待,三种等待方式解读

python Selenium expected_conditions

本文原创,请随意转载,但请添加文章链接,并将链接放置在文章开头,谢谢。

随手请吃块糖呗