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()
二、谷歌浏览器的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表格:http://www.fynas.com/ua
我们可以通过设置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()
4.添加Adblock Plus插件屏蔽广告
日常过程中我们怎么屏蔽广告,现在也怎么做就好了,下载安装屏蔽广告的 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}"')
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> '''
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没有固定的属性值,就只能通过相对位置定位,可以使用轴定位
-
parent::div 上层父节点,你那叫div的亲生爸爸,最多有一个;
-
child::div 下层所有子节点,你的所有亲儿子中叫div的;
-
ancestor::div 上面所有直系节点,是你亲生爸爸或者你亲爹或者你亲爹的爸爸中叫div的;
-
descendant::div 下面所有节点,你的后代中叫div的,不包括你弟弟的后代;
-
following::div 自你以下页面中所有节点叫div的;
-
following-sibling::div 同层下节点,你所有的亲弟弟中叫div的;
-
preceding::div 同层上节点,你所有的亲哥哥以及他们的后代中叫div的;
-
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()
# 等待元素消失,见博客 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")')
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("文档")
# 第一种 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)
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×tamp=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()
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'] 测试通过 """
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()
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加载完成后就自动登陆了 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)
#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)
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)