02-02 爬虫请求库之selenium

 

 
selenium 最初是一个自动化测试工具,而爬虫中使用它主要是为了解决requests无法直接执行JavaScript代码的问题,3.0版本2016发布
selenium 比requests功能强,但是需要驱动浏览器特别耗资源性能低,可以用它执行js操作,如登录拿到cookie,其他用requests进行提高性能
selenium 本质是通过驱动浏览器,完全模拟浏览器的操作,比如跳转、输入、点击、下拉等,来拿到网页渲染之后的结果,可支持多种浏览器
from selenium import webdriver
browser=webdriver.Chrome()
browser=webdriver.Firefox()
browser=webdriver.PhantomJS()
browser=webdriver.Safari()
browser=webdriver.Edge() 
 

官网:http://selenium-python.readthedocs.io

>>selenium版本介绍和底层原理分析点这里<<

一 有界无界浏览器介绍

1、有界面浏览器

#安装:selenium+chromedriver
 
第一步: pip3 install selenium 第二步:下载chromdriver.exe
安放位置:
       1.放到python安装路径的scripts目录中一劳永逸,
       2.或者直接放在pycharm根目录先爽为快
       3.也可以随便放入哪个文件夹,生成浏览器的时候指定具体路径就好了
  版本要求:版本要和自己谷歌浏览器版本对应上,真找不到对应版本就下相近版本测试是否可以使用
   国内镜像网站地址:http://npm.taobao.org/mirrors/chromedriver/
   最新的版本去官网找(不F墙可能进不去):https://sites.google.com/a/chromium.org/chromedriver/downloads #验证安装>>> from selenium import webdriver >>> driver=webdriver.Chrome() #弹出浏览器 >>> driver.get('https://www.baidu.com') >>> driver.page_source

2、无界面浏览器

使用有界浏览器每一次都弹框,我们有时候只需要代码执行拿结果就好了不想要弹框,就需要用无界浏览器

之前用 PhantomJS ,年久失修不再更新,很少使用

自Google 发布 chrome 59 / 60 正式版 开始便支持无界面模式 ,PhantomJS 不再是唯一选择 

 

selenium+谷歌浏览器headless模式:

from selenium import webdriver

# 如果需要额外的一些设置就需要调用options,传入各种设置,然后将options传给Chrome
from selenium.webdriver.chrome.options import Options Options.add_argument('blink-settings=imagesEnabled=false') #不加载图片, 提升速度 Options.add_argument('--headless') #浏览器不提供可视化页面. linux下如果系统不支持可视化不加这条会启动失败 driver=webdriver.Chrome(chrome_options=Options) driver.get('https://www.baidu.com') print('hao123' in driver.page_source) driver.close() #切记关闭浏览器,回收资源

3 有界无界浏览器基本使用

爬取百度美女照

from selenium import webdriver
from selenium.webdriver.common.keys import Keys #键盘按键操作
import time

# 无界浏览器使用
# from selenium.webdriver.chrome.options import Options
# chrome_options = Options()
# chrome_options.add_argument('window-size=1920x3000') #指定浏览器分辨率
# chrome_options.add_argument('--disable-gpu') #谷歌文档提到需要加上这个属性来规避bug
# chrome_options.add_argument('--hide-scrollbars') #隐藏滚动条, 应对一些特殊页面
# chrome_options.add_argument('blink-settings=imagesEnabled=false') #不加载图片, 提升速度
# chrome_options.add_argument('--headless') #浏览器不提供可视化页面. linux下如果系统不支持可视化不加这条会启动失败
# chrome_options.binary_location = r"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" #手动指定使
# bro=webdriver.PhantomJS()

# bro=webdriver.Chrome(chrome_options=chrome_options)
# bro.get('https://www.baidu.com')

# 有界浏览器使用
bro=webdriver.Chrome()
bro.get('https://www.baidu.com')
# print(bro.page_source)  # 可以得到代码,然后就是筛选

time.sleep(1)
#取到输入框
inp=bro.find_element_by_id('kw')
#往框里写字
inp.send_keys("美女")
inp.send_keys(Keys.ENTER) #输入回车
#另一种方式,取出按钮,点击su
time.sleep(3)
bro.close()
爬取百度mm

二、谷歌浏览器的Options 参数

在使用selenium浏览器渲染技术,爬取网站信息时,默认情况下就是一个普通的纯净的chrome浏览器,而我们平时在使用浏览器时,经常就添加一些插件,扩展,代理之类的应用。相对应的,当我们用chrome浏览器爬取网站时,可能需要对这个chrome做一些特殊的配置,以满足爬虫的行为。

常用的行为有:

  • 窗口最大化
  • 禁止图片和视频的加载:提升网页加载速度。
  • 添加代理:用于FQ访问某些页面,或者应对IP访问频率限制的反爬技术
  • 添加扩展:像正常使用浏览器一样的功能,使用插件等
  • 设置编码:应对中文站,防止乱码
  • 阻止JavaScript执行。
  • ………

1. chromeOptions

chromeOptions 是一个配置 chrome 启动是属性的类。通过这个类,我们可以为chrome配置如下参数(这个部分可以通过selenium源码看到):

  • 设置 chrome位置 (binary_location)
  • 添加启动参数 (add_argument)
  • 添加扩展应用 (add_extension, add_encoded_extension)
  • 添加实验性质的设置参数 (add_experimental_option)
  • 设置调试器地址 (debugger_address)
# 前提:驱动器放在了 'E:\driver\chrome\chromedriver.exe',生成浏览器时需要指定
import  os
from selenium import webdriver

# os.name——判断现在正在实用的平台,Windows 返回 ‘nt'; Linux 返回’posix'
driver_path = 'E:\driver\chrome\chromedriver.exe' if os.name == 'nt' else 'E:/driver/chrome/chromedriver'


# 引入Options
# Options和ChromeOptions是一样的,你点进源码是一个地方,随便用一个就好了 # 方式一 options = webdriver.ChromeOptions() # 方式二 # options = webdriver.chrome.options.Options()
# 参数的各种设置
#浏览器不提供可视化页面,无界浏览器要用 options.add_argument('--headless') # 窗口最大化 常用 options.add_argument('--start-maximized') # 下载文件设置 常用 prefs = {'download.default_directory': '你的保存路径', # 设置下载路径,路径不存在会自动创建 "safebrowsing.enabled": "false", # 是否提示安全警告 'download.prompt_for_download':False, # 是否弹窗询问,比如下载后浏览器询问‘xxoo会损害您的计算机,是否保留’ } options.add_experimental_option('prefs', prefs) # 禁止图片加载 # 方式一 prefs = {"profile.managed_default_content_settings.images": 2} options.add_experimental_option("prefs", prefs) # 方式二 options.add_argument('blink-settings=imagesEnabled=false') # 使用中文编码 options.add_argument('lang=zh_CN.UTF-8') # 设置窗口尺寸,涉及到截图比如验证码的时候用到较多 options.add_argument('window-size=600,600') # 设置窗口启动位置(左上角坐标) options.add_argument('window-position=300,0') # 无痕模式浏览,不记录任何历史记录 options.add_argument('incognito') # 禁用Javascript,如果觉得速度慢在加上这个 options.add_argument('–disable-javascript') # 禁用Java options.add_argument('–disable-java') #手动指定使用的浏览器安装位置,一般可以自动找到 options.binary_location = r"D:Chrome\chrome.exe" # 隐藏滚动条, 应对一些特殊页面 options.add_argument('--hide-scrollbars') # 谷歌文档提到需要加上这个属性来规避bug options.add_argument('--disable-gpu') # ip代理 options.add_argument('--proxy-server=http://ip:port') # 修改浏览器的User-Agent伪装你的浏览器,用来模拟移动设备,比如模拟 android QQ浏览器 iphone options.add_argument('User-Agent=Mozilla/5.0 ...iphone信息...') # 生成浏览器,启动 browser=webdriver.Chrome(driver_path, options=options) browser.get('https://www.baidu.com') browser.close() # 记得关闭来回收资源

 2.selenium添加代理

