注册网站卖东西,绵阳网站建设价格,北京h5网站开发公司,如何给网站做app最近需要批量操作某个古老的后台#xff0c;但是流程非常复杂#xff0c;通过 php-webdriver/webdriver 写了个基于队列的方式实现工作流#xff1b;
可以帮你实现web ui 测试#xff0c; 自动登录站点#xff0c;自动识别验证码#xff08;不复杂的那种#xff09;但是流程非常复杂通过 php-webdriver/webdriver 写了个基于队列的方式实现工作流
可以帮你实现web ui 测试 自动登录站点自动识别验证码不复杂的那种自动操作等
首先使用docker-compose搭建selenium测试平台其中ocr是用于对验证码的识别
version: 3.3
networks:net:driver: bridge
services:chrome:image: selenium/standalone-chrome:4.15.0-20231129container_name: chromehostname: ypprivileged: trueshm_size: 4gports:- 4443:4444- 5901:5900- 7902:7900volumes:- ./public/uploads/goods:/home/seluser/Downloadsnetworks:- netedge:image: selenium/standalone-edge:4.15.0-20231129container_name: edgehostname: ypprivileged: trueshm_size: 4gports:- 4441:4444- 5902:5900- 7901:7900volumes:- ./public/uploads/goods:/home/seluser/Downloadsnetworks:- netocrapi:container_name: ocrapibuild:context: ./dockerdockerfile: Dockerfilevolumes:- ./docker/ocr.py:/ocrapi/ocr.pyports:- 5000:5000networks:- netdockerfile
FROM python:3.11 # 类似ADD将我们文件拷贝到镜像中
WORKDIR /app
# 镜像的工作目录
RUN ls \ pip install -i https://mirrors.aliyun.com/pypi/simple/ ddddocr1.4.11 \ pip install -i https://mirrors.aliyun.com/pypi/simple/ Flask3.0.2
# RUN pip install -r ./requirements.txt
# 镜像构建的时候需要运行的命令
EXPOSE 5000
# 暴露端口配置 实际取决于docker run 命令的选择
ENTRYPOINT [python]
# 基础镜像构建镜像的开始这里是python版本
COPY . /app
# 指定这个容器启动的时候要运行的命令可以追加命令
CMD [/app/ocr.py]
# #指定这个容器启动的时候要运行的命令只有最后一个会生效可被替代ocr.py
from flask import Flask, request, jsonify
import ddddocrapp Flask(__name__)# 初始化OCR
ocr ddddocr.DdddOcr()app.route(/ocr, methods[POST])
def ocr_endpoint():try:# 获取上传的图片数据img_data request.files[image].read()# 调用OCR识别图片result ocr.classification(img_data)# 返回识别结果return jsonify({text: result})except Exception as e:# 发生错误时返回错误信息return jsonify({error: str(e)}), 400if __name__ __main__:app.run(host0.0.0.0,debugTrue)
以上是环境搭建ocr按目录载入即可docker自动构建部署
ocr是基于容器实现的通过接口的方式调用也可以独立使用
接下来就是核心工具trait ,需要创建一个自定义命令然后use这个trait
?phpnamespace app\yperp\common;use Facebook\WebDriver\Interactions\WebDriverActions;
use think\facade\Cache;
use GuzzleHttp\Client;
use Facebook\WebDriver\Remote\DesiredCapabilities;
use Facebook\WebDriver\Remote\RemoteWebDriver;
use Facebook\WebDriver\WebDriverBy;
use Facebook\WebDriver\WebDriverSelect;
use InvalidArgumentException;
use RuntimeException;trait MyWebDriver
{use Docker;protected $output;protected $input;protected $driver null;protected $windows [];protected $host http://localhost:4443/wd/hub;protected $cookies [];private $sessionIdKey webdriver_session_id;protected function WebDriver(){$sessionId Cache::get($this-sessionIdKey);if ($sessionId) {try {$this-output-writeln(使用$sessionId创建会话 . $sessionId);$this-driver RemoteWebDriver::createBySessionID($sessionId, $this-host, 300, 300, true, $this-config());if ($this-driver-getCurrentURL() about:blank) {Cache::set($this-sessionIdKey, false);$this-driver-quit();$this-driver $this-createNewWebDriver();}$this-driver-manage()-window()-maximize();$this-output-writeln(创建会话完成);} catch (\Exception $e) {Cache::set($this-sessionIdKey, false);$this-driver $this-createNewWebDriver();}} else {$this-driver $this-createNewWebDriver();}return $this-driver;}private function createNewWebDriver(){$this-output-writeln(创建会话);Cache::set($this-sessionIdKey, false);$driver RemoteWebDriver::create($this-host, $this-config());$this-driver-manage()-window()-maximize();$sessionId $driver-getSessionID();$this-output-writeln($sessionId: . $sessionId);Cache::set($this-sessionIdKey, $sessionId);$this-output-writeln(创建会话完成);return $driver;}function config(){$capabilities DesiredCapabilities::chrome();$capabilities-setCapability(goog:chromeOptions,[prefs [download.default_directory /home/seluser/Downloads,download.prompt_for_download false,download.directory_upgrade true,safebrowsing.enabled true,],]);return $capabilities;}protected function setCookies(){if ($this-cookies ! []) {$this-output-writeln(cookie登录);foreach ($this-cookies as $cookie) {$this-driver-manage()-addCookie($cookie);}}}function ask($tps 请输入){if (ob_get_level() 0) {ob_flush();}fwrite(STDOUT, $tps);return trim(fgets(STDIN));}private function ocrCaptchaOnline($imgPath){$this-output-writeln(验证码接口);$Http new Client();$res $Http-post(http://api.waizaowang.com/ai/captcha, [headers [Content-Type application/x-www-form-urlencoded,],form_params [models 1003,token 6554470371eba99bdaa27b265adf3fc4,image base64_encode(file_get_contents($imgPath)),],])-getBody()-getContents();$this-output-writeln(验证码接口结果 . $res);$res json_decode($res, true);if ($res[code] 200 $res[data][0][succsss]) {return $res[data][0][result];} else {return false;}}protected function docker_restart(){Cache::set($SessionId, false);Cache::set($getWindowHandle, false);$this-output-writeln(重启容器);static::docer_containers_restart(chrome);$isRun false;while ($isRun) {try {static::docer_check_run(chrome);$isRun true;} catch (\Throwable $th) {//throw $th;}sleep(1);}sleep(5);$this-output-writeln(启动成功);}protected function click_check_elem(WebDriverBy $select, $wait 3){$this-output-writeln(操作元素 . $select-getValue());$Elemensts $this-driver-findElements($select);if (!empty($Elemensts)) {$imgElement $this-driver-findElement($select);$imgElement-click();$this-output-writeln(完成操作元素 . $select-getValue());sleep($wait);} else {$this-output-writeln(操作失败 . $select-getValue());}}protected function toRun(){$number 0;Cache::set(OptionsStatus, 1);while (Cache::get(OptionsStatus) 1) {if ($this-driver null) {$this-driver $this-WebDriver();}sleep(1);if ($number 120) {$this-driver-findElement(WebDriverBy::xpath(html));$number 0;} else {$number;}try {$options Redis::lpop();$this-runSetp($options);} catch (\Throwable $th) {$this-output-writeln(操作错误 . $th-getMessage());$this-output-writeln(操作错误 . $th-getTraceAsString());if (isset($options[error]) in_array($options[error], [])) {$type $options[error];$this-$type();}}}}function ocrApi($imgPath, $apiUrl http://127.0.0.1:5000/ocr){// 检查文件是否存在if (!file_exists($imgPath)) {throw new InvalidArgumentException(File not found at path: {$imgPath});}// 初始化cURL会话$ch curl_init();// 设置cURL选项curl_setopt_array($ch, [CURLOPT_URL $apiUrl,CURLOPT_POST true,CURLOPT_RETURNTRANSFER true,CURLOPT_POSTFIELDS [image new \CurlFile($imgPath)],CURLOPT_HTTPHEADER [Content-Type: multipart/form-data],]);// 执行cURL请求$response curl_exec($ch);// 检查cURL错误if (curl_errno($ch)) {throw new RuntimeException(cURL error: . curl_error($ch));}// 获取HTTP响应状态码$httpCode curl_getinfo($ch, CURLINFO_HTTP_CODE);// 关闭cURL会话curl_close($ch);// 根据HTTP响应状态码处理结果if ($httpCode ! 200) {throw new RuntimeException(Failed to upload image. Server responded with status code: . $httpCode);}// 返回响应内容return json_decode($response, true);}function open($do){$this-driver-get($do[url]);}/*** 执行函数*/function func($do){$this-output-writeln(执行函数 . $do[func]);$func $do[func];$func($this, $do);}/*** 执行类方法*/function this($do){$this-output-writeln(执行当前类方法 . $do[this_method]);$method $do[this_method];$this-$method($this, $do);}function class($do){call_user_func_array([$do[className], $do[func]], $do[args]);}function window($do){$option $do[option];$this-$option($do[value]);}function closeWindow(){// 获取所有窗口的句柄$windowHandles $this-driver-getWindowHandles();// 关闭新窗口$this-driver-switchTo()-window($windowHandles[count($windowHandles) - 1])-close();$this-output-writeln(关闭窗口);// 返回到原来的窗口$this-driver-switchTo()-window($windowHandles[0]);}function toWindow($windowId){// 获取所有窗口句柄$windowHandles $this-driver-getWindowHandles();if (isset($windowHandles[$windowId])) {$this-driver-switchTo()-window($windowHandles[$windowId]);$this-output-writeln(窗口切换成功 . $windowId);} else {$this-output-writeln(窗口不存在 . $windowId);}}function getSelect($do){$keys array_keys($do);$by null;if (in_array(id, $keys)) {$by id;} else if (in_array(name, $keys)) {$by name;} else if (in_array(className, $keys)) {$by className;} else if (in_array(cssSelector, $keys)) {$by cssSelector;} else if (in_array(linkText, $keys)) {$by linkText;} else if (in_array(partialLinkText, $keys)) {$by partialLinkText;} else if (in_array(tagName, $keys)) {$by tagName;} else if (in_array(xpath, $keys)) {$by xpath;}return WebDriverBy::$by($do[$by]);;}function findElement($do){if (is_string($do[option])) {$this-options($do, $do[option]);} else {foreach ($do[option] as $option $value) {$this-options($do, $option, $value);}}}function options($do, $option, $value null){$select $this-getSelect($do);$element $this-driver-findElement($select);switch ($option) {case sendKeys:$this-output-writeln(sendKeys . $value);$element-sendKeys($value);break;case uploadFiles:if (is_string($option)) {$value[] $option;}if (is_array($value)) {// 将文件路径设置为 input 元素的值// 上传多张图片foreach ($value as $imagePath) {// $element-setFileDetector(new LocalFileDetector());$this-output-writeln(sendKeys . $imagePath);try {$element-sendKeys($imagePath);} catch (\Throwable $th) {//throw $th;}sleep(1);}}break;case select:// 使用 WebDriverSelect 类来操作下拉框$select new WebDriverSelect($element);switch ($do[type]) {case text:$select-selectByVisibleText($do[value]);break;case value:$select-selectByValue($do[value]);break;case index:$select-selectByIndex($do[value]);break;default:$select-selectByVisibleText($do[value]);}break;case click:$element-click();break;case doubleClick:// 创建一个Actions实例$actions new WebDriverActions($this-driver);// 执行双击操作$actions-doubleClick($element)-perform();break;case Keys:$constant constant(Facebook\WebDriver\WebDriverKeys:: . $value);if ($constant) {$element-sendKeys($constant);} else {$this-output-writeln(不存在的按键操作Facebook\WebDriver\WebDriverKeys:: . $value);}break;case clear:$this-output-writeln(clear);$element-clear();break;case sleep:sleep($value);break;case script:$this-driver-executeScript($value, [$element]);default:}}function run_script($do){$scripts $do[option];if (is_string($scripts)) {$scripts[] $scripts;}if (is_array($scripts)) {foreach ($scripts as $key $script) {$this-driver-executeScript($script);}}}function frame($do){$option $do[option];switch ($option) {case inframe:$this-inframe($do);break;case outframe:$this-outFrame();break;case parentFrame:$this-parentFrame();break;default:$this-output-writeln(操作错误);}}function inframe($do){$select $this-getSelect($do);$iframeElement $this-driver-findElement($select);$this-driver-switchTo()-frame($iframeElement);}function outFrame(){$this-driver-switchTo()-defaultContent();}function parentFrame(){$this-driver-switchTo()-parentFrame();}function countChildElement($do){$select $this-getSelect($do);$parentElement $this-driver-findElement($select);// 找到父元素下的所有子元素$childElements $parentElement-findElements(WebDriverBy::tagName(*));// 获取所有元素的个数return count($childElements);}function checkNumberDo($do){$this-output-writeln(开始执行:checkNumberDo);$func $do[func];$number (int)$func($this-driver, $do);$this-output-writeln(获取元素数量: . $number);if ($number) {$emptyArrays array_fill(0, $number, []);$options $do[setps] ?: false;foreach ($emptyArrays as $null) {if (is_array($options)) {foreach ($options as $option) {try {$this-runSetp($option);} catch (\Throwable $th) {//throw $th;}}}}}}function checkIsset($do){// $select $this-getSelect($do);// $parentElements $this-driver-findElements($select);// $this-output-writeln(判断元素是否存在);// if (!empty($parentElements)) {// $this-output-writeln(元素存在,开始执行对比程序);$func $do[func];if ((bool)$func($this-driver, $do)) {$this-output-writeln(对比成功);$options $do[true] ?: false;} else {$this-output-writeln(对比失败);$options $do[false] ?: false;}if ($options) {foreach ($options as $option) {$this-runSetp($option);}}}protected function runSetp($option){if ($option) {$this-output-writeln(-------------------------------------------);$this-output-writeln(时间 . date(Y-m-d H:i:s, time()));if (isset($option[title])) {$this-output-writeln(操作名称 . $option[title]);}$this-output-writeln(操作类型 . $option[type]);$this-output-writeln(操作数据 . json_encode($option, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));$type $option[type];$this-$type($option[do]);if (isset($option[sleep])) {sleep($option[sleep]);}}}protected function rpush($Options){$redis new \Redis();$redis-connect(127.0.0.1, 6379);$password fenglove;$redis-auth($password);foreach ($Options as $k $Option) {$redis-rpush(Options, json_encode($Option));}}protected function lpop(){$redis new \Redis();$redis-connect(127.0.0.1, 6379);$password fenglove;$redis-auth($password);//list类型出队操作$value $redis-lpop(Options);if ($value) {return json_decode($value, true);} else {return false;}}
}docker是通过docker的api来管理容器的重启的
?phpdeclare(strict_types1);namespace app\yperp\common;trait Docker
{/*** docker api* param $url* param string $method* return mixed* throws \GuzzleHttp\Exception\GuzzleException* throws \Psr\SimpleCache\InvalidArgumentException* throws \RedisException* throws \think\db\exception\DataNotFoundException* throws \think\db\exception\DbException*/static function docker_api($url, $method GET){// var_dump($url);$url http://localhost:2375 . $url;$ch curl_init($url);curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);curl_setopt($ch, CURLOPT_HEADER, 0);curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);$response curl_exec($ch);curl_close($ch);return json_decode($response, true);}/*** 容器重启*/static function docer_containers_restart($containerId){return static::docker_api(/containers/{$containerId}/restart, POST);}/*** 获取硬气状态*/static function docer_containers_info($containerId){return static::docker_api(/containers/{$containerId}/json);}/*** 检查容器是否启动*/static function docer_check_run($containerId){$containers static::docer_containers_info($containerId);return ($containers[State][Status] running) ? true : false;}
}命令行实例
?phpnamespace app\yperp\command;use app\yperp\common\MyWebDriver;
use app\yperp\common\Redis;
use think\console\Command;
use think\console\Input;
use think\console\input\Argument;
use think\console\Output;class mgtpush extends Command
{use MyWebDriver;protected function configure(){// 指令配置$this-setName(pushserver)-addArgument(restart, Argument::OPTIONAL, 重启docker容器)-setDescription(推送数据到系统);}protected function execute(Input $input, Output $output){// 指令输出$output-writeln(pushserver);// 指令输出$this-input $input;$this-output $output;$restart $this-input-getArgument(restart);if ($restart) {Redis::ldelete();$this-docker_restart();}$this-output-writeln(启动完成);// $this-driver-get(https://yjx.jzzw-tech.cn/test.html);$this-output-writeln(等待操作);$this-toRun();}
}下面是生成工作流的数组实例可按需使用按顺序推送到队列即可按操作执行
?phpdeclare(strict_types1);namespace app\yperp\common;class List
{static public function docker_restart(){return [// [type this, do [this_method docker_restart], sleep 3],];}static public function login(){return [[type this, do [this_method run_login], sleep 3],];}static public function checklogin(){return [[type this, do [this_method run_login], sleep 3],];}static public function list(){return [[type frame, do [option inframe, xpath /html/body/div[8]/div[2]/div[1]/div[2]/iframe], sleep 1],[type findElement, do [option click, xpath /html/body/div/div[2]/div/div[4]/a,], sleep 1],[type frame, do [option outframe,], sleep 3],[type frame, do [option inframe, xpath /html/body/div[8]/div[2]/div[3]/iframe], sleep 1],[type findElement, do [xpath /html/body/div[1]/div[1]/div[2]/div[2]/div/div[1], option doubleClick], sleep 1],[type findElement, do [xpath /html/body/div[1]/div[1]/div[2]/div[2]/div/div[1], option doubleClick], sleep 1],[type findElement, do [xpath /html/body/div[1]/div[1]/div[2]/div[2]/div/div[1], option doubleClick], sleep 1],[type findElement, do [xpath /html/body/div[1]/div[1]/div[2]/div[2]/div[2]/div[1], option doubleClick]],[type findElement, do [xpath /html/body/div[1]/div[1]/div[2]/div[2]/div[2]/div[1], option doubleClick]],[type findElement, do [xpath /html/body/div[1]/div[1]/div[3]/table/tbody/tr/td[1], option doubleClick]],];}static public function nav($navs []){$step[] [type frame, do [option inframe, xpath /html/body/div[8]/div[2]/div[1]/div[2]/iframe], sleep 1];$step[] [type findElement, do [option click, cssSelector div[title资源库],], sleep 1];$step[] [type findElement, do [option click, xpath //div[title产品中心 and classpresite],], sleep 1];$step[] [type findElement, do [option click, xpath //div[title产品中心 and classprechannel],], sleep 1];foreach ($navs as $key $nav) {$step[] [type findElement, do [option click, cssSelector div[title . $nav . ],]];$step[] [type findElement, do [option click, cssSelector div[title . $nav . ] a,]];}$step[] [type frame, do [option outframe,], sleep 3];$step[] [type frame, do [option inframe, xpath /html/body/div[8]/div[2]/div[3]/iframe], sleep 1];return $step;}static function checkIsset($goods_code){return [[type findElement, do [xpath /html/body/div[1]/div[1]/div[1]/div/div[3]/div/div/table/tbody/tr/td[1]/input, option click],],[title 搜索物料编码,type findElement, do [xpath /html/body/div[1]/div[1]/div[1]/div/div[3]/div/div/table/tbody/tr/td[1]/input,option [sendKeys $goods_code,]],sleep 1],[type findElement, do [xpath /html/body/div[1]/div[1]/div[1]/div/div[3]/div/div/table/tbody/tr/td[2]/div, option click], sleep 3],[title 判断物料编码是否存在,type checkIsset,do [xpath /html/body/div[1]/div[1]/div[2]/div[1]/table/tbody[2]/tr/td,func checkAttrClassName,true static::editPage(),false static::addPage(),],sleep 3],];}static public function addPage(){return [//点击进入创建商品页面[title 打开添加窗口, type findElement, do [xpath /html/body/div[1]/div[2]/div[1]/div[2]/div[1]/div/div[1]/div/div[2], option click]],[type window, do [option toWindow, value 1], sleep 3],];}static public function editPage(){return [//点击进入创建商品页面[title 打开编辑窗口, type findElement, do [xpath /html/body/div[1]/div[1]/div[2]/div[1]/table/tbody[2]/tr/td[2]/span, option click]],[type window, do [option toWindow, value 1], sleep 3],];}static function status($info){return [[type class, do [className app\yperp\model\Supplier, func status, args [$info[id], 2]], sleep 3],];}static public function saveDataTest($array []){return [//图片管理[title 切换tab 图片管理, type findElement, do [xpath /html/body/form/div/div/ul/li[11]/a, option click,], sleep 3],[type frame, do [option inframe, xpath /html/body/form/div/div/div[11]/div/div/div/iframe]],[title 显示上传按钮, type findElement, do [xpath /html/body/div[4]/div[1]/div/input[2],option [script arguments[0].setAttribute(style, display: block;),],], sleep 3],//商品头图[title 上传商品头图, type findElement, do [xpath /html/body/div[4]/div[1]/div/input[2],option [uploadFiles $array[goods_header_imgs]],], sleep 3],// /html/body/div[4]/div[2]/div/div[1]/div[3]/span[3][type window, do [option toWindow, value 1], sleep 3],];}static public function saveGoodsHeaderImgs($array []){$setp [];//图片管理$setp[] [title 切换tab 图片管理, type findElement, do [xpath /html/body/form/div/div/ul/li[11]/a, option click,], sleep 3];$setp[] [type frame, do [option inframe, xpath /html/body/form/div/div/div[11]/div/div/div/iframe]];$setp[] [title 显示上传按钮, type findElement, do [xpath /html/body/div[4]/div[1]/div/input[2],option [script arguments[0].setAttribute(style, display: block;),],], sleep 3];// /html/body/div[4]/div[2]/div$setp[] [title 根据数量执行操作步骤,type checkNumberDo,do [xpath /html/body/div[4]/div[2]/div,func checkElementNumber,setps [// /html/body/div[4]/div[2]/div/div[1]/div[3]/span[3][title 删除商品头图, type findElement, do [xpath /html/body/div[4]/div[2]/div/div[1]/div[3]/span[3], option click]],],],sleep 3];//商品头图foreach ($array[goods_header_imgs] as $key $goods_header_imgs) {# code...$setp[] [title 上传商品头图, type findElement, do [xpath /html/body/div[4]/div[1]/div/input[2],option [clear clear,uploadFiles [str_replace(/\s/, , $goods_header_imgs)],],], sleep 3];}$setp[] [type window, do [option toWindow, value 1], sleep 3];return $setp;}static public function saveGoodsBodyImgs($array []){$setp [];//产品特征$setp[] [title 切换tab 产品特征, type findElement, do [xpath /html/body/form/div/div/ul/li[8]/a, option click,], sleep 3];$setp[] [type frame, do [option inframe, xpath /html/body/form/div/div/div[8]/div/div/div/iframe]];$setp[] [type frame, do [option inframe, xpath /html/body/iframe[7]]];$setp[] [title 点击代码按钮, type findElement, do [xpath /html/body/div[2]/div[3]/div[1], option click,], sleep 3];$setp[] [title 清空代码, type findElement, do [xpath /html/body/div[2]/div[2]/div/table/tbody/tr[2]/td[2]/div/textarea, option [clear clear],], sleep 3];$setp[] [title 点击设计按钮, type findElement, do [xpath /html/body/div[2]/div[3]/div[2], option click,], sleep 3];$setp[] [title 点击多图上传打开新窗口, type findElement, do [xpath /html/body/div[2]/div[1]/table/tbody/tr[2]/td[3]/table[1]/tbody/tr/td[23]/div, option click,], sleep 1];$setp[] [type window, do [option toWindow, value 2], sleep 3];$setp[] [title 显示详情图上传按钮, type findElement, do [xpath /html/body/div[2]/div[3]/div/input,option [script arguments[0].setAttribute(style, display: block;),],], sleep 3];//商品详情图foreach ($array[goods_body_imgs] as $key $goods_body_img) {$setp[] [title 上传商品详情图, type findElement, do [xpath /html/body/div[2]/div[3]/div/input,option [clear clear,uploadFiles [str_replace(/\s/, , $goods_body_img)],],],];}$setp[] [title 确认上传, type findElement, do [xpath /html/body/div[4]/div[1], option click,], sleep 3];$setp[] [type window, do [option toWindow, value 1], sleep 3];return $setp;}static function saveGoodsMainImgs($array){return [//商品头图[title 判断主图是否存在,type checkIsset,do [xpath /html/body/form/div/div/div[1]/div[2]/div[3]/div/form/div[4],func checkAttrClassName,true [[title 删除已经存在的商品头图, type findElement, do [xpath /html/body/form/div/div/div[1]/div[2]/div[3]/div/form/div[4]/div/span[2], option click]],],],sleep 3],// 如果 /html/body/form/div/div/div[1]/div[2]/div[3]/div/form/div[4] 中有两个值那么将删除后重新再上传[title 新增商品头图, type findElement, do [xpath /html/body/form/div/div/div[1]/div[2]/div[3]/div/form/div[1]/input,option [sendKeys $array[goods_main_img]]], sleep 3],];}static public function closeWindow(){return [//保存并关闭[title 保存并关闭, type findElement, do [xpath /html/body/form/div/div/div[13]/button[1], option click,], sleep 2],[title 关闭提示确认, type findElement, error [option closeWindow,], do [xpath /html/body/div/div[2]/div/div/table/tbody/tr[2]/td/div/div/div/a, option click,], sleep 2],// [title 关闭窗口, type findElement, do [xpath /html/body/form/div/div/div[13]/button[3], option click,], sleep 2],[title 关闭窗口, type window, do [option closeWindow, value 1], sleep 3],[title 回到主窗口, type window, do [option toWindow, value 0], sleep 3],// [title 关闭窗口, type window, do [option closeWindow, value 0], sleep 3],];}static public function saveData($array []){if (!isset($array[weight])) {$array[weight] 8;}if (!isset($array[weight_unit])) {$array[weight_unit] 1;}$array[goods_title] $array[goods_title_alias];$array[goods_color] $array[goods_color_alias];$array[goods_sku] $array[goods_sku_alias];return [//物料编码[title 物料编码, type findElement, do [xpath /html/body/form/div/div/div[1]/div[1]/div[3]/span/input, option [clear clear, sendKeys $array[goods_sku]],], sleep 3],//供应商名称[title 供应商名称, type findElement, do [xpath /html/body/form/div/div/div[1]/div[5]/div[3]/div, option click]],[title 供应商名称, type findElement, do [xpath /html/body/form/div/div/div[1]/div[5]/div[3]/div/div/ul/li[3], option click]],//物料描述[title 物料描述, type findElement, do [xpath /html/body/form/div/div/div[1]/div[6]/div[3]/span/input, option [clear clear, sendKeys $array[goods_title] . | . $array[goods_color],]],],//产品简称[title 产品简称, type findElement, do [xpath /html/body/form/div/div/div[1]/div[7]/div[3]/span/input, option [clear clear, sendKeys $array[goods_title] . | . $array[goods_color]],],],//品牌[title 品牌, type findElement, do [xpath /html/body/form/div/div/div[1]/div[8]/div[3]/select, option select, type index, value (isset($array[brand]) ? $array[brand] : 4),],],//产品品牌[title 产品品牌, type findElement, do [xpath /html/body/form/div/div/div[1]/div[9]/div[3]/select, option select, type index, value (isset($array[goods_brand]) ? $array[goods_brand] : 4),],],//产品组[title 产品组, type findElement, do [xpath /html/body/form/div/div/div[1]/div[10]/div[3]/span/input, option [clear clear, sendKeys 其他,]],],//产品线[title 产品线, type findElement, do [xpath /html/body/form/div/div/div[1]/div[11]/div[3]/div, option click]],[title 产品线, type findElement, do [xpath /html/body/form/div/div/div[1]/div[11]/div[3]/div/div/ul/li[32], option click]],//产品名称[title 产品名称, type findElement, do [xpath /html/body/form/div/div/div[1]/fieldset[1]/div[1]/div[3]/span/input, option [clear clear, sendKeys $array[goods_title] . | . $array[goods_color]],],],//重量单位[title 重量单位, type findElement, do [xpath /html/body/form/div/div/div[1]/fieldset[2]/div[1]/div[3]/select, option select, type index, value $array[weight_unit],],],//计量单位[title 计量单位, type findElement, do [xpath /html/body/form/div/div/div[1]/fieldset[2]/div[2]/div[3]/select, option select, type index, value $array[weight_unit]],],//最小计量单位数量[title 最小计量单位数量, type findElement, do [xpath /html/body/form/div/div/div[1]/fieldset[2]/div[3]/div[3]/span/input, option [clear clear, sendKeys $array[weight]],],],//外包装尺寸厚[title 外包装尺寸厚, type findElement, do [xpath /html/body/form/div/div/div[1]/fieldset[2]/div[4]/div[3]/span/input, option [clear clear, sendKeys $array[weight]],],],//外包装尺寸(高)[title 外包装尺寸(高), type findElement, do [xpath /html/body/form/div/div/div[1]/fieldset[2]/div[5]/div[3]/span/input, option [clear clear, sendKeys $array[weight]],],],//外包装尺寸(宽)[title 外包装尺寸(宽), type findElement, do [xpath /html/body/form/div/div/div[1]/fieldset[2]/div[6]/div[3]/span/input, option [clear clear, sendKeys $array[weight]],],],//切换tab OFC专用区[title 切换tab OFC专用区, type findElement, do [xpath /html/body/form/div/div/ul/li[2]/a, option click,]],//货号[title 货号, type findElement, do [xpath /html/body/form/div/div/div[2]/div[1]/div[3]/span/input, option [clear clear, sendKeys $array[goods_code]]],],//条形码[title 条形码, type findElement, do [xpath /html/body/form/div/div/div[2]/div[2]/div[3]/span/input, option [clear clear, sendKeys $array[goods_code]]],],//税务编码[title 税务编码, type findElement, do [xpath /html/body/form/div/div/div[2]/div[3]/div[3]/span/input, option [clear clear, sendKeys $array[goods_code]]],],//堆放层数[title 堆放层数, type findElement, do [xpath /html/body/form/div/div/div[2]/div[4]/div[3]/span/input, option [clear clear, sendKeys 1,]],],//是否为代销[title 是否为代销, type findElement, do [xpath /html/body/form/div/div/div[2]/div[5]/div[3]/div/div[1]/input, option click,]],//切换tab 其他[title 切换tab 其他, type findElement, do [xpath /html/body/form/div/div/ul/li[12]/a, option click,]],//产品销售渠道[title 产品销售渠道, type findElement, do [xpath /html/body/form/div/div/div[12]/div[1]/div[3]/select, option select, type index, value 1,],],];}
}总结
其实就是将复杂冗长的代码逻辑通过数组来表达
[type class, do [className app\yperp\model\Supplier, func status, args [$info[id], 2]], sleep 3],
type是指定使用什么操作例如执行一个类方法做条件判断查找一个元素点击一个元素上传文件等
do是执行这个操作的具体参数每个操作需要的参数可能都不一样
sleep就是执行这个操作后需要等待的时间有的情况下网络环境等其他原因需要等待页面加载或后台反馈后才进行下一步操作
需要注意的是文件上传需要确定是否需要删除原来的文件并重新上传例如电商图片等所有上传的文件地址必须是以容器为主目录所以需要将本地资源文件夹给到容器中否则可能无法访问到文件资源