FlowChart_CN.html 78 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814
  1. <!doctype html>
  2. <html lang="en">
  3. <head>
  4. <script src="jquery-3.4.1.min.js"></script>
  5. <meta charset="UTF-8">
  6. <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  7. <meta http-equiv="X-UA-Compatible" content="ie=edge">
  8. <script src="bootstrap/js/bootstrap.js"></script>
  9. <script src="vue.js"></script>
  10. <link rel="stylesheet" href="bootstrap/css/bootstrap.css"></link>
  11. <link rel="stylesheet" href="FlowChart.css"></link>
  12. <title>设计流程</title>
  13. </head>
  14. <body>
  15. <div id="tip" class="alert alert-success alert-dismissible fade show" style="position: fixed; width:100%;display: none;">
  16. <button type="button" class="close" data-dismiss="alert">&times;</button> <span id="tip_message">提示:保存成功!</span>
  17. </div>
  18. <div id="tipInfo" class="alert alert-info alert-dismissible fade show" style="position: fixed; width:100%;display: none;">
  19. <button type="button" class="close" data-dismiss="alert">&times;</button> <span id="info_message">提示:您加载的任务版本不是最新版,可能出现兼容性问题。</span>
  20. </div>
  21. <div id="tipError" class="alert alert-danger alert-dismissible fade show" style="position: fixed; width:100%;display: none;">
  22. <button type="button" class="close" data-dismiss="alert">&times;</button> <span id="error_message">提示:保存名不符合MySQL表名规范,请重试!</span>
  23. </div>
  24. <div id="navigator">
  25. <nav aria-label="breadcrumb" v-if="type==1">
  26. <ol class="breadcrumb" style="padding-left:23px;padding-bottom: 0;margin-bottom:0;background-color: white">
  27. <li @click="gotoHome" class="breadcrumb-item"><a href="#">{{"Home~首页" | lang}}</a></li>
  28. <li @click="gotoInfo" aria-current="page" class="breadcrumb-item" style="color: black"><a href="#">{{"Task Information~任务信息" | lang}}</a></li>
  29. <li aria-current="page" class="breadcrumb-item active" style="color: black">{{"Task Flow~任务流程" | lang}}</li>
  30. </ol>
  31. </nav>
  32. </div>
  33. <div style="display:flex">
  34. <div style="width: 200px;float:left;overflow: auto">
  35. <div class="toolbox" style="text-align:center;margin: 20px;border-radius:10px;border:navy solid;background-color:rgb(242,243,245);z-index: 9999;">
  36. <div style="padding: 10px;border-radius:10px;font-size: 20px;">工具箱</div>
  37. <button type="button" id="save" data-toggle="modal" data-target="#myModal" onmousedown="$('#myModal').modal('show');" class="btn btn-primary">保存任务</button>
  38. <button type="button" data=1 draggable="true" class="btn btn-outline-primary options">打开网页</button>
  39. <button type="button" data=2 draggable="true" class="btn btn-outline-primary options">点击元素</button>
  40. <button type="button" data=3 draggable="true" class="btn btn-outline-primary options">提取数据</button>
  41. <button type="button" data=4 draggable="true" class="btn btn-outline-primary options">输入文字</button>
  42. <button type="button" data=5 draggable="true" class="btn btn-outline-primary options" style="font-weight: bold">自定义操作</button>
  43. <button type="button" data=6 draggable="true" style="font-size: 14px!important;" class="btn btn-outline-primary options">切换下拉选项</button>
  44. <button type="button" data=7 draggable="true" class="btn btn-outline-primary options">移动到元素</button>
  45. <button type="button" data=8 draggable="true" class="btn btn-outline-primary options" style="font-weight: bold">循环</button>
  46. <button type="button" data=9 draggable="true" class="btn btn-outline-primary options" style="font-weight: bold">判断条件</button>
  47. <div>----------</div>
  48. <button type="button" data=13 draggable="true" class="btn btn-outline-primary options" title="调整下一个要插入的节点的位置">调整锚点</button>
  49. <button type="button" data=10 class="btn btn-outline-primary options">剪切元素</button>
  50. <button type="button" data=11 class="btn btn-outline-primary options">复制元素</button>
  51. <button type="button" data=12 class="btn btn-outline-primary options">删除元素</button>
  52. <button type="button" data=0 class="btn btn-outline-primary2 options">取消操作</button>
  53. <div style="text-align: left;margin: 10px;font-size:15px!important">提示:拖动上方按钮到流程图箭头处以添加操作,也可以点击按钮再点击箭头。</div>
  54. </div>
  55. </div>
  56. <div style="margin-top:20px;border: solid;height:850px;overflow: auto;width:58%;float:right" id="flowchart_graph">
  57. <div id="0" class="clk" data="0">
  58. </div>
  59. <div style="border-radius: 50%;width: 40px;height: 40px;border:solid black;margin: 5px auto;background-color:lightcyan">
  60. <p style="font-size: 22px!important;text-align: center;margin-left: 1px;">■</p>
  61. </div>
  62. </div>
  63. <div style="margin-top:20px;border: solid navy;height:850px;overflow: auto;margin-left:10px;margin-right:10px;width:30%;float:right;min-width:300px">
  64. <!-- <div style="display: inline-block;border-bottom:solid 2px;width:100%">
  65. <input spellcheck=false style="float:left;margin-left:10px;margin-top:10px;margin-bottom:10px" type="button" class="btn-primary" value="保存任务"></input>
  66. </div> -->
  67. <div class="Modify" id="app">
  68. <div class="modal fade" id="myModal_XPath" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
  69. <div class="modal-dialog">
  70. <div class="modal-content">
  71. <div class="modal-header">
  72. <h4 class="modal-title">等价XPath</h4>
  73. <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
  74. </div>
  75. <div class="modal-body">
  76. <label>以下提供除默认生成的XPath外其余等价的XPath,都能定位到同一个元素(但不完全准确,可能可以定位到除该元素外的其他元素,因此只是提供在这里作为参考)。 </label>
  77. <label>每行一个XPath(可使用预装的XPath Helper扩展调试):</label>
  78. <textarea spellcheck=false id="otherXPaths" onkeydown="inputDelete(event)" class="form-control" rows="4">{{XPaths}}</textarea>
  79. <div>
  80. <img src="../img/XPather_helper.png" style="width:50%;height:50%; margin: 10px auto"></div>
  81. </div>
  82. </div>
  83. <!-- /.modal-content -->
  84. </div>
  85. <!-- /.modal -->
  86. </div>
  87. <div>
  88. <label>提示:鼠标移到笑脸可查看提示,在流程图中<b>双击</b>操作可<b>试运行</b>(页面完全加载完毕后),<b>右键</b>点击操作查看更多选项。</label>
  89. <label>选项名称</span>:</label>
  90. <input spellcheck=false onkeydown="inputDelete(event)" class="form-control" v-model='list.nl[index.nowNodeIndex]["title"]'></input>
  91. </div>
  92. <!-- 下面是10种不同类型操作选项的不同的配置页面 -->
  93. <div class="elements" v-if="nodeType==1">
  94. <div v-if="nowNode['isInLoop']">
  95. <!-- 如果在循环内且循环内是固定文本才显示此行元素 -->
  96. <p><input spellcheck=false onkeydown="inputDelete(event)" type="checkbox" v-model='useLoop'></input>使用循环内的链接</p>
  97. </div>
  98. <div v-if='!useLoop'>
  99. <!-- <label>url:</label>-->
  100. <!-- <input spellcheck=false onkeydown="inputDelete(event)" class="form-control" v-model='nowNode["parameters"]["url"]'></input>-->
  101. <label v-if='nowNode["parameters"]["url"]!="about:blank"'>链接池(每行一个链接,有多少行链接整个任务流程就会被执行多少次):</label>
  102. <label v-else>链接(只能填写一个链接,因为是手动添加的打开网页操作):</label>
  103. <textarea spellcheck=false v-if='nowNode["parameters"]["url"]!="about:blank"' onkeydown="inputDelete(event)" class="form-control" rows="2" v-model='nowNode["parameters"]["links"]'></textarea>
  104. <input spellcheck=false v-else onkeydown="inputDelete(event)" class="form-control" v-model='nowNode["parameters"]["links"]'></input>
  105. </div>
  106. <label>页面加载最长等待时间(秒):</label>
  107. <input spellcheck=false onkeydown="inputDelete(event)" class="form-control" v-model.number="nowNode['parameters']['maxWaitTime']" type="number" required></input>
  108. <label>打开网页后是否向下滚动:</label>
  109. <select v-model='nowNode["parameters"]["scrollType"]' class="form-control">
  110. <option :value = 0>不滚动</option>
  111. <option :value = 1>向下滚动一屏</option>
  112. <option :value = 2>滚动到底部</option>
  113. <option :value = 3>一直滚动直到页面内容无变化(需设置好滚动后的等待时间用于检测页面变化)</option>
  114. </select>
  115. <label>滚动次数(滚动类型设置为<b>不滚动</b>或<b>一直滚动</b>时请忽略此项):</label>
  116. <input spellcheck=false onkeydown="inputDelete(event)" class="form-control" v-model.number="nowNode['parameters']['scrollCount']" type="number" required></input>
  117. <label>滚动后等待时间(秒):</label>
  118. <input spellcheck=false onkeydown="inputDelete(event)" class="form-control" v-model.number="nowNode['parameters']['scrollWaitTime']" type="number" required></input>
  119. <p style="margin-top: 10px">
  120. <a class="btn btn-primary" data-toggle="collapse" href="#collapseOpenPage" role="button" aria-expanded="false" aria-controls="collapseExample">
  121. 点此展开/折叠自定义操作
  122. </a>
  123. </p>
  124. <div :class="{collapse: true, 'show': nowNode['parameters']['cookies'].length!=0}" id="collapseOpenPage">
  125. <div>
  126. <label>加载后设置Cookies: </label>
  127. <p style="margin-bottom: 20px;color:white"><a class="btn btn-primary" @click="getCookies">
  128. 点击获取当前页面Cookie
  129. </a></p>
  130. <textarea spellcheck=false onkeydown="inputDelete(event)" class="form-control" rows="2"
  131. placeholder='key=value形式,每行一个键值对' v-model='nowNode["parameters"]["cookies"]' id="pageCookies" style="font-size: 14px!important;"></textarea>
  132. </div>
  133. </div>
  134. </div>
  135. <div class="elements" v-if="nodeType==2">
  136. <p><input spellcheck=false onkeydown="inputDelete(event)" type="checkbox" v-model='nowNode["parameters"]["iframe"]'></input>元素在iframe内</p>
  137. <div v-if="nowNode['isInLoop']">
  138. <!-- 如果在循环内才显示此行元素 -->
  139. <p><input spellcheck=false onkeydown="inputDelete(event)" type="checkbox" v-model='useLoop'></input>使用相对循环内的XPath定位到的元素</p>
  140. </div>
  141. <div>
  142. <label>XPath(或者用point(10,10)表示点击网页坐标位置(10, 10)以用来点击空白区域推出弹窗对话框文本列表等): <span style="font-size: 30px!important;" title="相对XPATH写法:以/开头,如循环项XPATH为/html/body/div[1],您的输入为/*[@id='tab-customer'],则最终寻址的xpath为:/html/body/div[1]/*[@id='tab-customer']">☺</span></label>
  143. <textarea spellcheck=false onkeydown="inputDelete(event)" class="form-control" rows="2" v-model='xpath'></textarea>
  144. <p><button type="button" data-toggle="modal" data-target="#myModal_XPath" @click="changeXPaths(nowNode['parameters']['allXPaths'])" class="btn btn-primary" style="margin-top: 10px">点此查看其他等价的XPath</button></p>
  145. <label>任务运行时最终定位的本元素XPath:</label>
  146. <textarea v-model="getFinalXPath(nowNode['parameters']['xpath'], useLoop)" spellcheck=false onkeydown="inputDelete(event)" class="form-control" rows="2" readonly style="background:ghostwhite"></textarea>
  147. </div>
  148. <p style="margin-top: 10px">
  149. <a class="btn btn-primary" data-toggle="collapse" href="#collapseExample" role="button" aria-expanded="false" aria-controls="collapseExample">
  150. 点此展开/折叠自定义操作
  151. </a>
  152. </p>
  153. <div :class="{collapse: true, 'show': nowNode['parameters']['beforeJS'].length!=0 || nowNode['parameters']['afterJS'].length!=0}" id="collapseExample">
  154. <div>
  155. <label>点击该元素<strong>前</strong>针对该元素执行一段JavaScript脚本: </label>
  156. <textarea spellcheck=false onkeydown="inputDelete(event)" class="form-control" rows="2"
  157. placeholder='该元素用arguments[0]来表示,示例JS代码:arguments[0].innerText = arguments[0].innerText.replace("上海","Shanghai")即实现了将元素文字中的“上海”替换成”Shanghai“的功能,然后后续如提取数据时就会提取到替换后的值。' v-model='nowNode["parameters"]["beforeJS"]'></textarea>
  158. <label>最长等待脚本执行时间(0代表无限等待): </label>
  159. <input spellcheck=false onkeydown="inputDelete(event)" required class="form-control" type="number" v-model.number='nowNode["parameters"]["beforeJSWaitTime"]'></input>
  160. <label>点击该元素<strong>后</strong>针对该元素执行一段JavaScript脚本: </label>
  161. <textarea spellcheck=false onkeydown="inputDelete(event)" class="form-control" rows="2" placeholder='该元素用arguments[0]来表示,示例JS代码:arguments[0].click()即点击此元素' v-model='nowNode["parameters"]["afterJS"]'></textarea>
  162. <label>最长等待脚本执行时间(0代表无限等待): </label>
  163. <input spellcheck=false onkeydown="inputDelete(event)" required class="form-control" type="number" v-model.number='nowNode["parameters"]["afterJSWaitTime"]'></input>
  164. </div>
  165. </div>
  166. <label>点击后页面加载最长等待时间(秒):</label>
  167. <input spellcheck=false onkeydown="inputDelete(event)" class="form-control" v-model.number="nowNode['parameters']['maxWaitTime']" type="number" required></input>
  168. <label>点击类型:</label>
  169. <select v-model='nowNode["parameters"]["clickWay"]' class="form-control">
  170. <option :value = 0>Selenium点击</option>
  171. <option :value = 1>JavaScript点击</option>
  172. </select>
  173. <label>在新标签页打开超链接:</label>
  174. <select v-model='nowNode["parameters"]["newTab"]' class="form-control">
  175. <option :value = 1>是</option>
  176. <option :value = 0>否</option>
  177. </select>
  178. <label>点击后是否向下滚动页面:</label>
  179. <select v-model='nowNode["parameters"]["scrollType"]' class="form-control">
  180. <option :value = 0>不滚动</option>
  181. <option :value = 1>向下滚动一屏</option>
  182. <option :value = 2>滚动到底部</option>
  183. <option :value = 3>一直滚动直到页面内容无变化(需设置好滚动后的等待时间用于检测页面变化)</option>
  184. </select>
  185. <label>滚动次数(滚动类型设置为<b>不滚动</b>或<b>一直滚动</b>时请忽略此项):</label>
  186. <input spellcheck=false onkeydown="inputDelete(event)" class="form-control" v-model.number="nowNode['parameters']['scrollCount']" type="number" required></input>
  187. <label>滚动后等待时间(秒):</label>
  188. <input spellcheck=false onkeydown="inputDelete(event)" class="form-control" v-model.number="nowNode['parameters']['scrollWaitTime']" type="number" required></input>
  189. <label>文件下载最长等待时间(秒):</label>
  190. <input spellcheck=false onkeydown="inputDelete(event)" class="form-control" v-model.number="nowNode['parameters']['downloadWaitTime']" type="number" required></input>
  191. <label>点击元素后如有弹窗出现,弹窗处理方式:</label>
  192. <p><select v-model='nowNode["parameters"]["alertHandleType"]' class="form-control">
  193. <option :value = 0>无弹窗</option>
  194. <option :value = 1>接受弹窗(点击弹窗确定按钮)</option>
  195. <option :value = 2>拒绝弹窗(点击弹窗取消按钮,仅限Confirm弹框)</option>
  196. </select></p>
  197. </div>
  198. <div class="elements" v-if="nodeType==3">
  199. <p>
  200. <button class="btn btn-primary" v-on:mousedown= 'addParam'>新增字段</button>
  201. </p>
  202. <p><input spellcheck=false onkeydown="inputDelete(event)" type="checkbox" v-model='nowNode["parameters"]["clear"]'></input>提取数据前清空其他操作字段已记录的值</p>
  203. <p><input spellcheck=false onkeydown="inputDelete(event)" type="checkbox" v-model='nowNode["parameters"]["newLine"]'></input>此提取数据操作后生成新数据行 <span style="font-size: 30px!important;" title="取消勾选则适用于不想每次提取操作都生成一个新行的场景">☺</span></p>
  204. <div class="toolkitcontain">
  205. <table class="toolkittb2" cellspacing="0">
  206. <tbody>
  207. <th>字段名</th>
  208. <th style="width:200px">示例值</th>
  209. <th>操作</th>
  210. </tbody>
  211. </table>
  212. <table class="toolkittb4" cellspacing="0">
  213. <tbody>
  214. <tr v-for="i in params.parameters.length">
  215. <td style="padding-left:0px"><input spellcheck=false onkeydown="inputDelete(event)" style='padding-left:2px;font-size:13px!important;height:100%' v-model='params.parameters[i-1]["name"]'></input>
  216. </td>
  217. <td style="width:200px">{{params.parameters[i-1]["exampleValues"][0]["value"]}}</td>
  218. <td>
  219. <a v-on:mousedown="modifyParam(i-1)">修改</a>
  220. <a v-on:mousedown="deleteParam(i-1)">删除</a>
  221. <a v-on:mousedown="upParam(i-1)">上移</a>
  222. <a v-on:mousedown="downParam(i-1)">下移</a>
  223. </td>
  224. </tr>
  225. </table>
  226. </div>
  227. <div style="font-size: 13px;" v-if="paraIndex<params.parameters.length">
  228. <p>当前编辑字段参数名(点击字段的“修改”选项切换参数): </p>
  229. <label><strong>{{params.parameters[paraIndex]["name"]}}</strong></label>
  230. <p v-if="nowNode['isInLoop']"><input spellcheck=false onkeydown="inputDelete(event)" type="checkbox" v-model='params.parameters[paraIndex]["relative"]'></input>使用相对循环内的XPATH</p>
  231. <p v-if='!params.parameters[paraIndex]["relative"]'><input spellcheck=false onkeydown="inputDelete(event)" type="checkbox" v-model='params.parameters[paraIndex]["iframe"]'></input>元素在iframe内</p>
  232. <p>XPath(所有XPath内均可用Field["字段名"]表示参数值,用eval("你的代码")来替换成自定义的变量): <span style="font-size: 30px!important;" title="相对XPATH写法:以/开头,如循环项XPATH为/html/body/div[1],您的输入为/*[@id='tab-customer'],则最终寻址的xpath为:/html/body/div[1]/*[@id='tab-customer']">☺</span></p>
  233. <textarea spellcheck=false onkeydown="inputDelete(event)" class="form-control" rows="2" v-model='params.parameters[paraIndex]["relativeXPath"]' placeholder="如果要写相对循环内的xpath,可以写如*../div[1]即匹配当前循环元素的父元素的第一个div子元素"></textarea>
  234. <p><button type="button" data-toggle="modal" data-target="#myModal_XPath" @click="changeXPaths(params.parameters[paraIndex]['allXPaths'])" class="btn btn-primary" style="margin-top: 10px">点此查看其他等价的XPath</button></p>
  235. <label>任务运行时最终定位的本字段XPath:</label>
  236. <textarea spellcheck=false onkeydown="inputDelete(event)" class="form-control" rows="2" readonly style="background:ghostwhite">{{getFinalXPath(params.parameters[paraIndex]['relativeXPath'], params.parameters[paraIndex]['relative'])}}</textarea>
  237. <div style="margin-top: 10px"><a href="#" v-on:mousedown="trailParam(paraIndex)" style="text-decoration: none">试运行</a></div>
  238. <p style="margin-top: 10px">
  239. <a class="btn btn-primary" data-toggle="collapse" href="#elementAdvanced" role="button" aria-expanded="false" aria-controls="collapseExample">
  240. 点此展开/折叠自定义操作
  241. </a>
  242. </p>
  243. <div :class="{collapse: true, 'show': params.parameters[paraIndex]['beforeJS'].length!=0 || params.parameters[paraIndex]['afterJS'].length!=0}" id="elementAdvanced">
  244. <div>
  245. <label>提取该元素数据<strong>前</strong>针对该元素执行一段JavaScript脚本: </label>
  246. <textarea spellcheck=false onkeydown="inputDelete(event)" class="form-control" rows="2"
  247. placeholder='该元素用arguments[0]来表示,示例JS代码:arguments[0].innerText = arguments[0].innerText.replace("上海","Shanghai")即实现了将元素文字中的“上海”替换成”Shanghai“的功能,然后后续如提取数据时就会提取到替换后的值。' v-model='params.parameters[paraIndex]["beforeJS"]'></textarea>
  248. <label>最长等待脚本执行时间(0代表无限等待): </label>
  249. <input spellcheck=false onkeydown="inputDelete(event)" required class="form-control" type="number" v-model.number='params.parameters[paraIndex]["beforeJSWaitTime"]'></input>
  250. <label>提取该元素数据<strong>后</strong>针对该元素执行一段JavaScript脚本: </label>
  251. <textarea spellcheck=false onkeydown="inputDelete(event)" class="form-control" rows="2" placeholder='该元素用arguments[0]来表示,示例JS代码:arguments[0].click()即点击此元素' v-model='params.parameters[paraIndex]["afterJS"]'></textarea>
  252. <label>最长等待脚本执行时间(0代表无限等待): </label>
  253. <input spellcheck=false onkeydown="inputDelete(event)" required class="form-control" type="number" v-model.number='params.parameters[paraIndex]["afterJSWaitTime"]'></input>
  254. </div>
  255. </div>
  256. <label>采集内容类型</label>
  257. <select v-model='params.parameters[paraIndex]["contentType"]' class="form-control">
  258. <option :value = 0>文本(包括子元素)</option>
  259. <option :value = 1>文本(不包括子元素)</option>
  260. <option :value = 2>innerHTML</option>
  261. <option :value = 3>outerHTML</option>
  262. <option :value = 4>背景图片地址</option>
  263. <option :value = 5>页面网址</option>
  264. <option :value = 6>页面标题</option>
  265. <option :value = 7>元素截图</option>
  266. <option :value = 8>OCR识别文字</option>
  267. <option :value = 14>元素的属性值</option>
  268. <option :value = 9>(针对该元素的)JavaScript代码返回值(需以return 开头)</option>
  269. <option :value = 12>系统命令返回值</option>
  270. <option :value = 13>执行环境下的Python表达式值(eval操作)</option>
  271. <option :value = 10>当前选择框选中的选项值</option>
  272. <option :value = 11>当前选择框选中的选项文本</option>
  273. </select>
  274. <div v-if='params.parameters[paraIndex]["contentType"] == 14'>
  275. <label>属性名称:</label>
  276. <input spellcheck=false onkeydown="inputDelete(event)" class="form-control" v-model='params.parameters[paraIndex]["JS"]' placeholder="属性名称,如class表示当前元素的class属性值,即元素所拥有的类名。"></input>
  277. </div>
  278. <div v-else-if='params.parameters[paraIndex]["contentType"] == 9 || params.parameters[paraIndex]["contentType"] >= 12'>
  279. <label>JavaScript(也可以不针对该元素,直接写return JS代码即可)/系统命令/Python代码:</label>
  280. <textarea spellcheck=false onkeydown="inputDelete(event)" class="form-control" rows="2"
  281. placeholder='如要针对该元素,则该元素用arguments[0]来表示,示例:return arguments[0].innerText + "美元",即实现了提取该元素innerText并后面加“美元”的功能;不然直接如写return new Date().toString()即可获得当前时间戳。' v-model='params.parameters[paraIndex]["JS"]'></textarea>
  282. <label>最长等待脚本执行时间(0代表无限等待): </label>
  283. <input spellcheck=false onkeydown="inputDelete(event)" required class="form-control" type="number" v-model.number='params.parameters[paraIndex]["JSWaitTime"]'></input>
  284. </div>
  285. <label>节点类型</label>
  286. <select v-model='params.parameters[paraIndex]["nodeType"]' class="form-control">
  287. <option :value = 0>普通节点</option>
  288. <option :value = 1>链接文本</option>
  289. <option :value = 2>链接地址</option>
  290. <option :value = 3>表单值</option>
  291. <option :value = 4>图片地址</option>
  292. </select>
  293. <div v-if='params.parameters[paraIndex]["nodeType"] == 4'>
  294. <label>提取图片地址后是否同时<b>下载图片</b>:</label>
  295. <select v-model='params.parameters[paraIndex]["downloadPic"]' class="form-control">
  296. <option :value = 0>否</option>
  297. <option :value = 1>是</option>
  298. </select>
  299. </div>
  300. <!-- <label>提取方式</label>-->
  301. <!-- <select v-model='params.parameters[paraIndex]["extractType"]' class="form-control">-->
  302. <!-- <option :value = 0>普通提取</option>-->
  303. <!-- <option :value = 1>OCR提取</option>-->
  304. <!-- </select>-->
  305. <label>参数类型转换为(用于Excel和数据库):</label>
  306. <select v-model='params.parameters[paraIndex]["paraType"]' class="form-control">
  307. <option value = "text">文本(单个值长度预估超过1万请选择大文本)</option>
  308. <option value = "int">整数(位数在9位以内)</option>
  309. <option value = "double">浮点数(小数)</option>
  310. <option value = "mediumText">大文本(单个值长度超过1万低于100万)</option>
  311. <option value = "datetime">日期时间</option>
  312. <option value = "date">日期</option>
  313. <option value = "time">时间</option>
  314. <option value = "varchar">小文本(单个值长度小于50)</option>
  315. <option value = "longText">超大文本(单个值长度超过100万)</option>
  316. <option value = "bigInt">大整数(位数超过9位)</option>
  317. </select>
  318. <label>元素找不到时的值:</label>
  319. <input spellcheck=false onkeydown="inputDelete(event)" class="form-control" v-model='params.parameters[paraIndex]["default"]'></input>
  320. <label style="margin-top: 15px">是否将内容换行(长文章采集想要换行时设置):</label>
  321. <select v-model='params.parameters[paraIndex]["splitLine"]' class="form-control">
  322. <option :value = 0>否</option>
  323. <option :value = 1>是</option>
  324. </select>
  325. <label style="margin-top: 15px">是否保存该字段(只想把此字段当变量而不想保存时可选否):</label>
  326. <select v-model='params.parameters[paraIndex]["recordASField"]' class="form-control">
  327. <option :value = 1>是</option>
  328. <option :value = 0>否</option>
  329. </select>
  330. <label>参数描述:</label>
  331. <input spellcheck=false onkeydown="inputDelete(event)" class="form-control" style="min-height: 60px" v-model='params.parameters[paraIndex]["desc"]'></input>
  332. </div>
  333. </div>
  334. <div class="elements" v-if="nodeType==4">
  335. <p><input spellcheck=false onkeydown="inputDelete(event)" type="checkbox" v-model='nowNode["parameters"]["iframe"]'></input>元素在iframe内</p>
  336. <div v-if="nowNode['isInLoop']">
  337. <!-- 如果在循环内且循环内是固定文本才显示此行元素 -->
  338. <p><input spellcheck=false onkeydown="inputDelete(event)" type="checkbox" v-model='useLoop'></input>使用循环内的文本(不勾选则每次输入的文本为下方“输入值”文本框内的文本,勾选后会使用所在“文本列表”循环内设置的文本)</p>
  339. <p v-if="useLoop">
  340. <label>索引值(0表示使用整个当前循环的文本,如果大于0则表示当前文本用~来分割开的文本索引取值,即如果当前循环的文本值为A~B,则索引值为1表示输入A,2表示输入B,0表示输入A~B)</label>
  341. <input spellcheck=false onkeydown="inputDelete(event)" class="form-control" type="number" v-model.number='nowNode["parameters"]["index"]'></input></p>
  342. </p>
  343. </div>
  344. <div v-if='!useLoop'>
  345. <label>输入值(用Field["字段名"]来输入某字段/自定义操作的最新提取/返回值,用&lt;enter&gt;或&lt;ENTER&gt;表示模拟按下回车键),用JS("return JS代码")和eval("Python代码")来替换成JavaScript和Python代码返回值:</label>
  346. <textarea spellcheck=false onkeydown="inputDelete(event)" class="form-control" v-model='nowNode["parameters"]["value"]'></textarea>
  347. </div>
  348. <label>XPath: <span style="font-size: 30px!important;" title="相对XPATH写法:以/开头,如循环项XPATH为/html/body/div[1],您的输入为/*[@id='tab-customer'],则最终寻址的xpath为:/html/body/div[1]/*[@id='tab-customer']">☺</span></label>
  349. <textarea spellcheck=false onkeydown="inputDelete(event)" class="form-control" rows="2" v-model='nowNode["parameters"]["xpath"]'></textarea>
  350. <p><button type="button" data-toggle="modal" data-target="#myModal_XPath" @click="changeXPaths(nowNode.parameters['allXPaths'])" class="btn btn-primary" style="margin-top: 10px">点此查看其他等价的XPath</button></p>
  351. <p style="margin-top: 10px">
  352. <a class="btn btn-primary" data-toggle="collapse" href="#inputAdvanced" role="button" aria-expanded="false" aria-controls="collapseExample">
  353. 点此展开/折叠自定义操作
  354. </a>
  355. </p>
  356. <div :class="{collapse: true, 'show': nowNode['parameters']['beforeJS'].length!=0 || nowNode['parameters']['afterJS'].length!=0}" id="inputAdvanced">
  357. <div>
  358. <label>对该元素输入文字<strong>前</strong>针对该元素执行一段JavaScript脚本: </label>
  359. <textarea spellcheck=false onkeydown="inputDelete(event)" class="form-control" rows="2"
  360. placeholder='该元素用arguments[0]来表示,示例JS代码:arguments[0].innerText = arguments[0].innerText.replace("上海","Shanghai")即实现了将元素文字中的“上海”替换成”Shanghai“的功能,然后后续如提取数据时就会提取到替换后的值。' v-model='nowNode["parameters"]["beforeJS"]'></textarea>
  361. <label>最长等待脚本执行时间(0代表无限等待): </label>
  362. <input spellcheck=false onkeydown="inputDelete(event)" required class="form-control" type="number" v-model.number='nowNode["parameters"]["beforeJSWaitTime"]'></input>
  363. <label>对该元素输入文字<strong>后</strong>针对该元素执行一段JavaScript脚本: </label>
  364. <textarea spellcheck=false onkeydown="inputDelete(event)" class="form-control" rows="2" placeholder='该元素用arguments[0]来表示,示例JS代码:arguments[0].click()即点击此元素' v-model='nowNode["parameters"]["afterJS"]'></textarea>
  365. <label>最长等待脚本执行时间(0代表无限等待): </label>
  366. <input spellcheck=false onkeydown="inputDelete(event)" required class="form-control" type="number" v-model.number='nowNode["parameters"]["afterJSWaitTime"]'></input>
  367. </div>
  368. </div>
  369. </div>
  370. <div class="elements" v-if="nodeType==5">
  371. <p><input spellcheck=false onkeydown="inputDelete(event)" type="checkbox" v-model='nowNode["parameters"]["iframe"]'></input>操作在iframe内</p>
  372. <label>执行模式</label>
  373. <select v-model='codeMode' class="form-control" @change="handleCodeModeChange">
  374. <option :value = 0>执行一段JavaScript脚本(如要获得返回值则需以return 开头)</option>
  375. <option :value = 1>执行一段操作系统级别命令</option>
  376. <option v-if="nowNode['isInLoop']" :value = 2>针对当前循环项的JavaScript脚本</option>
  377. <option v-if="nowNode['isInLoop']" :value = 3>退出当前循环(Break操作)</option>
  378. <option v-if="nowNode['isInLoop']" :value = 4>跳过当前循环后面的操作(Continue操作)</option>
  379. <option :value = 5>在执行环境下运行Python代码(exec操作)</option>
  380. <option :value = 6>在执行环境下获得Python表达式值(eval操作)</option>
  381. <option :value = 7>暂停程序执行(如检测到验证码框出现时暂停执行)</option>
  382. <option :value = 8>刷新页面</option>
  383. <option :value = 9>发送邮件</option>
  384. </select>
  385. <div v-if='nowNode["parameters"]["codeMode"] < 3 || nowNode["parameters"]["codeMode"] >= 5 && nowNode["parameters"]["codeMode"] <=6'>
  386. <label>代码/脚本内容(用Field["字段名"]来输入某字段/自定义操作的最新提取/返回值): </label>
  387. <textarea spellcheck=false onkeydown="inputDelete(event)" class="form-control" rows="2" v-model='nowNode["parameters"]["code"]' placeholder="输入JS或系统命令,如:document.body.innerText = '1' 或 python D:/test.py,分别为JS命令和系统命令示例。如选择针对当前循环项的JS脚本,则循环项元素用arguments[0]表示,如arguments[0].style.color = 'blue'"></textarea>
  388. <pre class="form-control" style="background: white; margin-top: 20px; min-height: 200px; font-size: 15px!important; word-wrap: break-word; white-space: pre-wrap; border-radius: 0; border: 1px solid" disabled v-if='nowNode["parameters"]["codeMode"] == 5'>请先阅读此说明,再在上方输入框(不是本框)写具体代码,如果要执行大量代码,可以直接写outside:myCode.py,这样程序就会读取并执行EasySpider目录下的myCode.py中的代码。
  389. 注意包含exec和eval操作的语句和XPath不能在当前页面试运行,只能在任务真正调用时运行。
  390. 此选项为高级功能,可以直接用Python代码操纵正在运行中的浏览器,及可以自定义整个执行环境中的变量,并对变量进行修改赋值等操作,示例:
  391. 1. 用self.browser表示当前操作的浏览器,可直接用selenium的API进行操作,如self.browser.find_element(By.CSS_SELECTOR, "body").send_keys(Keys.END)即可滚动到页面最下方。
  392. 2. 自定义一个全局变量:self.myVar = 1
  393. 3. 操纵上面定义的全局变量:self.myVar = self.myVar + 1
  394. 4. 打印上面定义的全局变量:print(self.myVar)
  395. 5. 将自定义变量的值赋值为某个字段提取的值:self.myVar = self.outputParameters["字段名"]
  396. 如果想要将自己定义的变量作为字段记录,请选择下一个“在执行环境下获得Python表达式值(eval操作)”选项。
  397. 6. 如果想要引入并使用程序本身没有带的第三方库,需要先使用如pip等工具本地安装好此库,然后在import之前添加自己安装的库的路径,如:
  398. (1)在系统命令行执行安装emotlib库命令:
  399. pip install emotlib
  400. (2)在代码框中写入如下代码:
  401. sys.path.append("D:/Python38/Lib/site-packages") # 假设此路径下有emotlib库
  402. import emotlib # 此时就可以使用emotlib库了
  403. print(emotlib.emoji()) # 使用其中的函数。
  404. </pre>
  405. <pre class="form-control" style="background: white; margin-top: 20px; min-height: 200px; font-size: 15px!important; word-wrap: break-word; white-space: pre-wrap; border-radius: 0; border: 1px solid" disabled v-if='nowNode["parameters"]["codeMode"] == 6'>请先阅读此说明,再在上方输入框(不是本框)写具体代码,如果要执行大量代码,可以直接写outside:myCode.py,这样程序就会读取并执行EasySpider目录下的myCode.py中的代码。
  406. 此选项为高级功能,可以直接返回Python代码的表达式值,并在其他位置用Field["本操作名称"]表示此操作返回值,示例:
  407. 1. 返回当前浏览器对象的相关值,用self.browser表示当前操作的浏览器,可直接用selenium的API进行操作,如self.browser.find_element(By.CSS_SELECTOR, "body").text即可返回当前页面的文字。
  408. 2. 返回自定义全局变量的值:self.myVar
  409. 3. 返回条件判断的值:self.myVar == 1
  410. 4. 判断某个字段提取的值是否等于某个变量的值:self.outputParameters["字段名"] == self.myVar
  411. 注意此功能不能对变量进行赋值操作,即不可以写self.myVar = 1这种,如果想要进行赋值操作,请选择上一个“在执行环境下运行Python代码(exec操作)”选项。</pre>
  412. <p style="margin-top: 15px">是否将执行后的输出/返回值作为字段记录:</p>
  413. <p><select v-model='nowNode["parameters"]["recordASField"]' class="form-control">
  414. <option :value = 0>否(仍可在任意操作中用Field["操作名"]表示此命令返回值)</option>
  415. <option :value = 1>是(JavaScript脚本需要以return 开头)</option>
  416. </select></p>
  417. <p><label>参数类型转换为:</label>
  418. <select v-model='nowNode["parameters"]["paraType"]' class="form-control">
  419. <option value = "text">文本(单个值长度预估超过1万请选择大文本)</option>
  420. <option value = "int">整数(位数在9位以内)</option>
  421. <option value = "double">浮点数(小数)</option>
  422. <option value = "mediumText">大文本(单个值长度超过1万低于100万)</option>
  423. <option value = "datetime">日期时间</option>
  424. <option value = "date">日期</option>
  425. <option value = "time">时间</option>
  426. <option value = "varchar">小文本(单个值长度小于50)</option>
  427. <option value = "longText">超大文本(单个值长度超过100万)</option>
  428. <option value = "bigInt">大整数(位数超过9位)</option>
  429. </select>
  430. </p>
  431. <p>
  432. <label>记录前清空其他操作字段已记录的值:</label>
  433. <select v-model='nowNode["parameters"]["clear"]' class="form-control">
  434. <option :value = 0>否</option>
  435. <option :value = 1>是</option>
  436. </select>
  437. </p>
  438. <p>
  439. <label>此提取数据操作后生成新数据行:</label>
  440. <select v-model='nowNode["parameters"]["newLine"]' class="form-control">
  441. <option :value = 1>是</option>
  442. <option :value = 0>否</option>
  443. </select>
  444. </p>
  445. <label>最长等待脚本执行时间(0代表无限等待): </label>
  446. <input spellcheck=false onkeydown="inputDelete(event)" required class="form-control" type="number" v-model.number='nowNode["parameters"]["waitTime"]'></input>
  447. </div>
  448. <div v-if='nowNode["parameters"]["codeMode"] == 7'>
  449. <label>此操作可以暂停程序执行,如检测到验证码框出现时暂停执行,直到手动长按键盘自定义暂停/继续快捷键(默认:p键)后才继续执行。</label>
  450. </div>
  451. <div v-if='nowNode["parameters"]["codeMode"] == 8'>
  452. <label>此操作可以刷新当前页面。</label>
  453. </div>
  454. <div v-if='nowNode["parameters"]["codeMode"] == 9'>
  455. <label>此操作可以发送邮件,如用于爬虫任务完成后发送邮件通知。</label>
  456. <label>STMP邮件服务器主机:</label>
  457. <input spellcheck=false onkeydown="inputDelete(event)" class="form-control" v-model='nowNode["parameters"]["emailConfig"]["host"]' placeholder="如smtp.163.com"></input>
  458. <label>邮件服务器端口:</label>
  459. <input spellcheck=false onkeydown="inputDelete(event)" class="form-control" v-model='nowNode["parameters"]["emailConfig"]["port"]' placeholder="如465"></input>
  460. <label>发件人邮箱用户名:</label>
  461. <input spellcheck=false onkeydown="inputDelete(event)" class="form-control" v-model='nowNode["parameters"]["emailConfig"]["username"]'></input>
  462. <label>发件人邮箱密码(设置了密码注意不要轻易泄露任务文件!):</label>
  463. <input spellcheck=false onkeydown="inputDelete(event)" class="form-control" v-model='nowNode["parameters"]["emailConfig"]["password"]' placeholder="多数邮箱服务器为授权码而不是原密码"></input>
  464. <label>收件人邮箱地址:</label>
  465. <input spellcheck=false onkeydown="inputDelete(event)" class="form-control" v-model='nowNode["parameters"]["emailConfig"]["to"]' placeholder="多个收件人用英文逗号隔开"></input>
  466. <label>邮件主题:</label>
  467. <input spellcheck=false onkeydown="inputDelete(event)" class="form-control" v-model='nowNode["parameters"]["emailConfig"]["subject"]' placeholder="这里写邮件主题"></input>
  468. <label>邮件内容:</label>
  469. <textarea spellcheck=false onkeydown="inputDelete(event)" class="form-control" rows="2" v-model='nowNode["parameters"]["emailConfig"]["content"]' placeholder="这里写邮件内容"></textarea>
  470. </div>
  471. </div>
  472. <div class="elements" v-if="nodeType==6">
  473. <p><input spellcheck=false onkeydown="inputDelete(event)" type="checkbox" v-model='nowNode["parameters"]["iframe"]'></input>元素在iframe内</p>
  474. <div v-if="nowNode['isInLoop']">
  475. <!-- 如果在循环内且循环内是固定文本才显示此行元素 -->
  476. <p><input spellcheck=false onkeydown="inputDelete(event)" type="checkbox" v-model='useLoop'></input>使用循环内的索引值(不勾选则输入为下方“设定值”文本框内的内容,勾选后会使用所在“文本列表”循环内设置的下拉框索引值)</p>
  477. <p v-if="useLoop">
  478. <label>相对循环内文本索引值(0表示使用整个当前循环的文本当做索引值,如果大于0则表示当前循环的文本用~来分割开的文本索引取值,即如果当前循环的文本值为2~3,这里填写2,则表示取文本第二项,即取值3,表示设置下拉框为第3项)</label>
  479. <input spellcheck=false onkeydown="inputDelete(event)" class="form-control" type="number" v-model.number='nowNode["parameters"]["index"]'></input></p>
  480. </p>
  481. </div>
  482. <label>XPath: </label>
  483. <textarea spellcheck=false onkeydown="inputDelete(event)" class="form-control" rows="2" v-model='nowNode["parameters"]["xpath"]'></textarea>
  484. <p><button type="button" data-toggle="modal" data-target="#myModal_XPath" @click="changeXPaths(nowNode['parameters']['allXPaths'])" class="btn btn-primary" style="margin-top: 10px">点此查看其他等价的XPath</button></p>
  485. <div v-if="!useLoop">
  486. <p>切换模式</p>
  487. <select class="form-control" v-model='nowNode["parameters"]["optionMode"]'>
  488. <option :value=0>切换到下一个选项</option>
  489. <option :value=1>按索引值切换选项(第一个选项索引值为0)</option>
  490. <option :value=2>按选项值切换选项</option>
  491. <option :value=3>按选项文本切换选项</option>
  492. </select>
  493. <p>设定值(不适用于切换到下一个选项模式)</p>
  494. <input spellcheck=false class="form-control" id="selectValue" v-model='nowNode["parameters"]["optionValue"]' autoFocus="autofocus" type="text"></input>
  495. </div>
  496. </div>
  497. <div class="elements" v-if="nodeType==7">
  498. <p><input spellcheck=false onkeydown="inputDelete(event)" type="checkbox" v-model='nowNode["parameters"]["iframe"]'></input>元素在iframe内</p>
  499. <div v-if="nowNode['isInLoop']">
  500. <!-- 如果在循环内才显示此行元素 -->
  501. <p><input spellcheck=false onkeydown="inputDelete(event)" type="checkbox" v-model='useLoop'></input>使用相对循环内的XPath定位的元素</p>
  502. </div>
  503. <div>
  504. <label>XPath: </label>
  505. <textarea spellcheck=false onkeydown="inputDelete(event)" class="form-control" rows="2" v-model='xpath'></textarea>
  506. <p><button type="button" data-toggle="modal" data-target="#myModal_XPath" @click="changeXPaths(nowNode['parameters']['allXPaths'])" class="btn btn-primary" style="margin-top: 10px">点此查看其他等价的XPath</button></p>
  507. <label>任务运行时最终定位的本元素XPath:</label>
  508. <textarea v-model="getFinalXPath(nowNode['parameters']['xpath'], useLoop)" spellcheck=false onkeydown="inputDelete(event)" class="form-control" rows="2" readonly style="background:ghostwhite"></textarea>
  509. </div>
  510. </div>
  511. <div class="elements" v-if="nodeType==8">
  512. <p><input spellcheck=false onkeydown="inputDelete(event)" type="checkbox" v-model='nowNode["parameters"]["iframe"]'></input>在iframe内操作</p>
  513. <!-- 循环选项 -->
  514. <label>循环类型:</label>
  515. <select v-model='loopType' class="form-control" @change="handleLoopTypeChange">
  516. <option :value = 0>单个元素(多用于循环点击下一页)</option>
  517. <option :value = 1>不固定元素列表</option>
  518. <option :value = 2>固定元素列表</option>
  519. <option :value = 3>文本列表(多用于循环在文本框输入文本)</option>
  520. <option :value = 4>网址列表(多用于循环打开网页)</option>
  521. <option :value = 5>JavaScript命令返回值(需以return 开头)</option>
  522. <option :value = 6>系统命令返回值</option>
  523. <option :value = 7>执行环境下的Python表达式值(eval操作)</option>
  524. </select>
  525. <div v-if='parseInt(loopType) < 2'>
  526. <label>XPath: <span style="font-size: 30px!important;" title="相对XPATH写法:以/开头,如循环项XPATH为/html/body/div[1],您的输入为/*[@id='tab-customer'],则最终寻址的xpath为:/html/body/div[1]/*[@id='tab-customer']">☺</span></label>
  527. <textarea spellcheck=false onkeydown="inputDelete(event)" class="form-control" rows="2" placeholder="循环里的XPath不能用@href或者text()这种写法,只能定位元素不能取属性值,即@href和text()这种写法只在提取数据操作中支持,并且不推荐,建议直接在提取数据操作中选择节点类型和采集内容类型。" v-model='nowNode["parameters"]["xpath"]'></textarea>
  528. <p><button type="button" data-toggle="modal" data-target="#myModal_XPath" @click="changeXPaths(nowNode.parameters['allXPaths'])" class="btn btn-primary" style="margin-top: 10px">(测试功能)点此查看其他可能的XPath写法</button></p>
  529. </div>
  530. <div v-else-if='parseInt(loopType) == 2'>
  531. <label>XPath列表:</label>
  532. <textarea spellcheck=false onkeydown="inputDelete(event)" class="form-control" rows="3" placeholder="每行一个XPath,循环里的XPath不能用@href或者text()这种写法,只能定位元素不能取属性值,即@href和text()这种写法只在提取数据操作中支持,并且不推荐,建议直接在提取数据操作中选择节点类型和采集内容类型。" v-model='nowNode["parameters"]["pathList"]'></textarea>
  533. </div>
  534. <div v-else-if='parseInt(loopType) < 5'>
  535. <label>内容列表(用Field["字段名"]来输入某字段/自定义操作的最新提取/返回值):</label>
  536. <textarea spellcheck=false onkeydown="inputDelete(event)" class="form-control" rows="3" placeholder="每行一个文本/网址,用~来分割文字,即如果某行值为A~B,则在输入文字操作中可以设定索引值为1表示输入A,2表示输入B,0表示输入A~B" v-model='nowNode["parameters"]["textList"]'></textarea>
  537. </div>
  538. <div v-else-if='parseInt(loopType) < 8'>
  539. <label>代码/脚本内容(用Field["字段名"]来输入某字段/自定义操作的最新提取/返回值): </label>
  540. <textarea spellcheck=false onkeydown="inputDelete(event)" class="form-control" rows="3" v-model='nowNode["parameters"]["code"]' placeholder="命令返回值大于0或为真则继续循环,否则停止循环。如:return document.body.scrollWidth > 1000 或 python D:/test.py,分别为JS命令和系统命令返回值示例。"></textarea>
  541. <pre class="form-control" style="background: white; margin-top: 20px; min-height: 220px; font-size: 15px!important; word-wrap: break-word; white-space: pre-wrap; border-radius: 0; border: 1px solid" disabled v-if='parseInt(loopType) == 7'>请先阅读此说明,再在上方输入框(不是本框)写具体代码,如果要执行大量代码,可以直接写outside:myCode.py,这样程序就会读取并执行EasySpider目录下的myCode.py中的代码。
  542. 根据Python代码的表达式值来决定是否循环,示例:
  543. 1. 返回当前浏览器对象的相关值,用self.browser表示当前操作的浏览器,可直接用selenium的API进行操作,如self.browser.find_element(By.CSS_SELECTOR, "body").text=="123",表示判断当前页面是否为123这个文本。
  544. 2. 返回自定义全局变量的值:self.myVar,如果
  545. 3. 返回条件判断的值:self.myVar == 1
  546. 4. 判断某个字段提取的值是否等于某个变量的值:self.outputParameters["字段名"] == self.myVar
  547. 以上表达式返回值大于0或为真则继续循环,否则停止循环。
  548. </pre>
  549. <label>最长等待脚本执行时间(0代表无限等待): </label>
  550. <input spellcheck=false onkeydown="inputDelete(event)" required class="form-control" type="number" v-model.number='nowNode["parameters"]["waitTime"]'></input>
  551. </div>
  552. <!-- 这里添加退出循环条件,找不到元素肯定退出循环 -->
  553. <div v-if='parseInt(loopType) == 0'>
  554. <label>最多执行循环次数(0代表无限循环直到找不到元素或检测不到页面元素内容变化为止):</label>
  555. <input spellcheck=false onkeydown="inputDelete(event)" required class="form-control" type="number" v-model.number='nowNode["parameters"]["exitCount"]'></input>
  556. <label>检测页面以下元素内容不变化时退出循环(次数为0时生效,如果是多层嵌套iframe,建议写一个只有要提取的iframe页面内才有的元素的XPath,如/html/body/div[@class='LeftSide_menu']):</label>
  557. <input spellcheck=false onkeydown="inputDelete(event)" required class="form-control" type="text" v-model='nowNode["parameters"]["exitElement"]'></input>
  558. </div>
  559. <div id="breakAdvanced" v-if='nowNode["parameters"]["loopType"] < 5'>
  560. <div>
  561. <p><label>(自定义操作)使用代码/脚本定义循环退出条件(也可以在流程中添加<b>自定义操作</b>,然后选择<b>退出循环</b>选项): </label></p>
  562. <select v-model='nowNode["parameters"]["breakMode"]' class="form-control" style="font-weight: bold">
  563. <option :value = 0>不设置脚本(选择这个下面写了脚本也不会执行)</option>
  564. <option :value = 1>JavaScript脚本返回值(需以return 开头)</option>
  565. <option :value = 2>操作系统级别命令</option>
  566. </select>
  567. <div>
  568. <textarea spellcheck=false style="margin-top: 10px" onkeydown="inputDelete(event)" class="form-control" rows="2"
  569. placeholder='命令返回值小于等于0或为假时则直接退出循环,不管其他条件如何。如:document.evaluate("//div[1]/a", document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue == null 或 python D:/test.py,分别为JS命令(判断某元素是否存在)和系统命令返回值示例。' v-model='nowNode["parameters"]["breakCode"]'></textarea>
  570. <label>最长等待脚本执行时间(0代表无限等待):</label>
  571. <input spellcheck=false onkeydown="inputDelete(event)" required class="form-control" type="number" v-model.number='nowNode["parameters"]["breakCodeWaitTime"]'></input>
  572. </div>
  573. </div>
  574. </div>
  575. <div v-if="parseInt(loopType) < 5 && parseInt(loopType) > 0">
  576. <label>跳过前几次循环(如要跳过前2个循环则填写2):</label>
  577. <input spellcheck=false onkeydown="inputDelete(event)" required class="form-control" type="number" v-model.number='nowNode["parameters"]["skipCount"]'></input>
  578. </div>
  579. <label><b>历史记录回退后</b>等待秒数:</label>
  580. <input spellcheck=false onkeydown="inputDelete(event)" required type="number" class="form-control" v-model.number='list.nl[index.nowNodeIndex]["parameters"]["historyWait"]'></input>
  581. <label>执行完是否向下滚动:</label>
  582. <select v-model='nowNode["parameters"]["scrollType"]' class="form-control">
  583. <option :value = 0>不滚动</option>
  584. <option :value = 1>向下滚动一屏</option>
  585. <option :value = 2>滚动到底部</option>
  586. <option :value = 3>一直滚动直到页面内容无变化(需设置好滚动后的等待时间用于检测页面变化)</option>
  587. </select>
  588. <label>滚动次数(滚动类型设置为<b>不滚动</b>或<b>一直滚动</b>时请忽略此项):</label>
  589. <input spellcheck=false onkeydown="inputDelete(event)" class="form-control" v-model.number="nowNode['parameters']['scrollCount']" type="number" required></input>
  590. <label>滚动后等待时间(秒):</label>
  591. <input spellcheck=false onkeydown="inputDelete(event)" class="form-control" v-model.number="nowNode['parameters']['scrollWaitTime']" type="number" required></input>
  592. </div>
  593. <div class="elements" v-if="nodeType==9">
  594. <label>判断条件是从左往右判断的,即如果最左边的条件分支的判断条件满足,则执行最左边分支内的操作,否则判断从左向右第二个分支的条件是否满足,以此类推。设计任务时点击分支即可在浏览器中<b>动态调试</b>分支是否满足(不适用于系统命令和Python Eval操作)。</label>
  595. </div>
  596. <div class="elements" v-if="nodeType==10">
  597. <label>判断条件是从左往右判断的,即如果最左边的条件分支的判断条件满足,则执行最左边分支内的操作,否则判断从左向右第二个分支的条件是否满足,以此类推。设计任务时点击分支即可在浏览器中<b>动态调试</b>分支是否满足(不适用于系统命令和Python Eval操作)。</label>
  598. <p><input spellcheck=false onkeydown="inputDelete(event)" type="checkbox" v-model='nowNode["parameters"]["iframe"]'></input>在iframe内操作</p>
  599. <label>条件类型:</label>
  600. <select v-model='TClass' class="form-control" @change="handleJudgeTypeChange">
  601. <option :value = 0>无条件</option>
  602. <option :value = 1>当前页面包括文本</option>
  603. <option :value = 2>当前页面包括元素</option>
  604. <option v-if="nowNode['isInLoop']" :value = 3>当前循环项包括文本</option>
  605. <option v-if="nowNode['isInLoop']" :value = 4>当前循环项包括元素</option>
  606. <option :value = 5>JavaScript命令返回值(需以return 开头)</option>
  607. <option :value = 6>系统命令返回值</option>
  608. <option v-if="nowNode['isInLoop']" :value = 7>针对当前循环项的JavaScript命令返回值(需以return 开头)</option>
  609. <option :value = 8>执行环境下的Python表达式值(eval操作)</option>
  610. </select>
  611. <div v-if='TClass > 0 && TClass < 5'>
  612. <label>包含的文字/元素XPATH: <span style="font-size: 30px!important;" title="相对XPATH写法:以/开头,如循环项XPATH为/html/body/div[1],您的输入为/*[@id='tab-customer'],则最终寻址的xpath为:/html/body/div[1]/*[@id='tab-customer']">☺</span></label>
  613. <textarea spellcheck=false onkeydown="inputDelete(event)" required placeholder="如果是当前循环包含元素,则输入相对元素的xpath(如/div[2]/div[1]/img,如果写相对路径,需要写成/*//img,即检测当前循环项所有的子孙元素是否存在img标签)。" class="form-control" rows="3" v-model='nowNode["parameters"]["value"]'></textarea>
  614. </div>
  615. <div v-else-if='TClass > 0 && TClass < 7 || TClass == 8'>
  616. <label>代码/脚本内容(用Field["字段名"]来输入某字段/自定义操作的最新提取/返回值): </label>
  617. <textarea spellcheck=false onkeydown="inputDelete(event)" class="form-control" rows="3" v-model='nowNode["parameters"]["code"]' placeholder="命令返回值大于0或为真则执行此分支内操作,否则不执行。如:return document.body.scrollWidth > 1000 或 python D:/test.py,分别为JS命令和系统命令返回值示例。"></textarea>
  618. <pre class="form-control" style="background: white; margin-top: 20px; min-height: 200px; font-size: 15px!important; word-wrap: break-word!important; white-space: pre-wrap; border-radius: 0; border: 1px solid" disabled v-if='TClass == 8'>请先阅读此说明,再在上方输入框(不是本框)写具体代码,如果要执行大量代码,可以直接写outside:myCode.py,这样程序就会读取并执行EasySpider目录下的myCode.py中的代码。
  619. 根据Python代码的表达式值来判断条件是否满足,示例:
  620. 1. 返回当前浏览器对象的相关值,用self.browser表示当前操作的浏览器,可直接用selenium的API进行操作,如self.browser.find_element(By.CSS_SELECTOR, "body").text=="123",表示判断当前页面是否为123这个文本。
  621. 2. 返回自定义全局变量的值:self.myVar,如果
  622. 3. 返回条件判断的值:self.myVar == 1
  623. 4. 判断某个字段提取的值是否等于某个变量的值:self.outputParameters["字段名"] == self.myVar
  624. 以上表达式返回值大于0或为则执行此分支内操作,否则不执行。
  625. </pre>
  626. <label>最长等待脚本执行时间(0代表无限等待): </label>
  627. <input spellcheck=false onkeydown="inputDelete(event)" required class="form-control" type="number" v-model.number='nowNode["parameters"]["waitTime"]'></input>
  628. </div>
  629. <div v-else-if='TClass == 7'>
  630. <label>代码/脚本内容(<a href="https://github.com/NaiboWang/EasySpider/wiki/Example-of-JavaScript-instruction-for-the-current-iteration-in-a-conditional-statement" target="_blank">点击此处</a>查看更多示例): </label>
  631. <textarea spellcheck=false onkeydown="inputDelete(event)" class="form-control" rows="3" v-model='nowNode["parameters"]["code"]' placeholder="输入针对该循环项的JS命令,该循环项用arguments[0]表示,返回值大于0或为真则执行此分支内操作,否则不执行。如:return arguments[0].innerText.length >5 即判断当前循环项的文本长度是否大于5,注意要配合循环类型为元素相关(如不固定元素列表)使用。"></textarea>
  632. <label>最长等待脚本执行时间(0代表无限等待): </label>
  633. <input spellcheck=false onkeydown="inputDelete(event)" required class="form-control" type="number" v-model.number='nowNode["parameters"]["waitTime"]'></input>
  634. </div>
  635. </div>
  636. <div style="margin-top:5px">
  637. <label>操作<b>执行前</b>等待以下元素出现:</label>
  638. <textarea spellcheck=false onkeydown="inputDelete(event)" class="form-control" style="min-height: 30px" v-model='list.nl[index.nowNodeIndex]["parameters"]["waitElement"]'
  639. placeholder="填写要等待出现元素的XPath,不填写则不等待"></textarea>
  640. <label style="margin-top:5px">要等待的元素在页面第几个iframe中,0表示元素不在iframe中:</label>
  641. <input spellcheck=false onkeydown="inputDelete(event)" class="form-control" v-model.number="list.nl[index.nowNodeIndex]['parameters']['waitElementIframeIndex']" type="number" required></input>
  642. <label style="margin-top:5px">元素出现的最长等待时间(秒):</label>
  643. <input spellcheck=false onkeydown="inputDelete(event)" class="form-control" v-model.number="list.nl[index.nowNodeIndex]['parameters']['waitElementTime']" type="number" required></input>
  644. <div v-if="nodeType!=10">
  645. <label style="margin-top:5px">操作<b>执行后</b>等待秒数(所有等待时间均可设置为小数,如0.5):</label>
  646. <input spellcheck=false onkeydown="inputDelete(event)" required type="number" class="form-control" v-model.number='list.nl[index.nowNodeIndex]["parameters"]["wait"]'></input>
  647. <label style="margin-top:5px">等待类型</label>
  648. <select v-model='list.nl[index.nowNodeIndex]["parameters"]["waitType"]' class="form-control">
  649. <option :value = 0>固定等待(设置等10秒就等10秒)</option>
  650. <option :value = 1>随机等待(设置等10秒会随机等10×0.5 - 10 × 1.5 秒)</option>
  651. </select>
  652. </div>
  653. </div>
  654. <!-- <button class="btn btn-outline-primary" style="margin-top: 20px;" id="confirm">确定</button>-->
  655. </div>
  656. </div>
  657. </div>
  658. <div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
  659. <div class="modal-dialog modal-xl">
  660. <div class="modal-content">
  661. <div class="modal-header">
  662. <h4 class="modal-title" id="myModalLabel">保存任务(可按Ctrl+S调出此窗口)</h4>
  663. <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
  664. </div>
  665. <div class="modal-body" style="height:60vh;overflow: auto">
  666. <input spellcheck=false onkeydown="inputDelete(event)" id="serviceId" type="hidden" name="serviceId" value="-1"></input>
  667. <input spellcheck=false onkeydown="inputDelete(event)" id="url" type="hidden" name="url" value="about:blank"></input>
  668. <input spellcheck=false id="create_time" type="hidden"></input>
  669. <label>任务名称:</label>
  670. <input spellcheck=false onkeydown="inputDelete(event)" required name="serviceName" value="新web采集任务" id="serviceName" class="form-control"></input>
  671. <label>任务描述:</label>
  672. <input spellcheck=false onkeydown="inputDelete(event)" id="serviceDescription" name="serviceDescription" class="form-control"></input>
  673. <label>导出数据格式(Excel/CSV/TXT/数据库,<a href="https://www.bilibili.com/video/BV1os4y1679S/" target="_blank">查看MySQL操作教程</a>):</label>
  674. <select id="outputFormat" class="form-control">
  675. <option value = "xlsx">XLSX(即EXCEL文件,建议单个单元格长度超过500时使用CSV格式存储)</option>
  676. <option value = "csv">CSV(采集长文章推荐使用此格式)</option>
  677. <option value = "txt">TXT</option>
  678. <option value = "json">JSON</option>
  679. <option value = "mysql">MySQL数据库(大量数据推荐使用)</option>
  680. </select>
  681. <label>导出文件名/数据库表格名称(可使用../表示相对路径以改变文件保存位置,名称中的“current_time”会被替换为执行任务时的时间戳):</label>
  682. <input spellcheck=false onkeydown="inputDelete(event)" value="current_time" id="saveName" class="form-control"></input>
  683. <label>数据写入模式(上方导出文件名/数据库表格名称需固定,同一个任务ID多次执行时生效):</label>
  684. <select id="dataWriteMode" name="dataWriteMode" class="form-control">
  685. <option value=1>追加写入(如果文件已存在则在原文件后面追加)</option>
  686. <option value=2>覆盖写入(如果文件已存在则覆盖原文件)</option>
  687. <option value=3>重命名写入(如果文件已存在则重命名文件)</option>
  688. </select>
  689. <!-- <label>是否为Cloudflare等极端反爬网站(<a href="https://www.bilibili.com/video/BV1Ph4y1E7R9/" target="_blank">查看Cloudflare设计和执行教程</a>):</label>-->
  690. <!-- <select id="cloudflare" name="cloudflare" class="form-control">-->
  691. <!-- <option value = 0>否</option>-->
  692. <!-- <option value = 1>是(只支持Windows x64系统)</option>-->
  693. <!-- </select>-->
  694. <label>执行完成后是否去除重复数据(注意此功能需要等到任务结束时执行,因此执行任务中途退出将无法进行去重):</label>
  695. <select id="removeDuplicate" name="removeDuplicate" class="form-control">
  696. <option value = 0>否</option>
  697. <option value = 1>是(注意上方文件名应该为固定名称而不是current_time,同时每次执行任务时的执行ID要为同一个)</option>
  698. </select>
  699. <label>执行时通过读取以下Excel(.xlsx)文件来修改各个操作的输入参数,文件格式请在调用任务时点击“从Excel文件读取输入参数”按钮查看:</label>
  700. <input spellcheck=false onkeydown="inputDelete(event)" id="inputExcel" name="inputExcel" class="form-control" placeholder="为空则不从Excel读取输入参数,文件路径相对于EasySpider文件夹,如inputs/task1.xlsx"></input>
  701. <label>浏览器模拟类型:</label>
  702. <select id="environment" name="environment" class="form-control">
  703. <option value = 0>电脑端</option>
  704. <option value = 1>手机端</option>
  705. </select>
  706. <label>是否最大化浏览器窗口:</label>
  707. <select id="maximizeWindow" name="maximizeWindow" class="form-control">
  708. <option value = 0>否</option>
  709. <option value = 1>是</option>
  710. </select>
  711. <label>每采集多少条数据保存一次(值越大采集速度越快,但如果意外退出则有数据丢失风险):</label>
  712. <input spellcheck=false onkeydown="inputDelete(event)" type="number" value="10" id="saveThreshold" name="saveThreshold" class="form-control"></input>
  713. <label>是否要意外退出并重新执行任务时从上次保存的位置继续执行(已采集条数记录间隔为上面设置的值):</label>
  714. <select id="startFromExit" name="startFromExit" class="form-control">
  715. <option value = 0>否</option>
  716. <option value = 1>是(需要运行同一个任务ID和固定的文件名,请用命令行执行并指定ID)</option>
  717. </select>
  718. <label>任务执行完毕后自动关闭浏览器等待秒数(用户信息临时目录将在浏览器关闭后自动删除):</label>
  719. <input spellcheck=false onkeydown="inputDelete(event)" type="number" value="60" id="quitWaitTime" name="quitWaitTime" class="form-control"></input>
  720. <label>控制台预览时数据最大显示长度:</label>
  721. <input spellcheck=false onkeydown="inputDelete(event)" type="number" value="15" id="maxViewLength" class="form-control"></input>
  722. <label>任务执行时是否记录日志:</label>
  723. <select id="recordLog" name="recordLog" class="form-control">
  724. <option value = 1>是</option>
  725. <option value = 0>否</option>
  726. </select>
  727. <label>任务暂停/继续快捷键:</label>
  728. <input spellcheck=false onkeydown="inputDelete(event)" type="text" value="p" id="pauseKey" class="form-control"></input>
  729. <input type="hidden" id="browser" name="browser" value="chrome"></input>
  730. </div>
  731. <div class="modal-footer">
  732. <button type="button" id="saveAsButton" style="width: 100px" class="btn btn-outline-primary">另存为</button>
  733. <button type="button" id="saveButton" style="width: 100px" class="btn btn-primary">保存</button>
  734. </div>
  735. </div>
  736. <!-- /.modal-content -->
  737. </div>
  738. <!-- /.modal -->
  739. </div>
  740. </body>
  741. <script src="FlowChart.js"></script>
  742. <script src="global.js"></script>
  743. <script src="logic.js"></script>
  744. <script>
  745. var navigator = new Vue({
  746. el: '#navigator',
  747. data: {
  748. type: getUrlParam("type"),
  749. backEndAddressServiceWrapper: getUrlParam("backEndAddressServiceWrapper"),
  750. },
  751. methods:{
  752. gotoHome: function () {
  753. let url = "";
  754. if (getUrlParam("lang") == "zh") {
  755. url = "taskList.html?lang=zh&type="+getUrlParam("type")+"&wsport="+getUrlParam("wsport")+"&backEndAddressServiceWrapper=" + this.backEndAddressServiceWrapper
  756. } else {
  757. url = "taskList.html?lang=en&type="+getUrlParam("type")+"&wsport="+getUrlParam("wsport")+"&backEndAddressServiceWrapper=" + this.backEndAddressServiceWrapper
  758. }
  759. window.location.href = url;
  760. }, gotoInfo: function () {
  761. let url = "";
  762. if (getUrlParam("lang") == "zh") {
  763. url = "taskInfo.html?id="+getUrlParam("id")+"&lang=zh&type="+getUrlParam("type")+"&wsport="+getUrlParam("wsport")+"&backEndAddressServiceWrapper=" + this.backEndAddressServiceWrapper
  764. } else {
  765. url = "taskInfo.html?id="+getUrlParam("id")+"&lang=en&type="+getUrlParam("type")+"&wsport="+getUrlParam("wsport")+"&backEndAddressServiceWrapper=" + this.backEndAddressServiceWrapper
  766. }
  767. window.location.href = url;
  768. }
  769. }
  770. });
  771. </script>
  772. </html>