为selenium爬虫添加代理,这个地方尤其需要注意的是,在选择代理时,尽量选择静态IP,才能提升爬取的稳定性。

因为既然选择selenium来做爬虫,说明网站的反爬能力比较高(要不然直接上scrapy了),对网页之间的连贯性,cookies,用户状态等有较高的监测。

如果使用动态匿名IP,每个IP的存活时间是很短的(1~3分钟),很容易被检测到失效

from selenium import webdriver
# 静态IP:102.23.1.105:2005
# 阿布云动态IP:http://D37EPSERV96VT4W2:CERU56DAEB345HU90@proxy.abuyun.com:9020
PROXY = "proxy_host:proxy:port"
options = webdriver.ChromeOptions()
desired_capabilities = options.to_capabilities()
desired_capabilities['proxy'] = {
    "httpProxy": PROXY,
    "ftpProxy": PROXY,
    "sslProxy": PROXY,
    "noProxy": None,
    "proxyType": "MANUAL",
    "class": "org.openqa.selenium.Proxy",
    "autodetect": False
}
driver = webdriver.Chrome(desired_capabilities = desired_capabilities)

3.模拟移动设备

我们可以通过设置user-agent伪装成移动设备,用来模拟登录手机的网站

import time
from selenium import webdriver

options = webdriver.ChromeOptions()
# 中文编码
options.add_argument('lang=zh_CN.UTF-8')
# 最大话
# options.add_argument('--start-maximized')

# 禁止加载图片 任选一种
options.add_argument('blink-settings=imagesEnabled=false')
# prefs = {
#     'profile.default_content_setting_values.images': 2
# }
# options.add_experimental_option('prefs', prefs)

# 最常见的场景是设置 user-argument 来模拟移动设备,比如下面模拟 iphone6
options.add_argument(
    'user-agent="Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) '
    'AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 '
    'Mobile/13B143 Safari/601.1"')


driver_path = './driver/chrome/chromedriver.exe'  # 驱动器的地址,因人而异
driver = webdriver.Chrome(driver_path,chrome_options=options)

urls = [
    'http://www.touxiangzhan.com/qinglvtouxiang/',
    'http://www.touxiangzhan.com/nanshengtouxiang/',
    'http://www.touxiangzhan.com/nvshengtouxiang/',
    'http://www.touxiangzhan.com/oumeitouxiang/',
    'http://www.touxiangzhan.com/daizitouxiang/',
]
start_time = time.time()
for url in urls:
    try:
        driver.get(url)
        time.sleep(2)
    except Exception as e:
        print(e)
print(time.time() - start_time)

driver.quit()
模拟iphone6访问手机网站

4.添加Adblock Plus插件屏蔽广告

在使用 ChromeDriver 过程中,我们肯定是不希望遇到广告的
日常过程中我们怎么屏蔽广告,现在也怎么做就好了,下载安装屏蔽广告的 Adblock Plus即可
(这个插件真的是个神器,平时你搜索出来前几条结果都是广告,装了这个再也没有广告了)

自己去百度下载一个,安装好后指定路径就可以了

options = webdriver.ChromeOptions()
options.add_extension('插件安装路径,绝对相对都可以')
driver = webdriver.Chrome(chrome_options=options)

参考:

https://www.jianshu.com/p/8d2af62c95d2

https://blog.csdn.net/xc_zhou/article/details/82415870

三、八种选择器 和 WebElement对象的方法

八种方法 和 By的本质

driver.find_element_by_id('kw') # 此类方法底层还是调用find_element,就是个套娃多此一举
​
driver.find_element('id', 'kw') # 最基本的,4.0 alpha版本也是推荐这个
driver.find_element(By.ID, 'kw') # 我喜欢这个,不用写那么多字符串
# 从以下By源码可以看出,By其实就是将八种方法的字符串封装成了类属性
class By(object):
    ID = "id"
    XPATH = "xpath"
    LINK_TEXT = "link text"
    PARTIAL_LINK_TEXT = "partial link text"
    NAME = "name"
    TAG_NAME = "tag name"
    CLASS_NAME = "class name"
    CSS_SELECTOR = "css selector"

 

1) 选择器 基本用法

# 第一种 傻瓜选择器
#
1、find_element_by_id 根据id找 # 2、find_element_by_link_text 根据完整文字查找 # 3、find_element_by_partial_link_text 根据文字中个别关键字就可以找到控件 模糊查询 # 4、find_element_by_tag_name 根据标签名 # 5、find_element_by_class_name 根据类名 # 6、find_element_by_name 根据属性名 # 第二种 css选择器
# 7、find_element_by_css_selector 根据css选择器
# 第三种 xpath选择器
# 8、find_element_by_xpath 根据xpath选择

css和xpath选择器不管在哪里使用,都是通用的,用法都一样

2)By类 简化选择的语法

from selenium.webdriver.common.by import By #按照什么方式查找

self.driver.find_element(By.ID, "stRegisterDate").click()
self.driver.find_element(By.ID, "stRegisterDate").send_keys('2019-00-00')
self.driver.find_element(By.CSS_SELECTOR, "#specialCoverage input").click()

val = self.driver.find_element(By.XPATH, ".//option[. = 'xxoo1']").get_attribute('value')

certype = self.driver.find_element(By.ID, "certType")
certype.click()
certype.find_element(By.XPATH, ".//option[. = 'ooxx']").click()  # 元素对象可以往后继续查找

3) WebElement对象的属性和方法

# 对元素属性的获取以及操作
from selenium import webdriver
from selenium.webdriver.common.keys import Keys #键盘按键操作

browser=webdriver.Chrome()
element=browser.find_element_by_id('kw')
data = 'pwd123'

element.click() # 对元素执行点击操作
element.clear() # 清空,后面不支持直接跟send_key,这个方法及其low,很容易出现不能清空bug,清空方法见下
element.text    # 获取文本
element.get_attribute('属性名')       # 获取属性的值,如src的链接
print(element.element.text)          # 请输入密码
print(element.get_attribute('src'))  # www.baidu.com

