selenium下
1. 行为链
如果在页面中的操作可能要有很多步,那么这时候可以使用鼠标行为链类ActionChains来完成。比如现在要将鼠标移动到某个元素上并进行点击操作。常见的鼠标操作有:
- click(element):普通单击
- click_and_hold(element):点击但不松开鼠标
- context_click(element):右键单击
- double_click(element):双击
更多方法参考:http://selenium-python.readthedocs.io/api.html
示例代码:
from selenium import webdriver
from selenium.webdriver import ActionChains
import time
driver = webdriver.Chrome()
driver.get('https://www.baidu.com/')
# 定位到输入框
inputTag = driver.find_element_by_id('kw')
# 定位百度一下按钮
buttonTag = driver.find_element_by_id('su')
# 实例化
actions = ActionChains(driver)
# 把鼠标移动到输入框里面
actions.move_to_element(inputTag)
# 输入内容
actions.send_keys_to_element(inputTag, 'Python')
time.sleep(1)
# 将鼠标移动到按钮上,并点击
actions.move_to_element(buttonTag)
actions.click()
time.sleep(1)
# 右键单击
actions.context_click()
# 提交行为链上的操作
actions.perform()
# 如果想使用buttonTag对象操作点击,必须在提交行为后
# time.sleep(1)
# buttonTag.click()
运行结果:
编写上述代码时的一些注意点:
- 通过鼠标行为链操作之前,需要先进行ActionChains类的实例化;
- 定义两个行为后,需要提交行为才能看到想要的效果,代码上就要调用perform()方法;
- 如果不通过行为链点击按钮,则需在行为链提交动作之后,才能执行点击按钮(button.click()) ;
- 如果通过行为链点击按钮,点击“百度一下”按钮前,需先将鼠标移动到相应的按钮标签上。
2. selenium中的cookie操作
2.1 获取cookie
复习cookie的作用:
- 模拟登录
- 反反爬
cookie中真正有用的信息是字典key为name和value的数据。以获取百度网页的cookie为例:
from selenium import webdriver
driver = webdriver.Chrome()
driver.get('https://www.baidu.com/')
# 获取cookie, get_cookies() 返回的是一个列表
cookies = driver.get_cookies()
for cookie in cookies:
print(cookie)
运行结果:
2.2 模拟登陆QQ空间
按照正常思路,登陆QQ空间有两种方法:
- 向url发起post请求,需携带账号密码进行登录;
- 拿到cookie值进行模拟登录。
先采用简单的方法进行登陆,退出到qq空间快速登录界面,找到登陆头像对应的标签,然后对其进行点击操作即可。
示例代码:
url = 'https://xui.ptlogin2.qq.com/cgi-bin/xlogin?proxy_url=XXXXXX'
driver = webdriver.Chrome()
driver.get(url)
button = driver.find_element_by_class_name('face')
button.click()
time.sleep(4)
运行结果:
关于上述代码中的url获取方法:在快速登陆界面,刷新网页,打开开发者工具,在network中寻找即可。
接下来,获取目标URL的cookie,保存到本地(也可以不保存,这里只是为了方便显示结果)。
示例代码:
# 获取qq空间网页的cookie
qqzone_cookielist = driver.get_cookies()
# 将上述列表转化为json类型的字符串
qqzone_cookiestr = json.dumps(qqzone_cookielist)
# 将cookie保存到本地文件
with open('qqzone.json', 'w') as fobj:
fobj.write(qqzone_cookiestr)
运行结果:
获取到网页的cookie后,就要验证它能不能用,通常cookie的格式如下图:
将获取到的cookie进行处理成能使用的格式,然后携带处理后的cookie向网页发起请求,看是否能获取网页数据。
示例代码:
# 处理cookie,转化为想要的格式
cookie_strs = [cookie['name']+'='+cookie['value'] for cookie in qqzone_cookielist]
cookie_str = '; '.join(cookie for cookie in cookie_strs)
print(cookie_str)
# 向qq空间发起请求
req_url = 'https://user.qzone.qq.com/1017210919'
req_headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36',
'cookie':cookie_str
}
qqzone_res = requests.get(req_url, headers=req_headers)
# 保存网页数据到本地
with open('qqzone.html','w', encoding='utf-8') as fobj:
fobj.write(qqzone_res.text)
运行结果:
3. 页面等待
3.1 基本概念
现在的网页越来越多采用了 Ajax 技术,这样程序便不能确定何时某个元素能完全加载出来。如果实际⻚⾯等待时间过长,导致某个元素还没出来,但是代码却要使用该元素,那么就会抛出NullPointer的异常。
为了解决上述问题,所以 Selenium 提供了两种等待方式:
- 隐式等待:调用
driver.implicitly_wait(10)
方法。那么在获取不可用的元素之前,会先等待10秒中的时间; - 显式等待,表示某个条件成立后才执行获取元素的操作。也可以在等待的时候指定最长等待时间,如果超过该时间就抛出⼀个异常。通常由
selenium.webdriver.support.excepted_conditions
期望的条件和selenium.webdriver.support.ui.WebDriverWait
来配合完成。
3.2 隐式等待
示例代码:
from selenium import webdriver
import time
driver = webdriver.Chrome()
driver.get('https://www.baidu.com/')
# python提供的sleep()方法,强制性的等待
# time.sleep(5)
# selenium的隐式等待,如果能找到相应的元素,就无须等待设置的时间
driver.implicitly_wait(10)
driver.find_element_by_id('kw').send_keys('python')
运行结果:
隐式等待的好处是如果能在设置的等待时间内找到相应的元素,就无须等完该时间,从而继续执行接下来的代码,相比time.sleep()
方法无论结果如何,都会强制等待设定的时间。但缺点也明显,即如果找不到想要的元素,它会等到设置时间结束后,再报错或者抛出异常。
3.3 显式等待
代码需求:访问12306,输入车票的起始地和目的地,并查询车票信息。
12306网页中一些关键标签的选取:
示例代码:
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()
driver.get('https://kyfw.12306.cn/otn/leftTicket/init?linktypeid=dc')
# 显式等待
# 输入出发地
# until()方法中传递的是条件
WebDriverWait(driver, 100).until(
EC.text_to_be_present_in_element_value((By.ID, 'fromStationText'), '上海')
)
# 输入目的地
WebDriverWait(driver, 100).until(
EC.text_to_be_present_in_element_value((By.ID, 'toStationText'), '南京')
)
# 定位查询按钮,并进行点击
button = driver.find_element_by_id('query_ticket')
button.click()
运行结果:
在上述代码中:
WebDriverWait()
方法传递的是web驱动和最长等待时间;until()
方法传递的是等待终止条件,这里写的条件是某个目标ID的元素值是否为期望值;- 目前代码尚无法自动填充起始地和目的地,代码只能等待手动选择完后继续向下执行;
- 在点击查询按钮之前,必须完成输入起始地和目的地的动作。
一些其他的等待条件:
- presence_of_element_located:某个元素已经加载完毕;
- presence_of_all_elements_located:网页中所有满足条件的元素都加载完毕;
- element_to_be_clickable:某个元素是可以点击。
更多条件参考:http://selenium-python.readthedocs.io/waits.html
4. 操作多页面
有时候浏览器窗口中有很多子页面,这种情况下通常会有切换页面的需求。selenium提供了switch_to_window()
方法来进⾏切换,具体切换到哪个页面,可以从driver.window_handles
中找到。
代码需求:打开两个页面,分别为百度和豆瓣,尝试切换操作页面并打印当前页面的url。
示例代码:
from selenium import webdriver
driver = webdriver.Chrome()
driver.get('https://www.baidu.com/')
driver.implicitly_wait(2)
# 打开新的页面
driver.execute_script('window.open("https://www.douban.com/")')
driver.implicitly_wait(2)
# 此处仍然在操作百度页面
driver.find_element_by_id('kw').send_keys('python')
# 打印当前驱动的url
print(driver.current_url)
# 切换窗口
driver.switch_to.window(driver.window_handles[1])
print(driver.current_url)
# 关闭当前驱动的url
# driver.close()
# 整个退出
# driver.quit()
运行结果: