package web;
import java.io.File;
/**
* 获取打包后jar的路径信息
* @author Administrator
* 2011-01-16 13:53:12
*/
public class JarTool {
//获取jar绝对路径
public static String getJarPath(){
File file = getFile();
if(file==null)return null;
return file.getAbsolutePath();
}
//获取jar目录
public static String getJarDir() {
File file = getFile();
if(file==null)return null;
return getFile().getParent();
}
//获取jar包名
public static String getJarName() {
File file = getFile();
if(file==null)return null;
return getFile().getName();
}
private static File getFile() {
//关键是这行...
String path = JarTool.class.getProtectionDomain().getCodeSource()
.getLocation().getFile();
try{
path = https://www.sodocs.net/doc/d38093589.html,.URLDecoder.decode(path, "UTF-8");//转换处理中文及空格}catch (java.io.UnsupportedEncodingException e){
return null;
}
return new File(path);
}
}
package web;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
public class lastday {
String lsday() throws Exception{
Calendar now = Calendar.getInstance();
String nyr = now.get(Calendar.YEAR) + lastday.plus(now.get(Calendar.MONTH) + 1) + lastday.plus(now.get(Calendar.DAY_OF_MONTH));
ArrayList
BufferedReader reader1=new BufferedReader(new InputStreamReader(new FileInputStream(JarTool.getJarDir()+"/initdate.txt"),"gbk"));
String line1=null;
while ((line1=reader1.readLine())!=null) {
if(https://www.sodocs.net/doc/d38093589.html,pareTo(line1)>0){
list_h.add(line1);
}
}
//降序
Collections.reverse(list_h);//不指定排序规则时,也是按照字母的来排序的
return(list_h.get(0));
}
static String plus(int a){
String can1 =a + "";
if(can1.length()<2){
String can2="0"+can1;
return can2;
}else{
String can2=can1;
return can2;
}
}
}
package web;
import java.io.IOException;
import https://www.sodocs.net/doc/d38093589.html,.InetAddress;
import https://www.sodocs.net/doc/d38093589.html,.InetSocketAddress;
import https://www.sodocs.net/doc/d38093589.html,.Socket;
import https://www.sodocs.net/doc/d38093589.html,.SocketAddress;
import https://www.sodocs.net/doc/d38093589.html,.UnknownHostException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import https://www.sodocs.net/doc/d38093589.html,.SocketFactory;
import https://www.sodocs.net/doc/d38093589.html,.ssl.SSLContext;
import https://www.sodocs.net/doc/d38093589.html,.ssl.TrustManager;
import https://www.sodocs.net/doc/d38093589.html,.ssl.X509TrustManager;
import https://www.sodocs.net/doc/d38093589.html,mons.httpclient.ConnectTimeoutException;
import https://www.sodocs.net/doc/d38093589.html,mons.httpclient.params.HttpConnectionParams;
import https://www.sodocs.net/doc/d38093589.html,mons.httpclient.protocol.SecureProtocolSocketFactory;
/**
* MySecureProtocolSocketFactory.java.java Create on 2012-9-26下午1:15:03
*
*
* Copyright (c) 2012 by MTA.
*
* @author lmeteor
* @Email txin0814@https://www.sodocs.net/doc/d38093589.html,
* @description 自定义的socket factory 实现自动接受证书
* @version 1.0
*/
public class MySecureProtocolSocketFactory implements
SecureProtocolSocketFactory
{
private SSLContext sslcontext = null;
private SSLContext createSSLContext()
{
SSLContext sslcontext = null;
try
{
sslcontext = SSLContext.getInstance("SSL");
sslcontext.init(null, new TrustManager[]
{ new TrustAnyTrustManager() }, new java.security.SecureRandom());
}
catch (NoSuchAlgorithmException e)
{
e.printStackTrace();
}
catch (KeyManagementException e)
{
e.printStackTrace();
}
return sslcontext;
}
private SSLContext getSSLContext()
{
if (this.sslcontext == null)
{
this.sslcontext = createSSLContext();
}
return this.sslcontext;
}
public Socket createSocket(Socket socket, String host, int port,
boolean autoClose) throws IOException, UnknownHostException {
return getSSLContext().getSocketFactory().createSocket(socket, host,
port, autoClose);
}
public Socket createSocket(String host, int port) throws IOException,
UnknownHostException
{
return getSSLContext().getSocketFactory().createSocket(host, port);
}
public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort) throws IOException, UnknownHostException
{
return getSSLContext().getSocketFactory().createSocket(host, port,
clientHost, clientPort);
}
public Socket createSocket(String host, int port, InetAddress localAddress, int localPort, HttpConnectionParams params) throws IOException,
UnknownHostException, ConnectTimeoutException
{
if (params == null)
{
throw new IllegalArgumentException("Parameters may not be null");
}
int timeout = params.getConnectionTimeout();
SocketFactory socketfactory = getSSLContext().getSocketFactory();
if (timeout == 0)
{
return socketfactory.createSocket(host, port, localAddress,
localPort);
}
else
{
Socket socket = socketfactory.createSocket();
SocketAddress localaddr = new InetSocketAddress(localAddress,
localPort);
SocketAddress remoteaddr = new InetSocketAddress(host, port);
socket.bind(localaddr);
socket.connect(remoteaddr, timeout);
return socket;
}
}
// 自定义私有类
private static class TrustAnyTrustManager implements X509TrustManager
{
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException
{
}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException
{
}
public X509Certificate[] getAcceptedIssuers()
{
return new X509Certificate[]
{};
}
}
} package web;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.awt.image.ImageProducer;
import java.awt.image.MemoryImageSource;
import java.io.BufferedReader;
import process.algorithms.Elements;
import process.param.*;
import https://www.sodocs.net/doc/d38093589.html,mon;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
public class ImageIOHelper
{
private final String LANG_OPTION = "-l";
private final String EOL = System.getProperty("line.separator");
/**
* 文件位置我防止在,项目同一路径
*/
//private String tessPath = "C:\\Program Files\\Tesseract-OCR";
/**
* @param imageFile
* 传入的图像文件
* @param imageFormat
* 传入的图像格式
* @return 识别后的字符串
*/
public String recognizeText(String tessPath , File imageFile) throws Exception {
/**
* 设置输出文件的保存的文件目录
*/
File outputFile = new File(imageFile.getParentFile(), "output");
StringBuffer strB = new StringBuffer();
List
cmd.add(tessPath);
cmd.add("");
cmd.add(outputFile.getName());
cmd.add(LANG_OPTION);
// cmd.add("chi_sim");
cmd.add("eng");
ProcessBuilder pb = new ProcessBuilder();
/**
*Sets this process builder's working directory.
*/
pb.directory(imageFile.getParentFile());
cmd.set(1, imageFile.getName());
https://www.sodocs.net/doc/d38093589.html,mand(cmd);
pb.redirectErrorStream(true);
Process process = pb.start();
// tesseract.exe 1.jpg 1 -l chi_sim
// Runtime.getRuntime().exec("tesseract.exe 1.jpg 1 -l chi_sim");
/**
* the exit value of the process. By convention, 0 indicates normal
* termination.
*/
// System.out.println(cmd.toString());
int w = process.waitFor();
if (w == 0)// 0代表正常退出
{
BufferedReader in = new BufferedReader(new InputStreamReader(
new FileInputStream(outputFile.getAbsolutePath() + ".txt"),
"UTF-8"));
String str;
while ((str = in.readLine()) != null)
{
strB.append(str).append(EOL);
}
in.close();
} else
{
String msg;
switch (w)
{
case 1:
msg = "Errors accessing files. There may be spaces in your image's filename.";
break;
case 29:
msg = "Cannot recognize the image or its selected region.";
break;
case 31:
msg = "Unsupported image format.";
break;
default:
msg = "Errors occurred.";
}
throw new RuntimeException(msg);
}
new File(outputFile.getAbsolutePath() + ".txt").delete();
return strB.toString().replaceAll("\\s*", "");
}
} package web;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.ImageConsumer;
import java.awt.image.ImageProducer;
import java.awt.image.MemoryImageSource;
import java.awt.image.RenderedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import javax.imageio.ImageIO;
import process.algorithms.Elements;
import https://www.sodocs.net/doc/d38093589.html,mon;
public class ImageDemo extends Object implements ImageProducer{
//二值化图像
public static void binaryImage(String src,String Desti) throws IOException{
File file = new File(src);
//System.out.println(file);
BufferedImage image = ImageIO.read(file);
int width = image.getWidth();
int height = image.getHeight();
BufferedImage grayImage = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_BINARY);
for(int i= 0 ; i < width ; i++){
for(int j = 0 ; j < height; j++){
int rgb = image.getRGB(i, j);
grayImage.setRGB(i, j, rgb);
}
}
File newFile = new File(Desti);
ImageIO.write(grayImage, "jpg", newFile);
}
public static void grayImage2(String src,String Desti) throws IOException{
BufferedImage bufferedImage = ImageIO.read(new File(src));
int h = bufferedImage.getHeight();
int w = bufferedImage.getWidth();
BufferedImage grayImage = new BufferedImage(w, h,BufferedImage.TYPE_INT_RGB );
ColorModel cm = ColorModel.getRGBdefault();
int r, g, b, gray;
for(int i= 1 ; i < w ; i++){
for(int j = 1 ; j < h; j++){
int rgb = bufferedImage.getRGB(i, j);
r = cm.getRed(rgb);
g = cm.getGreen(rgb);
b = cm.getBlue(rgb);
gray =(int)((r + g + b) / 3);
rgb = 255 << 24|gray << 16|gray << 8|gray;
grayImage.setRGB(i, j, rgb);
}
}
File newFile = new File(Desti);
ImageIO.write(grayImage, "jpg", newFile);
}
//灰度化图像
public static void grayImage(String src,String Desti) throws IOException{
File file = new File(src);
BufferedImage image = ImageIO.read(file);
int width = image.getWidth();
int height = image.getHeight();
BufferedImage grayImage = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
for(int i= 0 ; i < width ; i++){
for(int j = 0 ; j < height; j++){
int rgb = image.getRGB(i, j);
grayImage.setRGB(i, j, rgb);
}
}
File newFile = new File(Desti);
ImageIO.write(grayImage, "jpg", newFile);
}
@Override
public void addConsumer(ImageConsumer ic) {
// TODO 自动生成的方法存根
}
@Override
public boolean isConsumer(ImageConsumer ic) {
// TODO 自动生成的方法存根
return false;
}
@Override
public void removeConsumer(ImageConsumer ic) {
// TODO 自动生成的方法存根
}
@Override
public void requestTopDownLeftRightResend(ImageConsumer ic) { // TODO 自动生成的方法存根
}
@Override
public void startProduction(ImageConsumer ic) {
// TODO 自动生成的方法存根
}
} package web;
import java.io.IOException;
public class web{
public static void main(String[] args) throws IOException{
mianban timeFrame = new mianban();;
timeFrame.setTitle("新版三板确权系统");
}
}package web;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.StringTokenizer;
import java.io.FileInputStream;
import javax.imageio.ImageIO;
import javax.swing.JOptionPane;
import https://www.sodocs.net/doc/d38093589.html,mons.httpclient.*;
import https://www.sodocs.net/doc/d38093589.html,mons.httpclient.methods.*;
import https://www.sodocs.net/doc/d38093589.html,mons.httpclient.params.HttpMethodParams;
import https://www.sodocs.net/doc/d38093589.html,mons.httpclient.protocol.Protocol;
import https://www.sodocs.net/doc/d38093589.html,mons.io.FileUtils;
import org.apache.http.message.BasicHeader;
import org.openqa.selenium.Alert;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.Keys;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.Point;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.ie.InternetExplorerDriver;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.WebDriverWait;
public class thread_a extends Thread {
FileOutputStream fos = null;
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:ms");
WebDriver driver ;
static HttpClient client = new HttpClient();
@Override
public void run() {
// TODO 自动生成的方法存根
BufferedReader reader1;
List
Date date = new Date();
SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd");
String sDateSuffix = dateformat.format(date);
folderisExist(JarTool.getJarDir()+"/log");
String lujing = JarTool.getJarDir()+"/log/download"+sDateSuffix+".log";
fileisExist(lujing);
String lujing2 = JarTool.getJarDir()+"/log/throwout"+sDateSuffix+".log";
fileisExist(lujing2);
try {
reader1 = new BufferedReader(new InputStreamReader(new FileInputStream(JarTool.getJarDir()+"/infor.txt"),"gbk"));
String line1=null;
while ((line1=reader1.readLine())!=null) {
yonghumima.add(line1);
}
} catch (Exception e) {
// TODO 自动生成的catch 块
e.printStackTrace();
}
System.out.println("begin");
//创建一个WebDriver实例
System.setProperty("webdriver.chrome.driver",
JarTool.getJarDir()+"/chromedriver.exe");
//System.setProperty("webdriver.ie.driver", JarTool.getJarDir()+"/IEDriverServer.exe");
ChromeOptions options = new ChromeOptions();
options.addArguments("--test-type", "--start-maximized");
options.addArguments("--test-type", "--ignore-certificate-errors");
DesiredCapabilities capabilities = DesiredCapabilities.chrome();
capabilities.setCapability("chrome.switches", Arrays.asList("--start-maximized"));
capabilities.setCapability(ChromeOptions.CAPABILITY, options);
capabilities.setCapability("takesScreenshot", true);
capabilities.setCapability("ACCEPT_SSL_CERTS", true);
capabilities.setJavascriptEnabled(true);
//capabilities.setCapability(InternetExplorerDriver.INTRODUCE_FLAKINESS_BY_IGNORING_SECUR ITY_DOMAINS,true);
//ieC.setCapability(InternetExplorerDriver.IGNORE_ZOOM_SETTING,true);
driver =new ChromeDriver(capabilities);
//driver=new InternetExplorerDriver(ieC);
//driver.manage().window().maximize();
try {
Thread.sleep(8000);
fos = new FileOutputStream (new File(lujing),true);
} catch (InterruptedException | FileNotFoundException e) {
// TODO 自动生成的catch 块
e.printStackTrace();
}
driver.get(yonghumima.get(0));
try {
Thread.sleep(8000);
} catch (InterruptedException e3) {
// TODO 自动生成的catch 块
e3.printStackTrace();
}
(new WebDriverWait(driver,20)).until(new ExpectedCondition
//另一种访问方法
//driver.navigate().to("https://www.sodocs.net/doc/d38093589.html,");
//找到文本框
/*yanzhengma.click();
//yanzhengma.click();
try {
sleep(1000);
} catch (InterruptedException e3) {
// TODO 自动生成的catch 块
e3.printStackTrace();
}
JavascriptExecutor j = (JavascriptExecutor)driver;
String srcRandom = (String) j.executeScript("var safecode = "
+ "document.getElementById('safecode'); "
+ "return safecode.getAttribute('src') ");
Actions action = new Actions(driver);
action.contextClick(yanzhengma).build().perform();;// 鼠标右击指定的元素
try {
sleep(1000);
} catch (InterruptedException e4) {
// TODO 自动生成的catch 块
e4.printStackTrace();
}
action.sendKeys("s");
String randomSrc=yanzhengma.getAttribute("src");
System.out.println(srcRandom+"/s/t"+randomSrc);
System.out.println(yanzhengma.getAttribute("title"));
File file = new File(JarTool.getJarDir()+"/broswer.data");
try {
// delete file if exists
file.delete();
file.createNewFile();
FileWriter fw = new FileWriter(file);
BufferedWriter bw = new BufferedWriter(fw);
for (org.openqa.selenium.Cookie ck : driver.manage().getCookies()) {
bw.write(/*ck.getName() + ";" + ck.getValue() + ";"
+ ck.getDomain() + ";" + ck.getPath() + ";"
+ ck.getExpiry() + ";" + ck.isSecure()
ck.getName() + "="
+ ck.getValue()+"; Path=/"
);
bw.newLine();
}
bw.flush();
bw.close();
fw.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("cookie write to file");
}
//指定协议名称和默认的端口号
Protocol myhttps = new Protocol("https", new MySecureProtocolSocketFactory(), 443); //注册刚才创建的https 协议对象
Protocol.registerProtocol("https", myhttps);
// 获取验证码图片
try {
doGetFile(randomSrc,JarTool.getJarDir()+"/random.jpg");
} catch (IOException e3) {
// TODO 自动生成的catch 块
e3.printStackTrace();
} */
/*PostMethod httpGet = new PostMethod(randomSrc);
try {
client.executeMethod(httpGet);
InputStream in = httpGet.getResponseBodyAsStream();
FileOutputStream out = new FileOutputStream(new File("c:\\random.jpg"));
byte[] b = new byte[1024];
int len = 0;
while((len=in.read(b))!= -1){
out.write(b,0,len);
}
in.close();
out.close();
String recognizeText = new ImageIOHelper().recognizeText(new File("c:\\random.jpg"));
System.out.print(recognizeText+"\t");
}catch (Exception e){
e.printStackTrace();
} finally{
httpGet.releaseConnection();
}
System.out.println("download, success!!");
client=null;*/
((JavascriptExecutor)driver).executeScript("$('#loginName').val('"+yonghumima.get(1)+"');"); ((JavascriptExecutor)driver).executeScript("$('#password').val('"+yonghumima.get(2)+"');");
/*WebElement element = driver.findElement(By.id("loginName"));
//输入搜索关键字
element.clear();
element.sendKeys(yonghumima.get(1));
//提交表单WebDriver会自动从表单中查找提交按钮并提交
WebElement element2 = driver.findElement(By.id("password"));
//输入搜索关键字
element2.clear();
element2.sendKeys(yonghumima.get(2));*/
boolean flagA=true;
int repeatTime=0;
while(flagA){
try {
WebElement yanzhengma = driver.findElement(By.id("safecode"));
shootWebElement(yanzhengma);
ImageDemo.binaryImage(JarTool.getJarDir()+"/random.jpg",
JarTool.getJarDir()+"/randomGray.jpg");
String recognizeText = new ImageIOHelper().recognizeText(yonghumima.get(4),new
File(JarTool.getJarDir()+"/randomGray.jpg")).replaceAll("(?i)a",
"8").replace("(?i)l","1").replace("(?i)J","1").replace("(?i)B","8").replace("(?i)!","1").replace("]","1" );
System.out.println(recognizeText);
if(recognizeText==null || recognizeText.length()==0 || recognizeText.replace(" ", "").equals("") ||recognizeText.length()!=4){
//yanzhengma.click();
((JavascriptExecutor)driver).executeScript("$('#safecode').click();");
sleep(500);
continue;
}
/*WebElement chknumber= driver.findElement(By.id("chknumber"));
chknumber.clear();
chknumber.sendKeys(recognizeText);*/
((JavascriptExecutor)driver).executeScript("$('#chknumber').val('"+recognizeText+"');");
sleep(1000);
//WebElement submit = driver.findElement(By.xpath("//input[@class='btn1']"));
//submit.click();
((JavascriptExecutor)driver).executeScript("$('.btn1').click();");
sleep(1000);
try {
sleep(3200);
Alert alert = driver.switchTo().alert(); // 把焦点切换到警告对话框
String actualText = alert.getText(); // 获取警告对话框的实际内容
if(actualText.length()<=0){
flagA=false;
}
alert.accept(); // 点击“OK”(或者“确定”)
sleep(500);
yanzhengma.click();
sleep(500);
} catch (Exception e) { // 警告对话框没有出现
e.printStackTrace();
flagA=false;
break;
}
} catch (Exception e3) {
// TODO 自动生成的catch 块
e3.printStackTrace();
try {
FileOutputStream fos3 = new FileOutputStream (new File(lujing2),true);
fos3.write((df.format(new Date())+e3.toString()+"\r\n").getBytes()) ;
fos3.flush();
fos3.close();
fos3=null;
} catch (Exception e) {
// TODO 自动生成的catch 块
e.printStackTrace();
}
repeatTime++;
if(repeatTime>10){
flagA=false;
break;
}
}
}
(new WebDriverWait(driver,20)).until(new ExpectedCondition
System.out.println("Page title is:"+ driver.getTitle());
WebElement element3 = driver.findElement(By.xpath("//a[contains(@href,'qqsj/dbyw.do')]"));
//输入搜索关键字
element3.click();;
//设置页面等待10秒超时?
try {
Thread.sleep(3000);
} catch (InterruptedException e2) {
// TODO 自动生成的catch 块
e2.printStackTrace();
}
(new WebDriverWait(driver,20)).until(new ExpectedCondition
lastday ld=new lastday();
StringBuffer riqi = null;
try {
riqi = new StringBuffer(plus_(ld.lsday()));
} catch (Exception e1) {
// TODO 自动生成的catch 块
e1.printStackTrace();
}
/*JavascriptExecutor jse=(JavascriptExecutor)driver;
jse.executeScript(" var headID = "
+ "document.getElementsByTagName(\"head\")[0];"
+ "var newScript = document.createElement('script');"
+ "newScript.type = 'text/javascript';" + "newScript.src = "
+ "'D:/hx/jquery-1.7.2.js';"
+ "headID.appendChild(newScript);"); */
//StringBuffer jquery=new StringBuffer();
//jquery=new StringBuffer(readToString(JarTool.getJarDir()+"/jquery-1.7.2.js"));
//System.out.println(jquery);
//((JavascriptExecutor)driver).executeScript(jquery.toString());
//((JavascriptExecutor)driver).executeScript(jquery.toString()+"
$('#fromDate1').val('"+riqi.toString()+"');");
((JavascriptExecutor)driver).executeScript("$('#fromDate1').val('"+riqi.toString()+"');");
((JavascriptExecutor)driver).executeScript("$('#toDate1').val('"+riqi.toString()+"');");
/*Actions action = new Actions(driver);
WebElement fromDate1 =driver.findElement(By.id("fromDate1"));
fromDate1.click();
for(int i=0;i fromDate1.sendKeys(String.valueOf(riqi.toString().charAt(i))); try { sleep(1000); } catch (InterruptedException e) { // TODO 自动生成的catch 块 e.printStackTrace(); } } //action.click(fromDate1).perform();// 鼠标右击指定的元素 try { sleep(1000); } catch (InterruptedException e4) { // TODO 自动生成的catch 块 e4.printStackTrace(); } //action.sendKeys(riqi.toString()); WebElement toDate1 =driver.findElement(By.id("toDate1")); toDate1.click(); for(int i=0;i toDate1.sendKeys(String.valueOf(riqi.toString().charAt(i))); try { sleep(1000); } catch (InterruptedException e) { // TODO 自动生成的catch 块 e.printStackTrace(); } } //action.click(toDate1).perform();// 鼠标右击指定的元素 try { sleep(1000); } catch (InterruptedException e4) { // TODO 自动生成的catch 块 e4.printStackTrace(); } //action.sendKeys(riqi.toString()); System.out.println(riqi.toString()); try { sleep(1000); } catch (InterruptedException e2) { // TODO 自动生成的catch 块 e2.printStackTrace(); }*/ //WebElement cx_ys =driver.findElement(By.xpath("//input[@class='btn1 btn2']")); //cx_ys.click(); ((JavascriptExecutor)driver).executeScript("submitForm2();"); try { Thread.sleep(3000); } catch (Exception e) { // TODO 自动生成的catch 块 e.printStackTrace(); } /*while(true){ int biaozhi = 0; Set Iterator String preWindowString = driver.getWindowHandle(); while(it.hasNext()){ String cruWindowString = it.next(); driver.switchTo().window(cruWindowString); biaozhi=1; } if(biaozhi >0){ break; } } try { Thread.sleep(7000); } catch (InterruptedException e1) { // TODO 自动生成的catch 块 e1.printStackTrace(); }*/ String url = new String("Current url =" + driver.getCurrentUrl()); System.out.println(url); try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO 自动生成的catch 块 e.printStackTrace(); } //WebElement tet1 = driver.findElement(By.className("content")) ; //String href = tet1.getAttribute("href"); //System.out.println(href); //List download(driver); while(isElementExsit(driver,By.linkText("下一页"))){ download(driver); } try { fos.close(); } catch (IOException e) { // TODO 自动生成的catch 块 e.printStackTrace(); } Object[] options1 = { "OK", "CANCEL" }; JOptionPane.showOptionDialog(null,"下载已完成", "提示", JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE, null, options1, options1[0]); //关闭浏览器 //driver.quit(); } /** * 发送请求报文,得到响应报文 * @param url * 登录请求URL * @param pList * 是否包含请求参数 * @return * @throws UnsupportedEncodingException */ public static String doRequestToString(String url,List { //获得postMethod对象 PostMethod pmethod = getPostMethod(url); pmethod.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET, "utf-8"); //判断是否包含参数 if(null != pList && pList.size() > 0) { pmethod.setRequestBody(pList.toArray(new NameValuePair[pList.size()])); } String value = ""; try { client.executeMethod(pmethod); value = pmethod.getResponseBodyAsString(); [原]自动生成验证码图片的工具类,收藏起来备用。用法:直接调用其静态方法即可。 Map Selenium安装以及简单的自动化测 试用例 中科软科技股份有限公司 2013年4月 V1.0.0 关于本文档 说明:类型-创建(C)、修改(U)、删除(D)、增加(A); 目录 目录 (3) 1.Selenium介绍 (3) 2.相关组件 (3) 3.启动seleniumRC (4) 4.简单测试用例 (4) 4.1在火狐浏览器上下载并打开selenium IDE (5) 4.2录制测试用例 (6) 4.2.1 录制 (6) 4.2.2 检查 (6) 4.2.3 语言转换 (6) 4.2.4 准备Eclipse环境 (7) 4.2.5 运行 (9) 1.Selenium介绍 Selenium是一个用于Web应用程序测试的工具。Selenium测试直接运行在浏览器中,就像真正的用户在操作一样。支持的浏览器包括IE、Mozilla Firefox、Mozilla Suite等。 功能: ●测试直接在浏览器中运行,就像真实用户所做的一样,从终端用户的角度测试应用程序。 ●使浏览器兼容性测试自动化成为可能。 ●使用简单,可生成多种语言的用例脚本。 2.相关组件 ●Selenium IDE:一个Firefox插件,可以录制用户的基本操作,生成测试用例。随后可以 运行这些测试用例在浏览器里回放,可将测试用例转换为其他语言的自动化脚本。 ●Selenium Remote Control (RC) :支持多种平台(Windows,Linux,Solaris)和多种浏览器(IE, Firefox,Opera,Safari),可以用多种语言(Java,Ruby,Python,Perl,PHP,C#)编写测试用例。 ●Selenium Grid :允许Selenium-RC 针对规模庞大的测试案例集或者需要在不同环境中 运行的测试案例集进行扩展。 3.启动seleniumRC 官网下载:https://www.sodocs.net/doc/d38093589.html,/download/。打开cmd,进入RC存放文件夹。在命令行输入:java –jar selenium-server.jar 。 启动成功。 注意在启动RC前,确认电脑上安装JDK版本高于1.5 4.简单测试用例 以OA系统登录为例: 新建一个WaterMark.ASHX文件,将如下代码Copy进去 <%@ WebHandler Language="C#" Class="WaterMark" %> using System; using System.Web; using System.Drawing; using System.Drawing.Drawing2D; using System.Web.SessionState; public class WaterMark : IHttpHandler, IRequiresSessionState // 要使用session必须实现该接口,记得要导入System.Web.SessionState命名空间 { public void ProcessRequest(HttpContext context) { string checkCode = GenCode(5); // 产生5位随机字符 context.Session["Code"] = checkCode; //将字符串保存到Session中,以便需要时进行验证 System.Drawing.Bitmap image = new System.Drawing.Bitmap(70, 22); Graphics g = Graphics.FromImage(image); try { //生成随机生成器 Random random = new Random(); //清空图片背景色 g.Clear(Color.White); // 画图片的背景噪音线 int i; for (i = 0; i < 25; i++) { int x1 = random.Next(image.Width); int x2 = random.Next(image.Width); int y1 = random.Next(image.Height); int y2 = random.Next(image.Height); g.DrawLine(new Pen(Color.Silver), x1, y1, x2, y2); } Font font = new System.Drawing.Font("Arial", 12, (System.Drawing.FontStyle.Bold)); System.Drawing.Drawing2D.LinearGradientBrush brush = new System.Drawing.Drawing2D.LinearGradientBrush(new Rectangle(0, 0, image.Width, image.Height), Color.Blue, Color.DarkRed, 1.2F, true); g.DrawString(checkCode, font, brush, 2, 2); package com.env.util; import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.image.BufferedImage; import java.util.Random; import javax.imageio.ImageIO; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; public class RandomValidateCode { public static final String RANDOMCODEKEY = "RANDOMVALIDATECODEKEY";//放到session 中的key private Random random = new Random(); private String randString = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";//随机产生的字符串 private int width = 80;//图片宽 private int height = 26;//图片高 private int lineSize = 40;//干扰线数量 private int stringNum = 4;//随机产生字符数量 /* * 获得字体 */ private Font getFont(){ return new Font("Fixedsys",Font.CENTER_BASELINE,18); } /* * 获得颜色 */ private Color getRandColor(int fc,int bc){ if(fc > 255) fc = 255; if(bc > 255) bc = 255; int r = fc + random.nextInt(bc-fc-16); int g = fc + random.nextInt(bc-fc-14); int b = fc + random.nextInt(bc-fc-18); return new Color(r,g,b); } 验证码技术的实现按如下步骤: 1、设计一个验证码生成类RandomImageGenerator.java import java.awt.*; import java.awt.image.*; import java.io.*; import javax.imageio.ImageIO; public class RandomImageGenerator { final static int LENGTH=4; static Color colors[]={Color.red,Color.black,Color.blue,Color.pink,Color.cyan}; public static String random() {//创建一个4位的验证码字符串 String str="1234567890ABCDEFGHIJKLMNOPORSTUVWXYZabcefghijklmnopqrstuvwxyz",r and=""; java.util.Random random=new java.util.Random(); for(int i=0;i 开源自动化测试工具selenium的使用 (玉米猫) 一Selenium概述: Selenium是现在使用最为广泛的一款开源自动化测试工具,也是非商业支持的稳定性易用性最好的一款自动化测试工具。和由HP提供强大商业支持的QTP相比,selenium不仅在软件投资上有比较大的优势,在针对web测试的稳定性上也有绝对的优势。以下介绍的内容会通过和QTP在各方面的比较中进行,并针对简单的测试样例,对基本的使用进行简单说明。 二Selenium的组成: 和QTP等其他工具类似,selenium也有几个组件组成,同时在使用的时候还需要一些开发的IDE平台进行支持。 对于初步的简单使用,需要先掌握seleniumIDE,RC的基本使用,以及对象识别方式Xpathe的基本知识。 1)seleniumIDE: selenium和QTP类似,同样需要先进行一定的脚本录制工作,而它默认支持的录制浏览器是firefox,IDE就充当了一个脚本记录的工作,它的表现形式为firefox的一款插件。 它可以记录准备过程中,用户在firefox上的制定网址下所做的一切操作,并转化为自己需要的一种开发语言,包括:java、perl、PHP、C#、Ruby等等。 2)RC: RC是selenium的特色组件,它通过从底层向不同的浏览器发出动作指令,达到用脚本控制web的效果,和QTP的activeX驱动的模式有着本质的不同,只要浏览器的动作指令原理不发生本质性的变化,就可以利用selenium达到自动化测试的效果,不会由于出现新的浏览器,还要等待HP重新开发相应的activeX控件。 3)其他: 由于selenium的非商业支持,所以很多类似于QTP中的组件都使用了firefox插件的办法得到了补充。 Firebug:帮助用户对页面上的对象进行识别,它可以准确捕捉到任何一个可见元素和不可见元素,同时支持由对象找代码和由代码找对象的使用方法,非常类似于QTP的spy 和控件高亮显示功能。 Xpather:帮助用户利用xpath标记对象的位置信息,根据xpath的实现方式,可以将页面上的每一个控件元素做唯一性标识,非常类似于QTP的对象库,区别在于Xpath只记录元素的位置样式属性,不会记录截图。 三Selenium的简单使用: 1)测试的准备工作: 这里所说的准备工作,只一个自动化测试的准备,预计基本的测试用例等内容已经准备完成。 假如被测系统为ADCPX: 首先:用firefox打开被测系统的首页,启动IDE插件。 需要注意的是,IDE的baseUrl一定是当前要测试的web首页,默认生成的第一个testcase 的名称可以通过属性进行更改。一个IDE中可以录制或生成多个testcase。 生成随机的5位登录验证码 import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.image.BufferedImage; import java.io.IOException; import java.io.OutputStream; import java.util.Random; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; static String code=""; publicclass checkService { publicvoid checkCode(HttpServletRequest req,HttpServletResponse resp) throws ServletException,IOException{ //绘制画布 BufferedImage bf=new BufferedImage(80,30,BufferedImage.TYPE_INT_BGR); //获得画笔 Graphics g=bf.getGraphics(); //给画笔设置颜色 g.setColor(new Color(255,255,255)); //填充背景色 g.fillRect(0, 0, 80, 30); //随机获得前景色 Random r=new Random(); g.setColor(new Color(r.nextInt(255),r.nextInt(255),r.nextInt(255))); //设置字体 Font f=new Font("",Font.BOLD,22); //获得字体 g.setFont(f); //以当前颜色和字体绘制干扰线 checkService.code=checkService.getstr(); g.drawString(checkService.code,10,25); for(int i=0;i<10;i++){ g.drawLine(r.nextInt(80), r.nextInt(30), r.nextInt(80), r.nextInt(30)); selenium 自动化测试的框架 自动化测试的框架 软件自动化测试 style="font-family: 宋体 ;mso-ascii-font-family:Calibri; mso-ascii-theme-font:minor-latin;mso-fareast-font-family: 宋体 ;mso-fareast-theme-font: minor-fareast;mso-hansi-font-family:Calibri;mso-hansi-the me-font:minor-latin"> 个阶段。 selenium 自动化测试的框架 自动化测试的框架 软件自动化测试的框架和工具的发展大致将经历以下4个阶段。 使用分层的Selenium框架进行复杂Web应用的自动测试 软件工程师,IBM 王晨,是IBM中国系统与科技研发中心的软件工程师。从事IBM Systems Director开发测试工作。对自动测试、Web2.0和Open Source等相关领域感兴趣。 简介:在复杂Web应用程序的自动测试中,会产生大量冗余的测试脚本,同时,由于测试场景复杂多变,测试用例的灵活管理与调用是不可回避的需求。在本文中,作者通过将开源Web自动测试框架Selenium从逻辑上进行了分层,从而提高了测试脚本的复用性与可维护性。通过本文的实例讲解,您将了解该项技巧的原理与关键实现。 发布日期:2010年2月22日 级别:中级 Selenium概述 Selenium是一种Web应用的自动测试工具,通过模拟用户对Web页面的各种操作,可以精确重现软件测试人员编写的Test Cases步骤。Selenium包含三个工具:Selenium-IDE,Selenium-RC以及Selenium-Core。其中,Selenium-Core是驱动Selenium工作的核心部分,作为一个用JavaScript编写的测试引擎,它可以操作Web页面上的各种元素,诸如:点击按钮、输入文本框,以及断言Web页面上存在某些文本与Web元素等。 Selenium-IDE是一个Firefox插件,能够录制回放用户在Firefox中的行为,并把所记录的Selenese(Selenium Commands)转化为 Java/C#/Python/Ruby等语言,在Selenium-RC中修改复用。对于较为复杂的Test Cases,Selenium-IDE的功能有限,往往用它录制大致的步骤,再转化为测试人员熟悉的编程语言,在此基础上完善,形成更为强大且灵活的Selenium-RC Test Cases。 Selenium-RC(Selenium Remote Control)在Web浏览器与需要测试的Web 应用间架设代理服务器(Selenium Server),使得JavaScript引擎与被测Web应用同源,绕开同源策略的限制(Same Origin Policy),进而取得对Web页面进行各种操作的权限。 开发环境配置 Selenium RC支持多种编程语言驱动客户端浏览器,这里主要介绍使用Python在Windows下驱动Selenium RC。Python是一种面向对象的解释性的计算机程序设计语言。 1、准备工作: 下载Java:目前是1.6 update7,下载地址:https://www.sodocs.net/doc/d38093589.html,/zh_CN/ 下载Python:目前稳定版本为2.5.2,下载地址: https://www.sodocs.net/doc/d38093589.html,/download/,Python的相关信息参见: https://www.sodocs.net/doc/d38093589.html,/ 下载Selenium RC:目前是1.0 Beta1版本,下载地址: https://www.sodocs.net/doc/d38093589.html,/download.html,Selenium RC相关信息参见:https://www.sodocs.net/doc/d38093589.html,/ 2、开始运行 首先启动Selenium Server,把下载的Selenium RC解压后,会有一个selenium-server-1.0-beta-1的文件夹,就是Selenium Server的存放目录,通过命令行Java -jar selenium-server.jar来启动Selenium Server端的服务, 以在Google上搜索Hello World为例,Python的脚本如下: "*firefox"是指支持的浏览器或是通过Selenium RC调用的浏览器,Selenium 支持以下的浏览器类型, Supported browsers include: *iexplore *konqueror *firefox package login.validate; import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.util.Random; import javax.imageio.ImageIO; import javax.imageio.stream.ImageOutputStream; public class RandomNum { private ByteArrayInputStream image;//图像 private String str;//验证码 /* public static final char[] code = {'a','b','c','d','e','f','g', 'h','i','j','k','l','m','n', 'o','p','q','r','s','t', 'u','v','w','x','y','z', 'A','B','C','D','E','F','G', 'H','I','J','K','L','M','N', 'O','P','Q','R','S','T', 'U','V','W','X','Y','Z', '0','1','2','3','4', '5','6','7','8','9'}; */ private RandomNum(){ init();//初始化属性 } /* * 取得RandomNumUtil实例 */ public static RandomNum Instance(){ return new RandomNum(); } /* * 取得验证码图片 */ public ByteArrayInputStream getImage(){ return this.image; } /* * 取得图片的验证码 */ public String getString(){ return this.str; Selenium自动化测试用例设计注意事项 UI元素映射 元素验证 等待加载 日志记录 结果收集 Selenium自动化测试用例设计注意事项(一) 自动化测试设计简介 我们在本章提供的信息,对自动化测试领域的新人和经验丰富的老手都是有用的。本篇中描述最常见的自动化测试类型,还描述了可以增强您的自动化测试套件可维护性和扩展性的“设计模式”。还没有使用这些技术的、有经验的自动化测试工程师会对这些技术更加感兴趣。 测试类型 您应该测试应用程序中的哪些部分这取决于您的项目的各种影响因素:用户的期望,时间期限,项目经理设置的优先事项等等。但是,一旦项目边界定义完成,作为测试工程师,你必须做出要测试什么的决定。 为了对Web应用的测试类型进行分类,我们在这里创建了一些术语。这些术语并不意味着标准,但是这些概念对web应用测试来说非常典型。 ● 测试静态内容 静态内容测试是最简单的测试,用于验证静态的、不变化的UI元素的存在性。例如: → 每个页面都有其预期的页面标题这可以用来验证链接指向一个预期的页面。 → 应用程序的主页包含一个应该在页面顶部的图片吗 → 网站的每一个页面是否都包含一个页脚区域来显示公司的联系方式,隐私政策,以及商标信息→ 每一页的标题文本都使用的 TAS Design Guide Author: peng gong Table of Contents 1 TAS模型介绍 (2) 1.1 Jenkins (2) 1.2 Python (3) 1.3 Selenium (3) 1.4 脚本代码管理:svn (3) 1.5 TAS运行环境:Linux+window (3) 2 TAS Frameworks (3) 2.1 测试管理:Jenkins (4) 2.2 脚本语言:Python (4) 2.2.1 Python2.7 (4) 2.2.2 Nose (4) 2.2.3 proboscis (5) 2.3 Web驱动:selenium (5) 3 TAS部署和要求 (5) 3.1 TAS环境要求 (5) 3.2 Jenkins和selenium安装 (5) 4 TAS运行和测试 (6) 4.1 测试运行 (6) 4.2 开发调试 (6) 4.3 开发调试工具 (6) 5 Code Frameworks (7) 5.1 Code结构 (7) 5.2 team模块举例 (7) 5.3 编码规范: (7) 5.4 A Simplest Example Script (8) 1.2 Python Python最大优点就是比其他语言更简单易学。同时Python自带的和大量开源的测试框架使得TAS系统架构更简单和便捷。TAS Frameworks使用了python自带的unittest拓展的开源nose和proboscis模块。 1.3 Selenium Selenium selenium是跨平台的web测试工具包。TAS选择selenium的原因在于: Selenium具有跨平台,跨浏览器的特点。 Selenium支持多种编程语言和测试框架。 Selenium工具包 TAS中使用了selenium RC驱动Web,开发工程师在开发script过程中可以使用selenium IDE和firebug等工具。 selenium运行 TAS中selenium有两种工作方式:服务器端和QA客户端。selenium运行在服务器端Jenkins和Selenium 交互,后者启动浏览器完成测试,返回结果给Jenkins。selenium运行在QA客户端的好处在于可以并行运行多个TAS测试任务。 1.4 脚本代码管理:svn TAS系统的脚本代码使用svn进行管理。测试中,Jenkins上配置svn的路径,Jenkins job开始构建时从svn中checkout最新版本进行测试。 1.5 TAS运行环境:Linux+window TAS系统的Jenkins安装在Server端的Linux/Ubuntu中,同时selenium也可以部署在Server上。测试工程师的PC上部署的selenium一般用于debug调试使用。 2 TAS Frameworks TAS框架主要由4部分组成,测试集成管理的Jenkins,Python脚本以及python 包,Selenium驱动模块和版本管理svn。详细模块拓扑图如下: Selenium自动化测试 一、目标和意义 a)掌握基本的自动化测试基础(过程,流程,定位方法) b)掌握初级脚本编写(参数化、打开文件,操作方法等) c)掌握单元测试套件的编写,自动化测试框架的设计和应用 二、课程安排 第一天 a)Web自动化测试的基础 b)Web自动化测试环境搭建 c)Python语言学习(上) 第二天 d)Python语言学习(下) e)Selenium-IDE工具的使用 f)Selenium初级脚本编写(定位;操作) 第三天 g)Selenium高级脚本编写(参数化, css/xpath定位) h)打开/写入文件、读取excel i)Pyunit单元测试框架介绍 第四天 j)测试套件的使用 k)测试报告的生成 l)测试框架的设计和应用 三、什么是自动化 由机器或工具代替手工执行软件测试,单击被测软件的界面,执行一系列操作并进行验证的过程 分类 功能自动化----QTP、Selenium 性能自动化----LR、Jmeter 白盒自动化----junit等 四、自动化测试的原理 a)手工测试 1、打开浏览器,访问iwebshop首页 2、点击登录按钮,进入登录页面 3、输入用户名,密码 4、点击登录按钮 5、系统提示登录成功,进入个人页面 b)自动化测试 1、调用webdriver函数打开浏览器,使用方法(get)访问目标网址 2、通过页面元素的属性定位登录按钮,使用方法(click)操作目标对象 3、通过页面元素的属性定位用户名/密码,使用方法(sendkeys)操作目标 对象 4、通过页面元素的属性定位登录按钮,使用方法(click)操作目标对象 5、定位实际结果并获取,比对实际结果与预期结果---断言 五、开展自动化测试的条件 1、手工测试基本通过 2、需求比较稳定,不易变更 3、自动化测试脚本可复用 4、项目周期足够长 5、手工测试无法完成时,需要投入大量的人力/物力 六、QTP与selenium工具的区别 七、Python—selenium自动化测试环境搭建 Os:xp、server、win7 1、安装Python--- python-2.7.6.msi,一路下一步,默认安装在C盘,配置path环境变量,追加Python安装目录C:\python27,验证:win+r打开运行,输入cmd进入dos环境,输入Python回车 查看是否进入Python环境。 2、安装setuptools-0.6c11.win32-py2.7.exe,一路下一步,默认安装。 3、安装selenium--- selenium-2.40.0.tar.gz, A、解压该压缩包,移动到C:\Python27\Lib\site-packages目录下,win+R 打开运行,输入cmd进入dos环境, B、使用cd命令进入C:\Python27\Lib\site-packages\selenium-2.40.0,输入dir查看setup.py文件 C、输入安装命令:Python setup.py install 回车自动生成验证码图片的工具类,收藏起来备用。
Selenium安装以及简单的自动化测试用例
c#生成验证码的方法
登录校验,生成随机图形验证码
验证码图片不能正常显示的一个原因
开源自动化测试工具selenium的使用
生成随机的5位登录验证码
selenium自动化测试的框架
selenium 自动化测试的框架
使用SELENIUM进行复杂的WEB自动化测试
使用Python进行Selenium自动化测试
随机生成验证码
Selenium自动化测试用例设计注意事项
标签吗每个页面有正确的头部文本内吗 您可能需要或也可能不需要对页面内容进行自动化测试。如果您的网页内容是不易受到影响手工对内容进行测试就足够了。如果,例如您的应用文件的位置被移动,内容测试就非常有价值。 ● 测试链接 Web站点的一个常见错误为的失效的链接或链接指向无效页。链接测试涉及点各个链接和验证预期的页面是否存在。如果静态链接不经常更改,手动测试就足够。但是,如果你的网页设计师经常改变链接,或者文件不时被重定向,链接测试应该实现自动化。 ●功能测试 在您的应用程序中,需要测试应用的特定功能,需要一些类型的用户输入,并返回某种类型的结果。通常一个功能测试将涉及多个页面,一个基于表单的输入页面,其中包含若干输入字段、提交“和”取消“操作,以及一个或多个响应页面。用户输入可以通过文本输入域,复选框,下拉列表,或任何其他的浏览器所支持的输入。 功能测试通常是需要自动化测试的最复杂的测试类型,但也通常是最重要的。典型的测试是登录,注册网站账户,用户帐户操作,帐户设置变化,复杂的数据检索操作等等。功能测试通常对应着您的应用程序的描述应用特性或设计的使用场景。 ● 测试动态元素 通常一个网页元素都有一个唯一的标识符,用于唯一地定位该网页中的元素。通常情况下,唯一标识符用HTML标记的’id’属性或’name’属性来实现。这些标识符可以是一个静态的,即不变的、字符串
Selenium自动化测试框架设计指南
Selenium自动化测试