# Keys类的操作,更多按键直接见源码
element.send_keys(data)              # 向输入框输入数据
element.send_keys(Keys.CONTROL,"a")  # 全选
element.send_keys(Keys.CONTROL,"x")  # 剪切
element.send_keys(Keys.CONTROL,"c")  # 复制
element.send_keys(Keys.CONTROL,"v")  # 粘贴
element.send_keys(Keys.ENTER)        # 回车
element.send_keys(Keys.BACK_SPACE)   # 删除
element.send_keys(Keys.SPACE)        # 空格键

#获取标签ID,位置,名称,大小(了解)
print(element.id)
print(element.location)
print(element.tag_name)
print(element.size)

# WebElement对象还有 is_displayed() 、is_enabled()、is_selected() 方法

clear()方法总是清空失败,以下方法可解决:

 

elem = self.driver.find_element_by_xpath('//div[@id="insuranceCarOwnInfoComAddress"]/div/input')
elem.send_keys(Keys.CONTROL, "a")
elem.send_keys(ownr_addr)

# 直接js设值
self.driver.execute_script('arguments[0].value="{}";'.format(nature_of_use), elem)
self.driver.execute_script(f'document.getElementsByName("taxVehicleType")[0].value="{val}"')
View Code

 

>>>>链接<<<<

4)  xpath选择器

详细教程

1. 基本语法

尤其好用,语法强大,和id选择并列荣获最热门的选择器

XPath 是一门在 XML 文档中查找信息的语言。

XPath 可用来在 XML 文档中对元素和属性进行遍历

doc='''
<html>
 <head>
  <base href='http://example.com/' />
  <title>Example website</title>
 </head>
 <body>
  <div id='images'>
   <a href='image1.html' a="xxx">Name: My image 1 <br /><img src='image1_thumb.jpg' /></a>
   <a href='image2.html'>Name: My image 2 <br /><img src='image2_thumb.jpg' /></a>
   <a href='image3.html'>Name: My image 3 <br /><img src='image3_thumb.jpg' /></a>
   <a href='image4.html' class='li'>Name: My image 4 <br /><img src='image4_thumb.jpg' /></a>
   <a href='image5.html' class='li li-item' name='items'>Name: My image 5 <br /><img src='image5_thumb.jpg' /></a>
   <a href='image6.html' name='items'><span><h5>test</h5></span>Name: My image 6 <br /><img src='image6_thumb.jpg' /></a>
  </div>
 </body>
</html>
'''
doc
from lxml import etree

html=etree.HTML(doc)
# html=etree.parse('search.html',etree.HTMLParser())
# 1 所有节点
a=html.xpath('//*')    #匹配所有标签
# 2 指定节点(结果为列表)
a=html.xpath('//head')
# 3 子节点,子孙节点
a=html.xpath('//div/a')
a=html.xpath('//body/a') #无数据
a=html.xpath('//body//a')
# 4 父节点
# a=html.xpath('//body//a[@href="image1.html"]/..')
a=html.xpath('//body//a[1]/..')  #从1开始
# 也可以这样
a=html.xpath('//body//a[1]/parent::*')
# 5 属性匹配
a=html.xpath('//body//a[@href="image1.html"]')

# 6 文本获取
a=html.xpath('//body//a[@href="image1.html"]/text()')
a=html.xpath('//body//a/text()')

# 7 属性获取
a=html.xpath('//body//a/@href')
# # 注意从1 开始取(不是从0)
a=html.xpath('//body//a[2]/@href')
# 8 属性多值匹配
#  a 标签有多个class类,直接匹配就不可以了,需要用contains
# a=html.xpath('//body//a[@class="li"]')
a=html.xpath('//body//a[contains(@class,"li")]/text()')
# a=html.xpath('//body//a[contains(@class,"li")]/text()')
# 9 多属性匹配
a=html.xpath('//body//a[contains(@class,"li") or @name="items"]')
a=html.xpath('//body//a[contains(@class,"li") and @name="items"]/text()')
a=html.xpath('//body//a[contains(@class,"li")]/text()')
# 10 按序选择
a=html.xpath('//a[2]/text()')
a=html.xpath('//a[2]/@href')
# 取最后一个
a=html.xpath('//a[last()]/@href')
# 位置小于3的
a=html.xpath('//a[position()<3]/@href')
# 倒数第二个
a=html.xpath('//a[last()-2]/@href')
# 11 节点轴选择
# ancestor:祖先节点
# 使用了* 获取所有祖先节点
a=html.xpath('//a/ancestor::*')
# # 获取祖先节点中的div
a=html.xpath('//a/ancestor::div')
# attribute:属性值
a=html.xpath('//a[1]/attribute::*')
# child:直接子节点
a=html.xpath('//a[1]/child::*')
# descendant:所有子孙节点
a=html.xpath('//a[6]/descendant::*')
# following:当前节点之后所有节点
a=html.xpath('//a[1]/following::*')
a=html.xpath('//a[1]/following::*[1]/@href')
# following-sibling:当前节点之后同级节点
a=html.xpath('//a[1]/following-sibling::*')
a=html.xpath('//a[1]/following-sibling::a')
a=html.xpath('//a[1]/following-sibling::*[2]/text()')
a=html.xpath('//a[1]/following-sibling::*[2]/@href')

print(a)
语法使用
# contains语法中,string()比text()范围更广,兼容标签和特殊字符
elem = self.driver.find_element(By.XPATH, f'//input[../../td[contains(string(),"{choice}")]]')
# text()匹配
self.driver.find_element_by_xpath('//input[@id="carOcrInput"]/../button[./span[text()="确认"]]')

# 多个筛选条件(span包含关键字,并且他有个div兄弟id是666)
elem = self.driver.find_element_by_xpath(f'//span[contains(text(),"{category}")][../div[@id="666"]]')
# 轴定位 找一个span,他爷爷下面的div有一个id为xxoo的input后代
self.driver.find_element_by_xpath("//span[../div/descendant::input[@id='insurance']]")
# self.driver.find_element(By.XPATH, '//span[text()="车辆损失险"]/ancestor::tr/td[1]/descendant::input')

# 函数定位
# 页面上有两个一毛一样的元素,无法定位,就用last()函数
elem = self.driverwait.until_find_element(By.XPATH,'(//ul[./li/span[text()="金融业"]])[last()]/li[./span[text()="其他行业"]]')
elem.click()
项目常用高级语法

2. 轴定位

当某些属性动态变化,即该element没有固定的属性值,就只能通过相对位置定位,可以使用轴定位

  1. parent::div 上层父节点,你那叫div的亲生爸爸,最多有一个;
  2. child::div 下层所有子节点,你的所有亲儿子中叫div的;
  3. ancestor::div 上面所有直系节点,是你亲生爸爸或者你亲爹或者你亲爹的爸爸中叫div的;
  4. descendant::div 下面所有节点,你的后代中叫div的,不包括你弟弟的后代;
  5. following::div 自你以下页面中所有节点叫div的;
  6. following-sibling::div 同层下节点,你所有的亲弟弟中叫div的;
  7. preceding::div 同层上节点,你所有的亲哥哥以及他们的后代中叫div的;
  8. preceding-sibling::div 同层上节点,你所有的亲哥哥中叫div的; 

