selenium介绍(下)
不管页面是动态加载还是静态加载出来的,只要是elements中能找到的,都能用selenium来获取数据,selenium获取数据的方式是以页面最终渲染后的前端为基础的,不需要去分析数据接口了,看到什么内容就直接去获取,“所见即所爬”,但也不是100%的爬取,使用时需要先加载驱动,速度比较慢。
driver.page_source 前端结构的源码 ,跟渲染之后有关系,与requests获取源码是有区别的
vs requests 响应内容中的源码
find() 用来查找某个字符串在HTML结构源码中是否存在,存在就返回数字,不存在就返回-1
node 元素对象,通过selenium可以获取元素的属性值,get_attribute 获取属性值,text用来获取节点文本,包括子节点和后代节点
from selenium import webdriverimport timedriver = webdriver.Edge()driver.get('/')time.sleep(1)# 获取html结构的源码# html = driver.page_source# print(html) # 获得html的源码# find(),用来查找某个字符串是否在html结构的源码(渲染后的页面源码)中print(driver.page_source.find('kw')) # 5682print(driver.page_source.find('su')) # 964print(driver.page_source.find('11122233aa')) # -1
比如获取豆瓣top250第一个电影的图片
# 获取豆瓣top250,第一个电影的图片from selenium import webdriverimport timedriver = webdriver.Edge()driver.get('/top250')time.sleep(1)img_tag = driver.find_element_by_xpath('//*[@id="content"]/div/div[1]/ol/li[1]/div/div[1]/a/img')# get_attribute 获取属性值print(img_tag.get_attribute('src'))# 图片的地址。/view/photo/s_ratio_poster/public/p480747492.webp# text用来获取节点文本,包括子节点和后代节点img_tag = driver.find_element_by_xpath('//*[@id="content"]/div/div[1]/ol/li[1]/div/div[2]/div[1]')print(img_tag.text) # 获取节点内所有的文本# 肖申克的救赎 / The Shawshank Redemption / 月黑高飞(港) / 刺激1995(台) [可播放]
选择select
select元素不能直接点击。因为点击后还需要选中元素。这时候selenium就专门为select标签提供了一个类from selenium.webdriver.support.ui import Select。将获取到的元素当成参数传到这个类中,创建这个对象。以后就可以使用这个对象进行选择了。
案例分析:17素材网
进入网站:/boards/53562.html,选择左侧的下拉框图片,进去之后,选择右边的查看演示。
我们要进行的操作,是让程序模仿人的行为,点击"Try Me!"按钮,进行里面选项的选择。右键点击第一个红框,检查,可以发现"Try Me!"在select标签有name和class两个属性,我们可以select进行操作。
在定位到select标签后,对选项进行选择有两种方式,一是通过value值,每个值代表一个选项;第二种是通过索引选择。
from selenium import webdriverimport timedrive = webdriver.Edge()drive.get('/pins/demo-show?id=5926')# 定位到select标签ipt_tag = drive.find_element_by_class_name('nojs')# 根据值来选择ipt_tag.select_by_value('AU')
这时我们会发现程序没有按照设置的内容进行选择选项,报出了错误:Message: no such element: Unable to locate element: {“method”:“css selector”,“selector”:".nojs"}
我们再检查网页代码,往上翻会看到代码中有iframe标签,里面的src里的url打开后跟刚才显示的网页一模一样。
iframe 是文档中的标签,文档中的文档,所以要对文档进行操作的时候,需要切换到iframe标签内,由于select没有不能直接点击,所以需要将获取到的元素当成参数传到select类中,完成点击的选择。
from selenium import webdriverfrom selenium.webdriver.support.ui import Selectimport timedrive = webdriver.Edge()drive.get('/pins/demo-show?id=5926')# 找到iframeifra_tag = drive.find_element_by_id('iframe')# 切换到iframe# drive.switch_to_frame(ifra_tag) # 被弃用的的方法,只是过时了,还可以用drive.switch_to.frame(ifra_tag) # 新方法# 定位到select标签ipt_tag = drive.find_element_by_class_name('nojs')# select不能点击,将获取到的元素当成参数传到这个类中,需要导入select库sele_tag = Select(ipt_tag)# 根据值来选择sele_tag.select_by_value('AU')# 根据索引来选择sele_tag.select_by_index(1) # 跟按值选择结果一样
实现了程序自动选择Australia。
总结:
如果我们碰上了iframe标签 而且这个标签里面嵌套的内容刚好有我们要操作的元素,这种情况下面 就得先切换到iframe标签
找到iframe
iframe_tag = driver.find_element_by_id(‘iframe’)
切换到iframe
driver.switch_to_frame(iframe_tag)
如何操作select标签
第一步 导入 from selenium.webdriver.support.ui import Select
第二步 定位到select标签 把定位到的标签以参数的形式传递到Select中
select_tag = driver.find_element_by_class_name(‘nojs’)
new_select_tag = Select(select_tag)
第三步 选择
两种选择方式
一种是根据值来选择
new_select_tag.select_by_value(‘AU’)
第二种是通过索引选择
第二个"Try Me!"选项
select值能服务于select对象,所以进行选项框选择的时候可以模仿人的操作,先点击,再选择,然后再点击。
选项的属性值在li中,而li并没有id和class属性,可以用xpath去定位,在CA处点击右键,复制xpath路径
from selenium import webdriverfrom selenium.webdriver.support.ui import Selectimport timedrive = webdriver.Edge()drive.get('/pins/demo-show?id=5926')# 找到iframeifra_tag = drive.find_element_by_id('iframe')# 切换到iframedrive.switch_to.frame(ifra_tag)# 定位到select标签div_tag = drive.find_element_by_id('dk_container_country-nofake')# select不能点击,将获取到的元素当成参数传到这个类中,需要导入select库# sele_tag = Select(div_tag) # 会报错,select值能服务与select对象# 模仿人的操作,先点击有选择div_tag.click()time.sleep(1)div_tag.find_element_by_xpath('//*[@id="dk_container_country-nofake"]/div/ul/li[3]/a').click()
模拟登录豆瓣
需求分析
打开豆瓣后,默认的光标在“短信登录/注册”,现在需要把光标位于“密码登录”处,自动输入账号密码,再点击“登录豆瓣”,出现图形验证码,目前只做到用手工进行图形验证。
页面分析
光标放到“密码登录”处,点击鼠标右键,检查,可以看到“密码登录”位于li标签内,我们要定位到这个li标签,完成点击的操作。
下面要输入账号密码,遇到需要填入的表格内容,我们需要先看一下网页代码中是否含有iframe标签,网上滚动代码,可以看到存在iframe标签,复制标签内的src在新网页中打开,可以看到跟要操作的登录框一样的网页,这时我们就需要先切换到iframe标签进行输入框的定位和操作。
通过鼠标右键分别检查账号密码输入框,可以看到题目分别位于两个input标签内,我们需要对两个标签分别进行定位和输入内容。
在“登录豆瓣”按钮处点击鼠标右键,检查,可以看到“登录豆瓣”位于a标签内,我们需要对a标签进行定位和点击
登录后会加载图形验证码,这里用手工滑动验证。
代码实现
from selenium import webdriver # 导入库import time # 浏览器加载需要时间,需要等待一下driver = webdriver.Edge() # 加载驱动driver.get('/') # 以字符串的形式传入网页,使用驱动打开time.sleep(1)# 切换iframe# 定位到iframe,发现标签里没有可定位的属性,可以用xpath定位iframe_tag = driver.find_element_by_xpath('//*[@id="anony-reg-new"]/div/div[1]/iframe')# 切换到定位的标签内driver.switch_to.frame(iframe_tag)# 定位切换登录模式的位置"""class标签‘account-tab-account on’里面有空格。1.可以采取保留长的那一部分2.采用xpath的方式定位"""# li_tag = driver.find_element_by_class_name('account-tab-account') # 第一种li_tag = driver.find_element_by_xpath('/html/body/div[1]/div[1]/ul[1]/li[2]') # 第二种# 在li标签处,点右键,复制xpathli_tag.click()time.sleep(1)# 定位用户名,输入用户名driver.find_element_by_id('username').send_keys('xxxxx')# 定位密码框psw_ipt = driver.find_element_by_id('password')# 输入密码psw_ipt.send_keys('yyyyy')time.sleep(1)# 定位登录按钮div_tag = driver.find_element_by_class_name('btn-account')div_tag.click()
通过selenium获取cookie
之前的操作是在浏览器中找到cookie,复制下来加到请求头里。有些网站的数据是需要登录之后才能爬取的
cookie在爬虫中的作用:
模拟登录反反爬:useragent 反反爬第一步,很多网站都会检查,还会有网站检查 cookie referer,但是cookie有时效性,几个小时到几天不等,可以通过selenium去动态的更新cookie值。
通过Network里查找到的cookie
通过浏览器驱动访问到的cookie,可以看到是一个列表里面放了很多的字典,在这里只需要取出每个字典的中key为name和value对应的value值,看网页代码中,n和v是通过“=”连接的字符串,个“=”连接的字符串中间用’; '隔开的,可以进行字符串的拼接。
代码实现:
from selenium import webdriverimport time# 加载驱动driver = webdriver.Edge()# 用驱动打开网站driver.get('/')# 获取cookiecookies = driver.get_cookies()# print(cookies)# 打印出来是一个列表里面放了很多的字典,# 在这里只需要取出每个字典的中key为name和value对应的value值cookie = []for cook in cookies:n = cook['name']v = cook['value']# 看网页代码中,n和v是通过“=”连接的字符串cookie.append(n + '=' + v)# print(cookie)# 每个“=”连接的字符串中间用'; '隔开的,可以进行字符串的拼接end_cookies = '; '.join(cookie)print(end_cookies)
模拟登录QQ空间
之前做的模拟登录是把cookie复制下来,放到header里,把获取到的网页源码保存下来就可以去访问。
这次是通过selenium获取到的cookie放到 对QQ空间发送请求的请求头里,如果能进入到QQ空间则说明获取到的cookie是可用的
进入网页后会出现如一个二维码框和一个QQ头像框,我们需要把鼠标移到头像框处,点击进入QQ空间,获取到cookie值,再把获取的cookie经过拼接整合以后放到requests请求里去访问,如果能进入QQ空间代表获取的cookie值是有效的
from selenium import webdriverimport timeimport requests"""1.通过selenium获取cookie值,2.进一步解析拼接cookie值,3.把最终拼接好的cookie值放到代码中测试"""# 1.通过selenium获取cookie值# 加载驱动driver = webdriver.Edge()# 打开网页driver.get('https://xui./cgi-bin/xlogin?proxy_url=https%3A///qzone/v6/portal/proxy.html&daid=5&&hide_title_bar=1&low_login=0&qlogin_auto_login=1&no_verifyimg=1&link_target=blank&appid=549000912&style=22&target=self&s_url=https%3A%2F%2Fqzs.%2Fqzone%2Fv5%2Floginsucc.html%3Fpara%3Dizone&pt_qr_app=手机QQ空间&pt_qr_link=http%3A///download.html&self_regurl=https%3A///qzone/v6/reg/index.html&pt_qr_help_link=http%3A///download.html&pt_no_auth=0')time.sleep(1)# 找到头像span_tag = driver.find_element_by_id('img_out_“自己的QQ号”')# 需要QQ在线才能出现QQ的头像框time.sleep(1)# 点击头像span_tag.click()# 等待页面加载一会time.sleep(2)cookies = driver.get_cookies()# print(cookies)# 打印出来是一个列表里面放了很多的字典,# 在这里只需要取出每个字典的中key为name和value对应的value值# 2.拼接cookie# 第一种方法:cookie = []for cook in cookies:n = cook['name']v = cook['value']# 看网页代码中,n和v是通过“=”连接的字符串cookie.append(n + '=' + v)# print(cookie)# 每个“=”连接的字符串中间用'; '隔开的,可以进行字符串的拼接end_cookies = '; '.join(cookie)# 第二种方法:列表推导式cookie = [item['name'] + '=' + item['value'] for item in cookies]end_cookies = '; '.join(cookie)# 第三种:end_cookies = '; '.join([item['name'] + '=' + item['value'] for item in cookies])# 3.测试代码,如果把selenium获取到的cookie放进请求头中,能成功模拟登录成功# 就证明我们获取的cookie是没问题的url = 'https://user./“自己的QQ号”/infocenter'headers = {'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36','cookie': end_cookies}res = requests.get(url, headers=headers)html = res.content.decode('utf-8')with open('qzone.html', 'w', encoding='utf-8') as f:f.write(html)
如果出现问题,很大的可能是没有用time对程序进行暂停,因为程序执行的很快,网页反应的有点慢,如果没有暂停,会出现网页还没有加载,下一步程序就执行了,导致出现问题。打开生成的qzone.html文件,可以进到QQ空间里,看到QQ名字就说明selenium获取到的cookie是有效的,这个时候加载的QQ空间会跟正常打开的稍微有区别,因为我们正常打开的网页是最终渲染出来的。
行为链
鼠标一系列的行为和动作,单击,双击,左键点击,右键点击等等。
有时候在页面中的操作可能要有很多步,那么这时候可以使用鼠标行为链类ActionChains来完成。比如现在要将鼠标移动到某个元素上并执行点击事件
还有更多的鼠标相关的操作
click:点击
click_and_hold(element):点击但不松开鼠标,按着不丢。
context_click(element):右键点击。
double_click(element):双击。
drag_and_drop(source, target):拖拽
drag_and_drop_by_offset(source, xoffset, yoffset):拖拽,有一定的位移量
更多方法请参考:http://selenium-python.readthedocs.io/api.html
使用行为链需要提前导入库,“from selenium.webdriver import ActionChains”
from selenium import webdriverfrom selenium.webdriver import ActionChainsimport time # 导入库# 加载驱动driver = webdriver.Edge()# 打开网页driver.get('/')time.sleep(1)# 第一种之前使用的方法# 获取标签,输入内容# driver.find_element_by_id('kw').send_keys('python')# 获取点击框,点击百度一下搜索# driver.find_element_by_id('su').click()# 第二种方法使用行为链,先导入行为链的库ipt_tag = driver.find_element_by_id('kw')btn_tag = driver.find_element_by_id('su')# 通过导入的类实例化action对象action = ActionChains(driver)# 往输入框中输入内容action.send_keys_to_element(ipt_tag, 'python')time.sleep(1)# 第1中方式在行为链外部点击按钮# 提交行为链# action.perform()# 通过标签的点击行为,不能放在行为链内部,要放行为链外# btn_tag.click()# 第2中方式在行为链内部点击按钮# 把鼠标移动到按钮的位置action.move_to_element(btn_tag)#进行点击操作action.click()# 切记,要提交行为链action.perform()
注意:
1 一定不要忘记提交鼠标行为链
2 要注意鼠标行为链中的点击操作:直接点击某个元素的逻辑是需要放在行为链外面的;如果是放行为链里面,要先定位点击按钮,把鼠标移到按钮的位置,再进行点击操作