Cookie操作
获取所有的cookie
根据cookie的name获取cookie
删除某个cookie
页面等待
selenium并不是为爬虫而生,但是它的所见即所爬可以方便的用来进行爬取数据,加载速度很慢,需要打开页面,加载相应的元素。如果打开网页,内部的元素慢慢进行加载,如果打开网页立即去查找元素,就会报出异常;很多网页是用Ajax加载出来的,如12306,只有选择日期,往返地,点击查询后才能加载出来数据,这就是需要页面等待的两个原因。
之前进行页面等待是用的python内置的,导入time模块,用time.sleep
()进行强制等待,不好的地方,等待时间长了浪费,时间不够页面加载不完全就会报错,不利于系统的优化。
现在的网页越来越多采用了 Ajax 技术,这样程序便不能确定何时某个元素完全加载出来了。如果实际页面等待时间过长导致某个dom元素还没出来,但是你的代码直接使用了这个WebElement,那么就会抛出NullPointer的异常。为了解决这个问题。所以 Selenium 提供了两种等待方式:一种是隐式等待、一种是显式等待。
隐式等待调用driver.implicitly_wait。那么在获取不可用的元素之前,会先等待10秒钟的时间,但是不会完全等待10秒,等页面加载完,定位到标签位置后立即就会执行,如果找不到,最多等待10秒后报出异常。而time模块的等待是必须等待设定的时间。
from selenium import webdriver import time driver = webdriver.Edge() driver.get('https://www.baidu.com/') # 之前time模块页面等待的方法 time.sleep(1) driver.find_element_by_id('kw').send_keys('爬虫') # 隐式等待 # 设定最长等待时间10秒,运行的时候并不会等待10秒,定位到输入框后就会输入数据 driver.implicitly_wait(10) driver.find_element_by_id('kw').send_keys('爬虫') # 如果定位的标签不存在,则会等待10秒后报错 driver.find_element_by_id('12sdf21s2d1sd').send_keys('爬虫')
比如人的行为对12306进行操作的时候,需要先输入出发点、目的地、出发时间,再点击查询,用selenium模拟人的行为的时候也会按照这个步骤进行。进入网站之后会有个弹窗,可以定位到弹窗的“确定”或者“叉号”进行操作,正常打开网页会有缓存,出发地和目的地会有之前输入的信息可以直接点击查询,而用selenium打开的话,出发地和目的地为空的,点击查询会提示让输入。
利用点击叉号关闭弹窗
利用点击确定关闭弹窗
定位并点击查询按钮。
显示等待是表明某个条件成立后才执行获取元素的操作。也可以在等待的时候指定一个最大的时间,如果超过这个时间那么就抛出一个异常。显示等待应该使用selenium.webdriver.support.excepted_conditions期望的条件和selenium.webdriver.support.ui.WebDriverWait来配合完成
显示等待设置条件和最大范围,一旦满足就不再等待直接往下走,不满足就一直等待,直到时间结束报出错误。
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.Edge() driver.get('https://kyfw.12306.cn/otn/leftTicket/init?linktypeid=dc') # 隐式等待,等待页面加载 driver.implicitly_wait(2) # 处理弹窗 # 找到叉号,点击叉号 # driver.find_element_by_id('gb_closeDefaultWarningWindowDialog_id').click() # 找到确定,点击确定 driver.find_element_by_id('qd_closeDefaultWarningWindowDialog_id').click() # 显示等待,需要导入库,需要有条件,条件满足才运行 # 等待出发地的输入,fromStationText出发地的id值 # 等待用户在输入地输入长沙,如果不输入或者输入错误会一直等待 WebDriverWait(driver, 1000).until( EC.text_to_be_present_in_element_value((By.ID, 'fromStationText'), '长沙')) # 等待目的地的输入,toStationText目的地的id值 # 等待用户输入目的地北京,等待时间为1000秒,超过时间就会报错 WebDriverWait(driver, 1000).until( EC.text_to_be_present_in_element_value((By.ID, 'toStationText'), '北京')) # 定位按钮 que_btn = driver.find_element_by_id('query_ticket') # 点击查询 # que_btn.click() # 如果碰到案例点击没有反应的话,也可以用js来执行点击 # 把已经定位到的que_btn传递进去,对arguments做点击操作,0代表的是第一个参数que_btn driver.execute_script('arguments[0].click()', que_btn) # 显示等待有条件限制,满足条件条件才能执行, # 用户输入出发地长沙,目的地北京以后,自动点击查询按钮, # 任何输入错误或者其他值会停留输入界面直到时间结束,进行报错
总结:通过案例学到的内容,隐式等待和显式等待的实现方法,两者的应用场景;如何用js实现点击操作。
一些其他的等待条件:
presence_of_element_located:某个元素已经加载完毕了。
presence_of_all_elements_located:网页中所有满足条件的元素都加载完毕了。
element_to_be_clickable:某个元素是可以点击了。
更多条件请参考:http://selenium-python.readthedocs.io/waits.html
有时候窗口中有很多子tab页面。这时候肯定是需要进行切换的。selenium提供了一个叫做switch_to_window来进行切换,具体切换到哪个页面,可以从driver.window_handles中找到。
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 import time driver = webdriver.Edge() driver.get('https://www.baidu.com/') time.sleep(2) # driver.get('https://www.douban.com/') # 会先打开百度,然后在同一界面替换打开豆瓣 # 用js打开多个窗口,execute_script执行js代码 # 注意单双引号的使用,外层是单引号,内层就要为双引号 driver.execute_script('window.open("https://www.douban.com/")') # 对两个网页进行操作,默认情况下操作第一个网页 # driver.find_element_by_id('kw').send_keys('python') # driver.close() # 进行操作的是第一个网页 # 如果要对第二个网页进行操作,可以进行切换 # 对于人来说视角已经在第二次打开的网页了,但是对于selenium来说还是停留在第一个网页 print('切换前:', driver.current_url) # 切换前:https://www.baidu.com/ # 把网页选项卡看成列表,-1代表最后一个,在这里也可以用1进行索引 # switch_to_window ,过时的方法也可以用 driver.switch_to.window(driver.window_handles[-1]) print('切换后:', driver.current_url) # 切换后:https://www.douban.com/ # 此时再用close关闭的就是第二个网页 time.sleep(2) driver.close() time.sleep(2) # 建议close最好不用,关闭网页再重新打开的时候还要先切换 # 把selenium的视角切换到第一个标签再执行打开操作,不然会出错 driver.switch_to.window(driver.window_handles[0]) driver.execute_script('window.open("https://www.douban.com/")')