详见

5)  百度、京东实例演示 

# 代码实现登录百度(因为涉及到js代码执行,reqquests不行,我们使用selenium)
from selenium import webdriver

import time
bro=webdriver.Chrome()
bro.get("http://www.baidu.com")

bro.implicitly_wait(10)  # 这里设置隐式等待等待所有控件加载成功,不然会报错,程序运行太快还没来得及加载

# 根据链接名字找到控件(a标签的文字) 网页右上角“登录”
dl_button=bro.find_element_by_link_text("登录")
dl_button.click()

# 登陆界面登录按钮
user_login=bro.find_element_by_id('TANGRAM__PSP_10__footerULoginBtn')
time.sleep(1)
user_login.click()

# 找到账号和密码输入框并输入,然后提交
input_name=bro.find_element_by_name('userName')
input_name.send_keys("xxxx")
input_password=bro.find_element_by_id("TANGRAM__PSP_10__password")
input_password.send_keys("xxxxxx")
submit_button=bro.find_element_by_id('TANGRAM__PSP_10__submit')
time.sleep(1)
submit_button.click()

time.sleep(100)

print(bro.get_cookies())  # 拿到cookie
# 我们用selenium登录(有js代码执行)拿到cookie,然后后续操作用requests(性能高)
bro.close()
登录百度
from selenium import webdriver
from selenium.webdriver.common.keys import Keys #键盘按键操作
import time
bro=webdriver.Chrome()
bro.get("https://www.jd.com")

# 这里设置隐式等待等待所有控件加载成功,不然会报错,程序运行太快还没来得及加载
bro.implicitly_wait(10)


#第三步 实现函数
def get_goods(bro):
    print("------------------------------------")
    goods_li = bro.find_elements_by_class_name('gl-item')
    for good in goods_li:
        img_url = good.find_element_by_css_selector('.p-img a img').get_attribute('src')
        # 如果链接为空,是因为网站有懒加载属性,当滑到该商品才有链接,我们直接取懒加载链接
        if not img_url:
            img_url = 'https:' + good.find_element_by_css_selector('.p-img a img').get_attribute('data-lazy-img')
        url = good.find_element_by_css_selector('.p-img a').get_attribute('href')
        price = good.find_element_by_css_selector('.p-price i').text
        name = good.find_element_by_css_selector('.p-name em').text.replace('\n', '')
        commit = good.find_element_by_css_selector('.p-commit a').text
        print('''
        商品链接:%s
        商品图片:%s
        商品名字:%s
        商品价格:%s
        商品评论数:%s

        ''' % (url, img_url, name, price, commit))

    next_page = bro.find_element_by_partial_link_text("下一页")  # 找到底部下一页按钮开始下一页加载
    time.sleep(1)
    next_page.click()
    time.sleep(1)
    get_goods(bro)
# 第一步 登录首页,拿到搜索框,输入商品名,点击回车
input_search=bro.find_element_by_id('key')
input_search.send_keys("性感内衣")
input_search.send_keys(Keys.ENTER)

#第二部 进入商品界面,为了复用我们写成函数
try:
    get_goods(bro)
except Exception as e:
    print("结束")
finally:
    bro.close()
爬取京东

四、selenium的等待方式 以及 EC模块 

等待的三大方式:
1.强制等待
    所有自动化学习者,最先接触的等待就是强制等待(Sleep)
    作用:当代码运行到强制等待这一行的时候,无论出于什么情况,都强制性等待指定的时间
    优势:简单入门,调试的一把好手
    劣势:只能够对单次生效,无法做有效的判断,会浪费大量的时间
2.隐式等待
    藏起来的等待,一次设置,终生有效,针对于当下的WebDriver对象,进行的等待时长的设置直接通过WebDriver对象的implicitly_wait()方法进行设置
    作用:对WebDriver对象设置全局等待,每一次操作,如遇到页面加载,则默认进入隐式等待,如遇元素无法找到,则进入隐式等待,当达到等待最大时长,则继续进行后续的代码
    优势:设置一次即可,全局使用,而且等不到不会报错
    劣势:必须等待页面加载完成才会进入到后续的操作,或者等待超时再进入后续的操作
3.显式等待
    指名道姓的等,专门用于等待指定的元素对象,超时后会报错
    通过导入from selenium.webdriver.support.wait import WebDriverWait
    优势:专门用于对指定的某一个元素进行等待

 

selenium只是模拟浏览器的行为,而浏览器解析页面是需要时间的(执行css,js),一些元素可能需要过一段时间才能加载出来,为了保证能查找到元素,必须等待

除了我们简单粗暴效率低下笨的要死的time.sleep()等待,selenium提供了两种更好用的等待方式

1.隐式等待

隐形等待是设置了一个最长等待时间,等待所有元素加载,如果在规定时间内网页加载完成,则执行下一步,否则一直等到时间截止,然后代码执行下一步,页面则抛出异常。

隐式等待虽然方便,但有一个弊端,那就是程序会一直等待整个页面加载完成,也就是一般情况下你看到浏览器标签栏那个小圈不再转,才会执行下一步,但有时候页面想要的元素早就在加载完成了,但是因为个别js之类的东西特别慢,我仍得等到页面全部完成才能执行下一步,我想等我要的元素出来之后就下一步怎么办?那就用显性等待

#方式一: 隐式等待:(推荐使用)
  在查找所有元素时,如果尚未被加载,则最多等10秒,10秒还不行就拜拜,10秒内等到了就继续执行
  在browser.get('https://www.baidu.com')前就设置,针对所有元素有效
    browser.implicitly_wait(10)
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By #按照什么方式查找,By.ID,By.CSS_SELECTOR
from selenium.webdriver.common.keys import Keys #键盘按键操作
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait #等待页面加载某些元素

browser=webdriver.Chrome()

#隐式等待:在查找所有元素时,如果尚未被加载,则等10秒
browser.implicitly_wait(10)

browser.get('https://www.baidu.com')

input_tag=browser.find_element_by_id('kw')
input_tag.send_keys('美女')
input_tag.send_keys(Keys.ENTER)

contents=browser.find_element_by_id('content_left') #没有等待环节而直接查找,找不到则会报错
print(contents)

browser.close()
隐式等待实例

2.显示等待

它主要的意思就是:程序每隔xx秒看一眼,如果条件成立了,则执行下一步,否则继续等待,直到超过设置的最长时间,然后抛出TimeoutException

WebDriverWait类,配合该类的until()和until_not()方法,就能够根据判断条件而进行灵活地等待了。

#方式二: 显式等待:
  等待某个元素被加载,最多等10秒,10秒还不行就拜拜
  在browser.get('https://www.baidu.com')之后设置,只针对某个元素有效
  wait=WebDriverWait(browser,10)
  wait.until(EC.presence_of_element_located((By.ID,'content_left')))
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By #按照什么方式查找,By.ID,By.CSS_SELECTOR
from selenium.webdriver.common.keys import Keys #键盘按键操作
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait #等待页面加载某些元素

