Selenium是一个自动化测试工具,利用它我们可以驱动浏览器执行特定的动作,如点击、下拉等操作。
本文将从环境部署到项目开发一步步讲解,包括这个过程所可能遇到的一些问题,都会一一解答,有不会的问题可以在下方评论留言一起思考解决。
一.环境部署
环境部署包括mac和linux
1.安装Selenium
pip3 install selenium
这里推荐大家使用Anaconda管理python包及环境,Anaconda是一个方便的python包管理和环境管理软件,一般用来配置不同的项目环境。如果你的电脑只能安装一个环境,而两个项目却用着不同的环境,那么你可以使用Anaconda创建多个互不干扰的环境,分别运行不同版本的软件包,以达到兼容的目的。
Anaconda通过管理工具包、开发环境、Python版本,大大简化了你的工作流程。不仅可以方便地安装、更新、卸载工具包,而且安装时能自动安装相应的依赖包,同时还能使用不同的虚拟环境隔离不同要求的项目。
Anaconda的安装流程及使用
https://www.cnblogs.com/trotl/p/11863544.html
2.安装ChromeDriver
###### 2.1.查看浏览器版本
###### 2.2.在浏览器的帮助/关于Google Chrome 查看浏览器版本
###### 2.3.下载相应的ChromeDriver(两种方法)
方法一 :
- 打开ChromeDriver官方网站,根据上面的浏览器版本,下载相应版本的ChromeDriver
- 将解压好的文件放入/usr/local/bin目录中,由于mac的很多目录都是隐藏的,所以我们按快捷键command+shift+g,在弹出的窗口输入/usr/local/bin,就可以打开这个目录,接着将解压好的驱动放入此目录即可。
- 进行测试(在终端输入: chromedriver --version,可以查看到版本)
方法二 :
- 安装brew及使用可能遇到的问题
https://www.cnblogs.com/trotl/p/11862796.html
下载chromedriver
通过命令brew cask install chromedriver去下载
测试
在终端输入: chromedriver --version,可以查看到版本
3.安装识别验证码的包
- 用homebrew 在电脑上安装tesseract库
brew install tesseract
- 用pip安装支持python的tesseract
pip install PyTesseract
如果是识别中文
去往https://github.com/tesseract-ocr/tessdata下载中文数据集chi_sim.traineddata,把它放到这目录下:
/usr/local/Cellar/tesseract/3.05.01/share/tessdata4 .安装容易遇到的问题:
- 提示brew update,代表homebrew需要更新
- 提示must be writable!或者Permission denied之类问题,试试前面加sudo
- 提示Please check the permissions and owner of that directory,说明权限有问题,那么使用sudo chown root 文件路径命令获得临时root权限
提示Xcode alone is not sufficient on Sierra,使用xcode-select --install
二.实现逻辑
开始想的逻辑是,获取到验证码的地址,然后爬取下来并请求,下载验证码图片并识别再填上去,发现这样行不通,每次请求获得的验证码图片不一致,这得从会话角度去解决问题。这里我换了种思维更简单的去解决这个问题,通过截图的方式把页面上的验证码截图下来保存为图片并识别出文字。
1. 实现中所遇到的问题
chromedriver的截图只能截取当前页面的图片,不能得到整个页面的图片,这样就不能通过定位验证码图片的位置去截取验证码图片,对于页面有滑动的只能手动调试位置。
- 处理验证码失败的提示框
- 当从a页面跳转到b网页,然后获取b页面的某个元素时,容易出错。因为代码执行速度比网页加载速度快,通常会出现无法找到该元素的错误。遇到无法找到页面元素的情况,要考虑是否是代码加载过快的原因,处理方法:在获取元素前➕time.sleep(2)
快速获取元素路径的方式:网页->检查->选中对应标签->右键选择copy->copy xpath
2. 用到的一些方法
2.1 处理Windows弹出框(三种情况)
使用 driver.switch_to.alert 切换到Windows弹出框
Alert类提供了一系列操作方法:
accept() 确定
dismiss() 取消
text() 获取弹出框里面的内容
send_keys(keysToSend) 输入字符串
A.定位alert弹出框
#点击页面元素,触发alert弹出框
driver.find_element_by_xpath('//*[@id="alert"]').click()
time.sleep(3)
#等待alert弹出框可见
webdriverwait(driver,20).until(EC.alert_is_present())
#从html页面切换到alert弹框
alert = driver.switch_to.alert
#获取alert的文本内容
print(alert.text)
#接受--选择“确定”
alert.accept()
B.定位confirm弹出框
driver.find_element_by_xpath('//*[@id="confirm"]').click()
time.sleep(3)
webdriverwait(driver,20).until(EC.alert_is_present())
alert =driver.switch_to.alert
print(alert.text)
# 接受--选择“取消”
alert.dismiss()
C.定位prompt弹出框
driver.find_element_by_id("prompt").click()
time.sleep(3)
webdriverwait(driver,20).until(EC.alert_is_present())
alert =driver.switch_to.alert
alert.send_keys("jaja")
time.sleep(5)
print(alert.text)
# alert.dismiss()
alert.accept()
2.2 python+selenium调用js方法
from selenium import webdriver
js = '''var str="联想词:%s===>车系:%s";window.alert(str);''' % (alias, name)
driver.execute_script(js)
execute_script(js)和execute_async_script(js)分别是是同步和异步方法,前者会等待js代码执行完毕后主线程执行,后者它不会阻塞主线程执行。
execute_script(js) 方法如果有返回值,有以下几种情况:
* 如果返回一个页面元素(document element), 这个方法就会返回一个WebElement
* 如果返回浮点数字,这个方法就返回一个double类型的数字
* 返回非浮点数字,方法返回Long类型数字
* 返回boolean类型,方法返回Boolean类型
* 如果返回一个数组,方法会返回一个List
2.3 selenium+python的常用方法
1.创建webdriver对象
browser=webdriver.Chrome()
2.打开百度页面
browser.get('https://www.baidu.com')
3.获取网页源码
browser.page_source
4.在百度页面id为kw的输入框中输入book
driver.find_element_by_id('kw').send_keys('book’)
5.在百度页面id为kw的输入框中清除book
driver.find_element_by_id('kw’).clear()
6.在百度页面id为search的按钮点击搜索
a.driver.find_element_by_id('search').click()
b.action3 = self.driver.find_element_by_class_name('next')
ActionChains(self.driver).move_to_element(action3).double_click(action3).perform()
7.向前跳转回上一个页面
driver.back()
8.向后跳转回上一个页面
driver.forward()
9.关闭浏览器
browser.close() 关闭当前窗口
browser.quit() 退出并关闭窗口的每一个相关的驱动程序
10.获取某个元素的文本内容
driver.find_element_by_class_name("loading_btn").text
11.将浏览器窗口最大化显示
driver.maximize_window()
12.设置浏览器宽480、高800显示:
driver.set_window_size(480, 800)
13.获取验证码图片的大小
codeEelement = driver.find_element_by_id(‘code')
imgSize = codeEelement.size
14.获取验证码元素坐标
imgLocation = imgElement.location
15.计算验证码整体坐标
rangle = (int(imgLocation['x']),int(imgLocation['y']),int(imgLocation['x'] + imgSize['width']),int(imgLocation['y']+imgSize['height']))
注意:submit和click的区别。Click方法只适用于button,而submit可以用于提交表单。
2.4 获取元素的方法之find_element_by_css_selector
-----------------通过类class获取---------------
<h1 class="important">This heading is very important.</h1>
<p class="important">This paragraph is very important.</p>
<p class="important warning">This paragraph is a very important warning.</p>
1.获取class值为important的h1标签
find_element_by_css_selector(h1.importane)
2.获取所有class值为important的标签
find_element_by_css_selector(*.importane)或者find_element_by_css_selector(.importane)
3.获取class值为important warning的标签
find_element_by_css_selector(.importane.warning)
-----------------通过类ID获取---------------
<p id="intro">This is a paragraph of introduction.</p>
find_element_by_css_selector(#"intro")
-----------------属性选择器---------------
1.<a title="W3School Home" href="http://w3school.com.cn">W3School</a>
属性中包含了title和href,find_element_by_css_selector('a[title][href]’)
2<a href="http://www.w3school.com.cn/about_us.asp">About W3School</a>
定位属性中href="http://www.w3school.com.cn/about_us.asp"的元素,
find_element_by_css_selector('a[href="http://www.w3school.com.cn/about_us.asp"]’)
3.<a href="http://www.w3school.com.cn/" title="W3School">W3School</a>
通过href和title来定位
find_element_by_css_selector("a[href='http://www.w3school.com.cn/about_us.asp'][title='W3School']”)
-----------------部分属性定位---------------
<h1>可以应用样式:</h1>
<img title="figure 1" src="/i/figure-1.gif" />
<img title="figure 2" src="/i/figure-2.gif" />
<hr />
<h1>无法应用样式:</h1>
<img src="/i/figure-1.gif" />
<img src="/i/figure-2.gif" />
定位title中包含有figure的元素:
find_element_by_css_selector("image[title~='figure']")
-----------------其他-------------------
[abc^="def"] 选择 abc 属性值以 "def" 开头的所有元素
[abc$="def"] 选择 abc 属性值以 "def" 结尾的所有元素
[abc*="def"] 选择 abc 属性值中包含子串 "def" 的所有元素
-----------------后代选择器--------------
<h1>This is a <em>important</em> heading</h1>
<p>This is a <em>important</em> paragraph.</p>
find_element_by_css_selector("h1 em")
获取元素的方法之find_element_by_xpath
这个方法是非常强大的元素查找方式,使用这种方法几乎可以定位到页面上的任意元素。在正式开始使用XPath进行定位前,我们先了解下什么是XPath。XPath是XML Path的简称,由于HTML文档本身就是一个标准的XML页面,所以我们可以使用XPath的语法来定位页面元素。
Xpath通过路径来定位控件,分为绝对路径和相对路径。绝对路径以单/号表示,相对路径则以//表示。当xpath的路径以/开头时,表示让Xpath解析引擎从文档的根节点开始解析。当xpath路径以//开头时,则表示让xpath引擎从文档的任意符合的元素节点开始进行解析。而当/出现在xpath路径中时,则表示寻找父节点的直接子节点,当//出现在xpath路径中时,表示寻找父节点下任意符合条件的子节点。弄清这个原则,就可以理解其实xpath的路径可以绝对路径和相对路径混合在一起来进行表示,想怎么玩就怎么玩。
快速获取你想要的元素xpath方式:
网页->检查->选中对应标签->右键选择copy->copy xpath
绝对路径写法(只有一种),写法如下:
引用页面上的form元素(即源码中的第3行):/html/body/form
下面是相对路径的引用写法:
查找页面根元素:
//
查找页面上所有的input元素:
//input
查找页面上第一个form元素内的直接子input元素(即只包括form元素的下一级input元素):
//form/input
查找页面上第一个form元素内的所有子input元素(只要在form元素内的input都算,不管还嵌套了多少个其他标签,使用相对路径表示,双//号):
//form//input
查找页面上第一个form元素:
//form
查找页面上id为loginForm的form元素:
//form[@id='loginForm']
查找页面上具有name属性为username的input元素:
//input[@name='username']
查找页面上id为loginForm的form元素下的第一个input元素:
//form[@id='loginForm']/input[1]
查找页面具有name属性为contiune并且type属性为button的input元素:
//input[@name='continue'][@type='button']
查找页面上id为loginForm的form元素下第4个input元素:
//form[@id='loginForm']/input[4]
以百度主页为例,搜索框的HTML示例代码如下,其xpath为//*[@id=''kw]。
获取元素的方法之find_element_by_css_selector
获取元素的方法之find_element_by_xpath
这两种方法来自于百度,方便大家更好的学习,我在这里借花献佛总结了一下放在了这里,因为我在写项目的时候记录笔记到了其他地方,具体的地址忘了,如果原创作者看到了,请留下你的地址。
三.代码展示
import re
import time
import pandas as pd
import PyTesseract
from PIL import Image
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.support.wait import webdriverwait
class CrackTouClick(object):
def __init__(self):
self.url = ""
self.search_url = ""
self.driver = webdriver.Chrome()
self.wait = webdriverwait(self.driver, 20)
self.j_username = laosiji_username
self.j_password = laosiji_password
def open(self):
self.driver.get(self.url)
self.driver.find_element_by_name("j_username").send_keys(self.j_username)
self.driver.find_element_by_name("j_password").send_keys(self.j_password)
action3 = self.driver.find_element_by_id("code")
ActionChains(self.driver).move_to_element(action3).double_click(action3).perform()
def get_window_png(self):
ele = self.driver.find_element_by_class_name('logo')
ele.screenshot('ele.png')
def verification_code(self):
self.driver.maximize_window()
self.driver.save_screenshot('./element.png') # 截取当前网页,该网页有我们需要的验证码
rangle = (1434, 961, 1598, 1017) # 写成我们需要截取的位置坐标
element = Image.open("./element.png") # 打开截图
frame4 = element.crop(rangle) # 使用Image的crop函数,从截图中再次截取我们需要的区域
frame4.save('./code.png')
code = Image.open('./code.png')
text = PyTesseract.image_to_string(code) # 使用image_to_string识别验证码
return text
def write(self):
while True:
code = self.verification_code()
# 判断验证码是否识别到且为4位数字与字母的字符串
if len(code.strip()) == 4 and code.isalnum():
self.driver.find_element_by_name("rand").send_keys(code)
break
else:
action3 = self.driver.find_element_by_id("rand_img")
ActionChains(self.driver).move_to_element(action3).double_click(action3).perform()
def login(self):
self.write()
login_action = self.driver.find_element_by_class_name("btn")
ActionChains(self.driver).move_to_element(login_action).double_click(login_action).perform()
# 判断是否有弹出框
def alert_is_present(self):
try:
alert = self.driver.switch_to.alert
print(alert)
return alert
except:
return False
def read(self):
while True:
self.login()
time.sleep(1)
# 如果有弹出框 点击确定
if self.alert_is_present():
self.driver.switch_to.alert.accept()
self.driver.switch_to.alert.accept()
time.sleep(1)
else:
break
time.sleep(1)
self.driver.get(self.search_url)
self.driver.quit()
如果觉得不错,请留下您的大拇指哦
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。