browser=webdriver.Chrome()
browser.get('https://www.baidu.com')



input_tag=browser.find_element_by_id('kw')
input_tag.send_keys('美女')
input_tag.send_keys(Keys.ENTER)

#显式等待:显式地等待某个元素被加载
wait=WebDriverWait(browser,10)
wait.until(EC.presence_of_element_located((By.ID,'content_left')))

contents=browser.find_element(By.CSS_SELECTOR,'#content_left')
print(contents)

browser.close()
显示等待简单示例

2.1 WebDriverWait 类

class WebDriverWait():
    __init__:
        driver: 传入WebDriver实例,即我们上例中的driver
        timeout: 超时时间,等待的最长时间(同时要考虑隐性等待时间)
        poll_frequency: 调用until或until_not中的方法的间隔时间,默认是0.5秒,0.5秒去检测一次
        ignored_exceptions: 忽略的异常,如果在调用until或until_not的过程中抛出这个元组中的异常,则不中断代码,继续等待,如果抛出的是这个元组外的异常,则中断代码,抛出异常。默认只有NoSuchElementException
    
    def until():
        method: 在等待期间,每隔一段时间调用这个传入的方法,直到返回值不是False
        message: 如果超时,抛出TimeoutException,将message传入异常

    def until_not():
        与until相反,until是当某元素出现或什么条件成立则继续执行,until_not是当某元素消失或什么条件不成立则继续执行,参数也相同,不再赘述

until或until_not中的可执行方法method参数,很多人传入了WebElement对象,如下:

WebDriverWait(driver, 10).until(driver.find_element_by_id('kw')) # 错误

这里的参数一定要是可以调用的,即这个对象一定有 __call__() 方法,你可以用selenium提供的 expected_conditions 模块中的各种条件,

当然也可以用WebElement的 is_displayed() 、is_enabled()、is_selected() 方法,或者用自己封装的方法都可以,下面我们只分析expected_conditions 

2.2  expected_conditions 模块

expected_conditions是selenium的一个模块,其中包含一系列可用于判断的条件:

# coding=utf-8
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait

base_url = "http://www.baidu.com"
driver = webdriver.Firefox()
driver.implicitly_wait(5)
'''隐式等待和显示等待都存在时,超时时间取二者中较大的'''
locator = (By.ID, 'kw')
driver.get(base_url)

WebDriverWait(driver, 10).until(EC.text_to_be_present_in_element((By.XPATH, "//*[@id='u1']/a[8]"), u'设置'))
'''判断指定的元素中是否包含了预期的字符串,返回布尔值'''
WebDriverWait(driver, 10).until(EC.text_to_be_present_in_element_value((By.CSS_SELECTOR, '#su'), u'百度一下'))
'''判断指定元素的属性值中是否包含了预期的字符串,返回布尔值'''

WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, "//*[@id='u1']/a[8]"))).click()
'''判断某个元素中是否可见并且可点击'''
driver.find_element_by_xpath("//*[@id='wrapper']/div[6]/a[1]").click()


# WebDriverWait(driver,10).until(EC.staleness_of(driver.find_element(By.ID,'su')))
'''等待某个元素从dom树中移除'''
# 这里没有找到合适的例子

WebDriverWait(driver, 10).until(EC.element_to_be_selected(driver.find_element(By.XPATH, "//*[@id='nr']/option[1]")))
'''判断某个元素是否被选中了,一般用在下拉列表'''

WebDriverWait(driver, 10).until(EC.element_selection_state_to_be(driver.find_element(By.XPATH, "//*[@id='nr']/option[1]"), True))
'''判断某个元素的选中状态是否符合预期'''

WebDriverWait(driver, 10).until(EC.element_located_selection_state_to_be((By.XPATH, "//*[@id='nr']/option[1]"), True))
'''判断某个元素的选中状态是否符合预期'''

driver.find_element_by_xpath(".//*[@id='gxszButton']/a[1]").click()

instance = WebDriverWait(driver, 10).until(EC.alert_is_present())
'''判断页面上是否存在alert,如果有就切换到alert并返回alert的内容'''
print(instance.text)
instance.accept()

WebDriverWait(driver, 10).until(EC.title_is(u"百度一下,你就知道"))
'''判断title是否相同,返回布尔值'''
WebDriverWait(driver, 10).until(EC.title_contains(u"百度一下"))
'''判断title是否包含,返回布尔值'''

WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.ID, 'kw')))
'''判断某个元素是否被加到了dom树里,并不代表该元素一定可见,如果定位到就返回WebElement'''
WebDriverWait(driver, 10).until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, '.mnav')))
'''判断是否至少有1个元素存在于dom树中,如果定位到就返回列表'''

WebDriverWait(driver, 10).until(EC.visibility_of(driver.find_element(by=By.ID, value='kw')))
'''判断元素是否可见,如果可见就返回这个元素'''
WebDriverWait(driver, 10).until(EC.visibility_of_element_located((By.ID, 'su')))
'''判断某个元素是否被添加到了dom里并且可见,可见代表元素可显示且宽和高都大于0'''
WebDriverWait(driver, 10).until(EC.visibility_of_any_elements_located((By.CSS_SELECTOR, '.mnav')))
'''判断是否至少有一个元素在页面中可见,如果定位到就返回列表'''
WebDriverWait(driver, 10).until(EC.invisibility_of_element_located((By.CSS_SELECTOR, '#swfEveryCookieWrap')))
'''判断某个元素在dom不可见,不可见返回这个元素,如果可见返回False,'''
# 注意#swfEveryCookieWrap在此页面中是一个隐藏的元素

driver.close()
View Code
# 等待元素消失,见博客
WebDriverWait(self.driver, 5).until(EC.invisibility_of_element(elem))
# 等待元素不再存在于DOM
WebDriverWait(self.driver,timeout).until(EC.staleness_of(elem))
# 判断界面是否存在     
def exists(self, timeout=3.0):
    if self.root:
        return True
    try:
        # self.root = WebDriverWait(self.driver, timeout).until(EC.presence_of_element_located((By.CLASS_NAME, 'el-message')))
        # 这样才行,上面的不行,气死了....
        self.root = self.driverwait.until_find_element(By.XPATH,'//*[@class="el-message"]') # 自己写的辅助等待类
        except TimeoutException:
            return False
        return True
# 等待加载
locator = (By.XPATH, '//*[@id="insuranceApplicantInfoIdentifyNumber"]/div/input')
text = data['身份证号']
WebDriverWait(self.driver, 2).until(EC.text_to_be_present_in_element_value(locator, text))
用法举例

>>>参考链接<<<

>>>参考链接<<<

五、 ActionChains 鼠标操作模块

需求:需要模拟鼠标操作才能进行的情况,比如单击、双击、鼠标右键、拖拽等操作

原理:调用ActionChains不会立即执行,而是将所有的操作顺序放在一个队列里,当调用perform()方法时,队列中的事件会被依次执行

写法:支持链式写法和分步写法

from selenium.webdriver.common.action_chains import ActionChains
class ActionChains(object):
    def __init__(self, driver):
        self._driver = driver
        self._actions = []

    def perform(self):
        #将所有的操作顺序放在一个队列里,当调用perform()方法时,队列中的事件会被依次执行

    def click(self, on_element=None):
        点击:
        - 如果参数不写,那么点击的是当前鼠标位置
        - 如果参数写定位到的元素对象element,那就是点这个元素

    def click_and_hold(self, on_element=None):
        鼠标左键按住某个元素
        - 如果参数不写,那么点的是当前鼠标位置
        - 如果参数写定位到的元素对象element,那就是点这个元素

    def context_click(self, on_element=None):
        鼠标右键点击
        - 如果参数不写,那么点的是当前鼠标位置
        - 如果参数写定位到的元素对象element,那就是点这个元素

    def double_click(self, on_element=None):
        双击鼠标
        - 如果参数不写,那么点的是当前鼠标位置
        - 如果参数写定位到的元素对象element,那就是点这个元素

    def drag_and_drop(self, source, target):
        按住源元素上的鼠标左键,然后移动到目标元素并释放鼠标按钮
        - source: 按住鼠标的元素位置
        - target: 松开鼠标的元素位置

    def drag_and_drop_by_offset(self, source, xoffset, yoffset):
        按住源元素上的鼠标左键,然后移动到目标偏移量并释放鼠标按钮。
        - source: 按住鼠标的元素位置
        - xoffset: X 轴的偏移量
        - yoffset: Y 轴的偏移量

    def key_down(self, value, element=None):
        只发送一个按键,而不释放它。只应用于修饰键(控制、alt和shift)。

        - value: 要发送的修饰符键。值在“Keys”类中定义。
        - element: 定位的元素
        如果element参数不写就是当前鼠标的位置

        举个例子,按住 ctrl+c::

        ActionChains(driver).key_down(Keys.CONTROL).send_keys('c').key_up(Keys.CONTROL).perform()

    def key_up(self, value, element=None):
        # 释放按键,配合上面的一起使用

    def move_by_offset(self, xoffset, yoffset):
        将鼠标移动到当前鼠标位置的偏移量

         - xoffset: X轴 作为一个正整数或负整数移动到x偏移量
         - yoffset: Y轴 偏移,作为正整数或负整数。


    def move_to_element(self, to_element):
        鼠标悬停
        - to_element: 定位需要悬停的元素


    def move_to_element_with_offset(self, to_element, xoffset, yoffset):
        通过指定元素的偏移量移动鼠标。偏移量与元素的左上角相对
        - to_element: 定位需要悬停的元素
        - xoffset: X 轴偏移量
        - yoffset: Y 轴偏移量


    def release(self, on_element=None):
        释放一个元素上的鼠标按钮。

        - 如果参数不写,那么是当前鼠标位置
        - 如果参数写定位到的元素对象element,那就是这个元素.

    def send_keys(self, *keys_to_send):
        发送到当前焦点元素
        要发送的按键。修饰符键常数可以在“Keys”类。
   

    def send_keys_to_element(self, element, *keys_to_send):
        发送到定位到的元素上
        - element: 定位的元素
        - keys_to_send: 要发送的按键。修饰符键常数可以在“Keys”类。
所有操作
from selenium.webdriver import ActionChains #两种导入方式都行
# from selenium.webdriver.common.action_chains import ActionChains

# 双击元素  将driver和需双击的元素传入,并提交动作
element = self.driver.find_element(By.XPATH, f'//*[@id="resultTable"]/td[2]')
ActionChains(driver).double_click(element).perform()
# 悬停
above = driver.find_element_by_link_text('更多产品')
ActionChains(driver).move_to_element(above).perform()
# 拖放
source = driver.find_element_by_link_text('新闻')
target = driver.find_element_by_xpath('//*[@id="form"]/span[1]/span')
ActionChains(driver).drag_and_drop(source, target).perform()   #将source元素拖动到target元素位置

# 支持链式操作,一次传入多个动作,并提交动作  按住ctrl + c:
ActionChains(driver).key_down(Keys.CONTROL).send_keys('c').key_up(Keys.CONTROL).perform()

 

>>>>>参考链接<<<<<>>参考链接<<<

 六、selenium执行js

1.web自动化测试框架的底层原理就是通过js来实现对web元素的操作
    selenium:它将我们要进行自动化操作的网页内嵌到它自己的网页,然后通过脚本语言js去执行自动化操作
    自动化测试框(appium,qtp,macaca,roboframework)底层用的也是selenium
    接口测试,了解接口的本质,接口的原理,接口发送网络请求通信的原理,
2.提高我们自动化用例执行的效率和稳定性
    时间日历控件
    文件上传
    点击
    输入
    勾选
3.selenium难以实现的操作
    a.一些隐藏的按钮,通过js更改元素的属性,显示隐藏的按钮
    b.滚动条
    c.前端限制输入,移除readonly属性
# js代替elem.click()选中input
elem = self.driver.find_element(By.XPATH, f'//input[../../td[contains(text(),"{choice}")]]')
self.driver.execute_script('arguments[0].checked=true;', elem) 
# js直接点击元素(一切皆可js,但是有的按钮,比如查询,可能js传值或点击后不会自动加载,必须click)
self.driver.execute_script("arguments[0].click()", elem)
# 直接js设值
self.driver.execute_script('arguments[0].value="{}";'.format(nature_of_use), elem)
# 滚动到某个元素
self.driver.execute_script("arguments[0].scrollIntoView();", elem)

 

1)情景1:页面上的元素超过一屏,无法定位:

当页面上的元素超过一屏后,想操作屏幕下方的元素,是不能直接定位到,会报元素不可见的。这时候需要借助滚动条来拖动屏幕,使被操作的元素显示在当前的屏幕上。

滚动条是无法直接用定位工具来定位的。selenium里面也没有直接的方法去控制滚动条,

这时候只能借助JS了,selenium提供了一个操作js的方法:  execute_script(),可以直接执行js的脚本。

我们可以先让页面直接跳到元素出现的位置,然后就可以操作了

方法一 操作滚动条 元素聚焦:

  element.scrollIntoView() 参数默认为true

  参数为true:调用该函数,页面发送滚动,使element的顶部与视图(容器)顶部对齐

  参数为false:使element的底部与视图(容器)底部对齐

target = driver.find_element_by_xxxx()
driver.execute_script("arguments[0].scrollIntoView();", target)

方法二:直接js代码实现修改删除属性操作

#1)第一种:传入selenium元素,修改属性值
        # 例一:这个是那种需要输入日期的元素,点击之后出现小日历让你选择,页面可能太大,元素看不到,定位到后不能直接点击,用js传值后自动跳转到该位置,就可以进行其他点击操作
        start_datetime = data['start_date']
        elem = self.driver.find_element(By.ID, "compulsoryStartDate")
        # js的DOM操作查找到的元素是个列表,arguments[0],代表第一个参数,如果搜索对象只有一个,那就是我们要找的目标,即elem,
     # 这是execute_script提供的将元素传入js代码的方法,除了用selenium的元素定位,这里也可以用原生的js代码查找到控件,见第二种
# 选择时间的话太麻烦,直接js修改就好了 driver.execute_script('arguments[0].value="{}";'.format(start_datetime), elem) elem.click() elem.send_keys(Keys.ENTER) # 例二:type = "checkbox",打勾选择那种,可以点击也可以直接修改checked=true属性,点击在看不到元素的情况下会报错,js选择就没问题 driver.execute_script('arguments[0].checked=true;', elem) #2)第二种:直接使用原生js的代码查找元素,修改属性值值 driver.execute_script(f'document.getElementsByName("taxVehicleType")[0].value="{val}"') driver.execute_script(f'document.querySelector("#ele_id").value="{value}"') # 删除标签的target属性,阻止跳转网页 driver.execute_script('document.getElementsByClassName("site-nav-right fr")[0].childNodes[1].removeAttribute("target")')

更多js的DOM操作见链接

2)情景2:需要执行函数

# 在登陆某公司网站时跳出来mac地址绑定失败,查看网页js,搜索关键字mac可以找到这么个js函数,
# 模仿函数执行js,直接返回一个网站允许的固定mac,绕过本地mac绑定
 function getAndCheckMacAddress() {
     var macAddr = getMacAddressIfPresent();
     if (!macAddr) {
         dialogs.warning("无法获取 MAC 地址,有如下几种情况,请予以确认。<br/>" +
                 "1. 当前浏览器不支持获取 MAC 地址,请使用 IE 浏览器!<br/>" +
                 "2. IE 浏览器 ActiveX 控件未启用,如有疑问,请查看帮助手册!", "提示");
         return null;
     }
     return macAddr;}
driver.execute_script('getAndCheckMacAddress = function () { return "0a:1b:3c:4c:5d:6e";}')

参考链接:

https://www.cnblogs.com/wenm1128/p/11534887.html

https://blog.csdn.net/yinlin330/article/details/82625454

七、其他技术点

1. Select 、ul-li 下拉选择框

select_ele = driver.find_element_by_xpath("//select[@name='modules']")
select = Select(select_ele)
# 1.通过索引进行选择
# select.select_by_index('2')
# 2.通过value进行选择
select.select_by_value('doc')
# 3.通过文本进行选择
select.select_by_visible_text("文档")
select下拉选择框
# 第一种 li 下面有input,但是readonly,不能直接改值,先点击再js设值value
        elem = self.driver.find_element_by_xpath('//input[@id="insuranceCarInfoNatureOfUsage"]')
        self.driver.execute_script("arguments[0].click()", elem)
        # 直接js设值
        self.driver.execute_script('arguments[0].value="{}";'.format(nature_of_use), elem)
 # 第二种 js改值虽然可以暂时成功,但是系统识别不了,或者刷新后没了,就得 输入-点击
    # 直接点击下拉(点击后只有几项li):
            elem = self.driver.find_element_by_id('insuranceChannelInfoBusinessSource')
            # 点击出现下拉
            self.driver.execute_script("arguments[0].click()", elem)
            # 等待出现后,点击选择
            elem = self.driverwait.until_find_element(By.XPATH, '//span[contains(text(),"19007--个人代理")]')
            self.driver.execute_script("arguments[0].click()", elem)        
     # 直接输入关键字后刷新下拉出目标li(点击后有超多li选项,显示不全)
            # 先输入关键词
            elem = self.driver.find_element_by_id('loginCompleteCode')
            elem.send_keys(organization) # 直接js传值后可能后续不能正常加载,还是send_key + click操作来的更正常
            # 等待对应的li元素加载出来后再点击
            elem = self.driverwait.until_find_element(By.XPATH, '//span[contains(text(),"05--浙江分公司")]')
            self.driver.execute_script("arguments[0].click()",elem)
            time.sleep(2)
ul-li下拉选择框(非select-optoin下拉框)

2.cookies获取和设置

from selenium import webdriver

browser=webdriver.Chrome()
browser.get('https://www.zhihu.com/explore')
print(browser.get_cookies()) #获取 browser.add_cookie({'k1':'xxx','k2':'yyy'}) # 设置 print(browser.get_cookies()) # 调用 # browser.delete_all_cookies()

3.字符串和中文相互转换

from urllib.parse import unquote_plus  #字符转中文
from urllib.parse import urlencode  #中文转字符
msg = '''
"client_id=c3cef7c66a1843f8b3a9e6a1e3160e20&grant_type=password&timestamp=1574838172749&source=com.zhihu.web&signature=d9ca5ecd24ebcfd42360eabd392d860e837005d8&username=%2B8618953675221&password=lqz12345&captcha=&lang=cn&utm_source=&ref_source=other_https%3A%2F%2Fwww.zhihu.com%2Fsignin%3Fnext%3D%252F"
'''
print(unquote_plus(msg))
字符串和中文相互转换

4.模拟浏览器前进后退

#模拟浏览器的前进后退
import time
from selenium import webdriver

browser=webdriver.Chrome()
browser.get('https://www.baidu.com')
browser.get('https://www.taobao.com')
browser.get('http://www.sina.com.cn/')

browser.back()
time.sleep(10)
browser.forward()
browser.close()
View Code

5.选项卡切换 | 窗口切换

cur_window = driver.current_window_handle
windows = driver.window_handles
driver.switch_to.window(windows[-1])
from selenium import webdriver
import time, os

driver_path = './driver/chrome/chromedriver.exe' if os.name == 'nt' else './driver/chrome/chromedriver'
# 打开网站主页【第一个窗口】
driver = webdriver.Chrome(driver_path)
driver.get('http://www.kgc.cn/')
driver.maximize_window()

print(driver.current_window_handle) # 当前窗口
print(driver.window_handles)  # 所有窗口


# 点击某个课程,出现课程页面【第二个窗口】
driver.find_element_by_xpath('/html/body/div[4]/div[1]/ul/li[1]').click()
time.sleep(3)

print(driver.current_window_handle)
print(driver.window_handles)

windows = driver.window_handles
driver.switch_to.window(windows[-1])
time.sleep(1)

print(driver.current_window_handle)
print(driver.window_handles)

# 【在第二个窗口页面进行元素点击操作,来判断窗口是否切换成功】
driver.find_element_by_xpath('/html/body/div[3]/div[2]/div[3]/div[1]/ul/li[3]/p').click()
time.sleep(3)

# 再次回到首页,即第一个窗口
driver.switch_to.window(windows[0])
time.sleep(1)
# 点击页面另外一个链接,出现第三个页面
driver.find_element_by_xpath('/html/body/div[3]/div/ul/li[3]/a/i').click()
time.sleep(3)

print(driver.current_window_handle)
print(driver.window_handles)

# 关闭浏览器
driver.quit()
print('测试通过')
"""
CDwindow-D815A225395FE90DAE78B341F6D1ECF7
['CDwindow-D815A225395FE90DAE78B341F6D1ECF7']

CDwindow-D815A225395FE90DAE78B341F6D1ECF7   # 不手动跳转,当前页面不变
['CDwindow-D815A225395FE90DAE78B341F6D1ECF7', 'CDwindow-A00429393F9DD58B2DE981034DCE1DCF']

CDwindow-A00429393F9DD58B2DE981034DCE1DCF    # 跳转后,当前窗口变化
['CDwindow-D815A225395FE90DAE78B341F6D1ECF7', 'CDwindow-A00429393F9DD58B2DE981034DCE1DCF']

CDwindow-D815A225395FE90DAE78B341F6D1ECF7
['CDwindow-D815A225395FE90DAE78B341F6D1ECF7', 'CDwindow-A00429393F9DD58B2DE981034DCE1DCF', 'CDwindow-95FF31A2AE2B40BF8D1F82675FB54253']
测试通过
"""
View Code

6.异常处理

from selenium import webdriver
from selenium.common.exceptions import TimeoutException,NoSuchElementException,NoSuchFrameException

try:
    browser=webdriver.Chrome()
    browser.get('http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable')
    browser.switch_to.frame('iframssseResult')

except TimeoutException as e:
    print(e)
except NoSuchFrameException as e:
    print(e)
finally:
    browser.close()
View Code

7.截图等操作总结

# 对元素截图
capcha = driver.find_element_by_id('capImg')
capcha.screenshot(save_path)
# 点击元素
driver.find_element(By.CSS_SELECTOR, '#dzbdxz').click()
# 获取元素文字
mobile = self.driver.find_element(By.XPATH, '//div[@data="insureTelephone"]').text
# 给元素中传值
driver.find_element(By.NAME, "quotationNo").send_keys(quotation_id)
# 等待元素 EC模块等知识,详见等待那一部分
quotation_id = 'xxoo'
WebDriverWait(driver, 5).until(EC.visibility_of_element_located((By.XPATH, '//td[.="{}"]'.format(quotation_id))))
# js直接修改属性,详见执行js那一部分
val='xxoo'
driver.execute_script(f'document.getElementsByName("taxVehicleType")[0].value="{val}"')
elem = self.driver.find_element(By.ID, "compulsoryStartDate")
driver.execute_script('arguments[0].value="{}";'.format(start_datetime), elem)
driver.execute_script(f'document.querySelector("#ele_id").value="{value}"')
driver.execute_script(f'document.getElementsByName("ele_name")[0].value="{value}"')

8.selenium的clear()不生效,解决输入框没法清空的情况

 >>传送门<<

七、登陆博客园

1.分步操作实现selenium登录后requests请求

import time
from selenium import webdriver
import json
browser=webdriver.Chrome()
# 我们去输入账户密码登录登录
browser.get('https://account.cnblogs.com/signin?returnUrl=https%3A%2F%2Fwww.cnblogs.com%2F')

time.sleep(30)
# 拿到cookie
cookie=browser.get_cookies() # 加s直接拿,如果是get_cookie括号里面要写具体名字
print(cookie)
# 保存cookie
with open('cookie.json','w')as f:
    json.dump(cookie,f)
selenium登录博客保存cookie
#下一次selenium登录,页面等待一段时间cookie加载完成后就自动登陆了
import time
from selenium import webdriver
import json
browser=webdriver.Chrome()
browser.get('https://www.cnblogs.com/')

# 我们直接读取cookie
with open('cookie.json','r')as f:
    di=json.load(f)

cookies = {}
# 获取cookie中的name和value,转化成requests可以使用的字典形式
for cookie in di:
    cookies[cookie['name']] = cookie['value']
print(cookies)
browser.add_cookie(cookies) # 保存转换后的cookie
browser.refresh()

time.sleep(10)
selenium再次登录直接用cookie
#request模块模拟
import requests
with open('cookie.json','r')as f:
    di=json.load(f)

cookies = {}
# 获取cookie中的name和value,转化成requests可以使用的形式
for cookie in di:
    print(cookie)
    for key in cookie.keys():
        cookies[key] = cookie[key]
print(cookies)
# browser.add_cookie(cookies) # 保存转换后的cookie
# browser.refresh()
# cookies = browser.get_cookies() # 取出

# 我们使用cookie访问自己的博客,直接就是登陆状态
res=requests.get('https://i-beta.cnblogs.com/api/user',
             cookies=cookies)

print(res.text)
request再次登录cookie自动登录

2. 整套博客园操作

import requests
from selenium import webdriver
import time
import json
# 使用selenium打开网址,然后让用户完成手工登录,再获取cookie
url = 'https://account.cnblogs.com/signin?returnUrl=https%3A%2F%2Fwww.cnblogs.com%2F'
driver = webdriver.Chrome()
driver.get(url=url)
time.sleep(50)
driver.refresh()
c = driver.get_cookies()
print(c)
with open('xxx.txt','w') as f:
    json.dump(c,f)

time.sleep(3)
with open('xxx.txt', 'r') as f:
    di = json.load(f)
cookies = {}
# 获取cookie中的name和value,转化成requests可以使用的形式
for cookie in di:
    cookies[cookie['name']] = cookie['value']
print(cookies)
# from datetime import datetime
#
# GMT_FORMAT = '%a, %d %b %Y %H:%M:%S GMT'
#
# # Sun, 24 Nov 2019 06:14:53 GMT
# #Tue, 26 Nov 2019 22:18:23 GMT
# #Sun, 24 Nov 2019 06:14:53 GMT
# # Tue, 26 Nov 2019 14:16:01 GMT (GMT)
# print(datetime.now().strftime(GMT_FORMAT))
# ttt=str(datetime.now().strftime(GMT_FORMAT))
headers = {
    # 'authority': 'www.jd.com',
    # 'method': 'GET',
    # 'path': '/',
    # 'scheme': 'https',
    # 'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3',
    # 'accept-encoding': 'gzip, deflate, br',
    # 'accept-language': 'zh-CN,zh;q=0.9',
    # 'cache-control': 'max-age=0',
    # 'upgrade-insecure-requests': '1',
    'authority': 'i-beta.cnblogs.com',
    'method': 'GET',
    'path': '/',
    'scheme': 'https',
    'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3',
    'accept-encoding': 'gzip, deflate, br',
    'accept-language': 'zh-CN,zh;q=0.9',
    'cache-control': 'max-age=0',
    'if-modified-since': 'Sun, 24 Nov 2019 06:14:53 GMT',
    # 'if-modified-since': 'Sun, 24 Nov 2019 06:14:53 GMT,
    'sec-fetch-mode': 'navigate',
    'sec-fetch-site': 'none',
    'sec-fetch-user': '?1',
    'upgrade-insecure-requests': '1',
    'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36'

}
# 使用该cookie完成请求
response = requests.get(url='https://i-beta.cnblogs.com/api/user', headers=headers, cookies=cookies)
print('xxx')
response.encoding = response.apparent_encoding
print(response.text)
View Code

 

posted @ 2019-12-03 20:40  www.pu  Views(604)  Comments(0Edit  收藏  举报