依涵学习通作业助手

开发中,目前支持新版学习通作业和老版考试答题功能,新增老版界面自动讨论功能,第一遍答题后会请求第二个接口答题,实现答题率在95%以上;

目前为 2021-12-17 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name 依涵学习通作业助手
  3. // @namespace https://www.yihanstudio.com/
  4. // @version 1.0.5
  5. // @description 开发中,目前支持新版学习通作业和老版考试答题功能,新增老版界面自动讨论功能,第一遍答题后会请求第二个接口答题,实现答题率在95%以上;
  6. // @author ZhouChaoHan
  7. // @match *://*.chaoxing.com/*
  8. // @grant GM_xmlhttpRequest
  9. // @license MIT
  10. // ==/UserScript==
  11.  
  12. var unknowQuestionAnswerArray = []
  13.  
  14. function strSimilarity2Number(s, t) {
  15. var n = s.length,
  16. m = t.length,
  17. d = [];
  18. var i, j, s_i, t_j, cost;
  19. if (n == 0) return m;
  20. if (m == 0) return n;
  21. for (i = 0; i <= n; i++) {
  22. d[i] = [];
  23. d[i][0] = i;
  24. }
  25. for (j = 0; j <= m; j++) {
  26. d[0][j] = j;
  27. }
  28. for (i = 1; i <= n; i++) {
  29. s_i = s.charAt(i - 1);
  30. for (j = 1; j <= m; j++) {
  31. t_j = t.charAt(j - 1);
  32. if (s_i == t_j) {
  33. cost = 0;
  34. } else {
  35. cost = 1;
  36. }
  37. d[i][j] = Minimum(d[i - 1][j] + 1, d[i][j - 1] + 1, d[i - 1][j - 1] + cost);
  38. }
  39. }
  40. return d[n][m];
  41. }
  42.  
  43. function Minimum(a, b, c) {
  44. return a < b ? (a < c ? a : c) : (b < c ? b : c);
  45. }
  46.  
  47. //两字符串相似度匹配
  48. function strSimilarity2Percent(s, t) {
  49. var l = s.length > t.length ? s.length : t.length;
  50. var d = strSimilarity2Number(s, t);
  51. return parseInt((1 - d / l).toFixed(4) * 100);
  52. }
  53.  
  54. function isInArray(ary,str){
  55. for(let i=0;i<ary.length;i++){
  56. if(ary[i].trim() == str.trim()){return true;}
  57. }
  58. return false;
  59. }
  60.  
  61. //单选题选择
  62. function choiseAnswerOptionType1(options,answer){
  63. let fs = 0;
  64. let ary = [];
  65. for (let j = 0; j < options.length; j++) {
  66. let option = $(options[j]); //选项体
  67. let optionName = option.find(".answer_p").text().trim(); //选项文字
  68. optionName = optionName.replace(/[\ |\~|\`|\!|\@|\#|\$|\%|\^|\&|\*|\(|\)|\-|\_|\+|\=|\||\\|\[|\]|\{|\}|\;|\:|\"|\'|\,|\<|\.|\>|\/|\?]/g,"");
  69. answer = answer.replace(/[\ |\~|\`|\!|\@|\#|\$|\%|\^|\&|\*|\(|\)|\-|\_|\+|\=|\||\\|\[|\]|\{|\}|\;|\:|\"|\'|\,|\<|\.|\>|\/|\?]/g,"").trim();
  70. let lsfs = strSimilarity2Percent(optionName, answer);
  71. if (lsfs >= 70 && lsfs > fs) {
  72. fs = lsfs;
  73. ary.push(option);
  74. }
  75. }
  76. if(ary.length == 0){
  77. return false;
  78. }
  79. if(!ary[ary.length-1].find(".check_answer").attr("data")){
  80. ary[ary.length-1].click();
  81. return true;
  82. }else{
  83. return true;
  84. }
  85. return false;
  86. }
  87.  
  88. //多选题选择
  89. function choiseAnswerOptionType2(options,answers){
  90. let choiseNum = 0;
  91. let lsAnswers = answers.replace(/\s/g,"").split("#");
  92. if(lsAnswers.length <= 1){
  93. lsAnswers = answers.replace(/\s/g,"").split(/[^\u4e00-\u9fa5^\w]/g);
  94. }
  95. for(let i=0;i<options.length;i++){
  96. let option = $(options[i]); //选项体
  97. let optionName = option.find(".answer_p").text().trim(); //选项文字
  98. optionName = optionName.replace(/[\ |\~|\`|\!|\@|\#|\$|\%|\^|\&|\*|\(|\)|\-|\_|\+|\=|\||\\|\[|\]|\{|\}|\;|\:|\"|\'|\,|\<|\.|\>|\/|\?]/g,"");
  99. for(let j=0;j<lsAnswers.length;j++){
  100. let answer = lsAnswers[j];//答案
  101. answer = answer.replace(/[\ |\~|\`|\!|\@|\#|\$|\%|\^|\&|\*|\(|\)|\-|\_|\+|\=|\||\\|\[|\]|\{|\}|\;|\:|\"|\'|\,|\<|\.|\>|\/|\?]/g,"").trim();
  102. if(optionName == answer){
  103. if(!option.find(".check_answer_dx").attr("data")){
  104. option.click();
  105. }
  106. choiseNum++;
  107. }
  108. }
  109. }
  110. if(choiseNum > 0){
  111. return true;
  112. }
  113. return false;
  114. }
  115.  
  116. //填空题填空
  117. function writeTextAnswerType3(textareas,answers){
  118. let writeNum = 0;
  119. let lsAnswers = answers.replace(/\s/g,"").split("#");
  120. if(lsAnswers.length <= 1){
  121. lsAnswers = answers.replace(/\s/g,"").split(/[^\u4e00-\u9fa5^\w]/g);
  122. }
  123. if(textareas.length == lsAnswers.length){
  124. for(let i=0;i<textareas.length;i++){
  125. UE.getEditor(textareas[i].name).setContent(lsAnswers[i]);
  126. }
  127. return true;
  128. }
  129. return false;
  130. }
  131.  
  132. //判断题选择
  133. function choiseAnswerOptionType4(options,answer){
  134. let zq = ["正确","是","true","True","T","对","√","ri"];
  135. let cw = ["错误","否","false","False","F","错","×","wr"];
  136. let lsAnswer = null;
  137. if(isInArray(zq,answer.trim())){lsAnswer = true;}
  138. if(isInArray(cw,answer.trim())){lsAnswer = false;}
  139. for (let j = 0; j < options.length; j++) {
  140. let lsOption = null;
  141. let option = $(options[j]); //选项体
  142. let optionName = option.find(".answer_p").text().trim(); //选项文字
  143. if(isInArray(zq,optionName)){lsOption = true;}
  144. if(isInArray(cw,optionName)){lsOption = false;}
  145. if(lsAnswer != null && lsOption != null && lsOption == lsAnswer){
  146. if(!option.find(".check_answer").attr("data")){
  147. option.click();
  148. }
  149. return true;
  150. }else{
  151. continue;
  152. }
  153. }
  154. return false;
  155. }
  156.  
  157. function getAnswer(questionName,isFirst){
  158. return new Promise(res => {
  159. let qType = $(".Cy_TItle").next().val() || '-1';
  160. let courseId = location.search.match(/courseId=(\d+)/i)[1];
  161. let classId= location.search.match(/classId=(\d+)/i)[1];
  162. let knowledgeId=0
  163. try {
  164. knowledgeId= location.search.match(/knowledgeid=(\d+)/i)[1];
  165. } catch (err) {
  166. }
  167. GM_xmlhttpRequest({
  168. method: 'POST',
  169. url: isFirst ? "http://onlinecoursekiller.online/OnlineCourseKiller/killer" : "http://s.jiaoyu139.com:886/get?ua=cx&v=1&keyword="+questionName+"&courseid="+courseId+"&type="+qType+"&classid="+classId+"&knowledgeid="+knowledgeId,
  170. headers: {
  171. 'Content-type': 'application/x-www-form-urlencoded'
  172. },
  173. data: isFirst ? "q=" + questionName : "",
  174. timeout: 5000,
  175. onload: function(xhr) {
  176. if (xhr.status == 200) {
  177. if(isFirst == true){
  178. let answer = JSON.parse(xhr.response);
  179. if (answer.success === "true") {
  180. $('<tr>' +
  181. '<td style="border: 1px solid;">0</td>' +
  182. '<td style="border: 1px solid;">' + questionName + '</td>' +
  183. '<td style="border: 1px solid;">' + answer.answer + '</td>' +
  184. '</tr>').appendTo(".question-table-tbody").css('background-color','');
  185. }else{
  186. $('<tr>' +
  187. '<td style="border: 1px solid;">0</td>' +
  188. '<td style="border: 1px solid;">' + questionName + '</td>' +
  189. '<td style="border: 1px solid;">' + answer.answer + '</td>' +
  190. '</tr>').appendTo(".question-table-tbody").css('background-color', 'rgba(200 ,0 ,0, 0.6)');
  191. }
  192. }else{
  193. let answer = JSON.parse(xhr.response);
  194. if (answer.code == 1) {
  195. $('<tr>' +
  196. '<td style="border: 1px solid;">1</td>' +
  197. '<td style="border: 1px solid;">' + questionName + '</td>' +
  198. '<td style="border: 1px solid;">' + answer.data.answer + '</td>' +
  199. '</tr>').appendTo(".question-table-tbody").css('background-color','');
  200. }else{
  201. $('<tr>' +
  202. '<td style="border: 1px solid;">1</td>' +
  203. '<td style="border: 1px solid;">' + questionName + '</td>' +
  204. '<td style="border: 1px solid;">' + answer.data.answer + '</td>' +
  205. '</tr>').appendTo(".question-table-tbody").css('background-color', 'rgba(200 ,0 ,0, 0.6)');
  206. }
  207. }
  208. var divscll = document.getElementById('question-scdiv');
  209. divscll.scrollTop = divscll.scrollHeight;
  210. }else{
  211. getAnswer(questionName,isFirst);
  212. }
  213. setTimeout(() => {
  214. res();
  215. }, 200);
  216. },
  217. ontimeout: function() {
  218.  
  219. }
  220. });
  221. });
  222. }
  223.  
  224. function findAnswer(isFirst,questionName, type, question) {
  225. return new Promise(res => {
  226. let qType = question.find('input[name^=answertype]:eq(0)').val() || '-1';
  227. let courseId = location.search.match(/courseId=(\d+)/i)[1];
  228. let classId= location.search.match(/classId=(\d+)/i)[1];
  229. let knowledgeId=0
  230. try {
  231. knowledgeId= location.search.match(/knowledgeid=(\d+)/i)[1];
  232. } catch (err) {
  233. }
  234. GM_xmlhttpRequest({
  235. method: 'POST',
  236. url: isFirst ? "http://onlinecoursekiller.online/OnlineCourseKiller/killer" : "http://s.jiaoyu139.com:886/get?ua=cx&v=1&keyword="+questionName+"&courseid="+courseId+"&type="+qType+"&workid="+($('#workId').val() || $('#oldWorkId').val())+"&classid="+classId+"&knowledgeid="+knowledgeId,
  237. headers: {
  238. 'Content-type': 'application/x-www-form-urlencoded'
  239. },
  240. data: isFirst ? "q=" + questionName : "",
  241. timeout: 5000,
  242. onload: function(xhr) {
  243. if (xhr.status == 200) {
  244. if(isFirst == true){
  245. let answer = JSON.parse(xhr.response);
  246. if (answer.success === "true") {
  247. let tf = false;
  248. //1.2.4获取选项组
  249. if (type == 1 || type == 2 || type == 4) {
  250. let answerOptions = question.find(".stem_answer .clearfix");
  251. if(type == 1){
  252. tf = choiseAnswerOptionType1(answerOptions,answer.answer);
  253. }else if(type == 2){
  254. tf = choiseAnswerOptionType2(answerOptions,answer.answer);
  255. }else if(type == 4){
  256. tf = choiseAnswerOptionType4(answerOptions,answer.answer);
  257. }
  258. } else if (type == 3) {
  259. //填空题
  260. let textareas = question.find("textarea");
  261. tf = writeTextAnswerType3(textareas,answer.answer);
  262. }
  263. if(tf == false){
  264. $('<tr>' +
  265. '<td style="border: 1px solid;">' + questionName + '</td>' +
  266. '<td style="border: 1px solid;">' + answer.answer + '</td>' +
  267. '</tr>').appendTo(".question-table-tbody").css('background-color', 'rgba(200 ,0 ,0, 0.6)');
  268. question.attr("noGetAnswer","no");
  269. question.css('background-color', 'rgba(200 ,0 ,0, 0.6)');
  270. unknowQuestionAnswerArray.push(question);
  271. }else{
  272. $('<tr>' +
  273. '<td style="border: 1px solid;">' + questionName + '</td>' +
  274. '<td style="border: 1px solid;">' + answer.answer + '</td>' +
  275. '</tr>').appendTo(".question-table-tbody").css('background-color','');
  276. question.css('background-color', 'rgba(0 ,200 ,0, 0.6)');
  277. }
  278. }else{
  279. $('<tr>' +
  280. '<td style="border: 1px solid;">' + questionName + '</td>' +
  281. '<td style="border: 1px solid;">' + answer.answer + '</td>' +
  282. '</tr>').appendTo(".question-table-tbody").css('background-color', 'rgba(200 ,0 ,0, 0.6)');
  283. //未获取到答案
  284. question.attr("noGetAnswer","no");
  285. question.css('background-color', 'rgba(200 ,0 ,0, 0.6)');
  286. unknowQuestionAnswerArray.push(question);
  287. }
  288. }else{
  289. let answer = JSON.parse(xhr.response);
  290. if (answer.code == 1) {
  291. let tf = false;
  292. if (type == 1 || type == 2 || type == 4) {
  293. let answerOptions = question.find(".stem_answer .clearfix");
  294. if(type == 1){
  295. tf = choiseAnswerOptionType1(answerOptions,answer.data.answer);
  296. }else if(type == 2){
  297. tf = choiseAnswerOptionType2(answerOptions,answer.data.answer);
  298. }else if(type == 4){
  299. tf = choiseAnswerOptionType4(answerOptions,answer.data.answer);
  300. }
  301. } else if (type == 3) {
  302. //填空题
  303. let textareas = question.find("textarea");
  304. tf = writeTextAnswerType3(textareas,answer.data.answer);
  305. }
  306. if(tf == true && question.attr("noGetAnswer") == "no"){
  307. question.css('background-color', 'rgba(0 ,200 ,0, 0.6)');
  308. }
  309. }
  310. }
  311. var divscll = document.getElementById('question-scdiv');
  312. divscll.scrollTop = divscll.scrollHeight;
  313. }else{
  314. findAnswer(isFirst,questionName, type, question);
  315. }
  316. setTimeout(() => {
  317. res();
  318. }, 200);
  319. },
  320. ontimeout: function() {
  321.  
  322. }
  323. });
  324. });
  325. }
  326. function getQueryVariable(variable)
  327. {
  328. var query = window.location.search.substring(1);
  329. var vars = query.split("&");
  330. for (var i=0;i<vars.length;i++) {
  331. var pair = vars[i].split("=");
  332. if(pair[0] == variable){return pair[1];}
  333. }
  334. return(false);
  335. }
  336. (async function() {
  337. 'use strict';
  338. var taolunList = [];
  339. var index = 0;
  340. $(document).on("click", "#hideButton", function() {
  341. $(".question-showdiv").show();
  342. $(".question-div").hide();
  343. });
  344. $(document).on("click", "#showButton", function() {
  345. $(".question-div").show();
  346. $(".question-showdiv").hide();
  347. });
  348. $(".clearfix").click(function(){
  349. if($(this).parent().parent().attr("noGetAnswer") == "no"){
  350. $(this).parent().parent().css('background-color', 'rgba(0 ,0 ,0, 0)');
  351. }
  352. });
  353. $(document).on("click",".thisCT",function(){
  354. let div = $(".content1118 .oneRight");
  355. let go = false;
  356. taolunList = [];
  357. for(let i=0;i<div.length;i++){
  358. if(div.eq(i).parent().attr("id") == $(this).parent().attr("id")){
  359. go = true;
  360. }
  361. if(go){
  362. taolunList.push(div.eq(i).find(".bt a"));
  363. }
  364. }
  365. let val = window.open(taolunList[index].attr("href")+"&isFirstJoin=1", "讨论", "height=500, width=1500,top=200");
  366. });
  367.  
  368. var url = location.pathname;
  369. console.log(url);
  370. if (url === "/mooc2/work/dowork") {
  371. console.log("进入作业")
  372. let div = $(
  373. '<div class="question-showdiv" style="display: none;position: fixed;top: ' + $(".subNav")
  374. .height() +
  375. 'px;right: 10px;height: 100px;width: 300px;">' +
  376. '<div style="font-size: medium;">已隐藏</div>' +
  377. '<button id="showButton">取消隐藏</button>' +
  378. '</div>' +
  379. '<div class="question-div" style="position: fixed;top: ' + $(".subNav").height() +
  380. 'px;right: 10px;height: 500px;width: 300px;z-index: 99999;background-color: rgba(190, 231, 233 ,0.9);border: 2px dashed rgb(190 ,231 ,233);">' +
  381. '<div style="font-size: medium;height:20px;" id="question">正在搜索答案...</div>' +
  382. '<button id="hideButton" style="height:20px;">隐藏显示</button>' +
  383. '<div style="max-height: 460px; overflow-y: auto;" id="question-scdiv">'+
  384. '<table border="1" style="font-size: 12px;overflow-y: auto;">' +
  385. '<thead>' +
  386. '<tr>' +
  387. '<th style="width: 60%; min-width: 130px;">题目(点击可复制)</th>' +
  388. '<th style="min-width: 130px;">答案(点击可复制)</th>' +
  389. '</tr>' +
  390. '</thead>' +
  391. '<tbody class="question-table-tbody">' +
  392. '</tbody>' +
  393. '</table>' +
  394. '</div>'+
  395. '</div>'
  396. );
  397. $("body").append(div);
  398. //获取题目组
  399. var questions = $(".questionLi");
  400. if (questions.length === parseInt($(".infoHead span:eq(0)").text().split(':')[1])) {
  401. console.log("共" + questions.length + "题");
  402. for (let i = 0; i < questions.length; i++) {
  403. let question = $(questions[i]); //题目体
  404. let type = 0;
  405. if (question.attr("typename").trim() === "单选题") {
  406. type = 1
  407. } else if (question.attr("typename").trim() === "多选题") {
  408. type = 2
  409. } else if (question.attr("typename").trim() === "填空题") {
  410. type = 3
  411. } else if (question.attr("typename").trim() === "判断题") {
  412. type = 4
  413. }
  414. //获取题目
  415. let questionName = question.find(".mark_name").text(); //题目文字
  416. questionName = questionName.substring(questionName.indexOf(")") + 1).trim();
  417.  
  418. //查找答案
  419. await findAnswer(true, questionName, type, question);
  420. }
  421. if(unknowQuestionAnswerArray.length > 0){
  422. //二次查找答案
  423. for(let i=0;i<unknowQuestionAnswerArray.length;i++){
  424. let question = $(unknowQuestionAnswerArray[i]); //题目体
  425. let type = 0;
  426. if (question.attr("typename").trim() === "单选题") {
  427. type = 1
  428. } else if (question.attr("typename").trim() === "多选题") {
  429. type = 2
  430. } else if (question.attr("typename").trim() === "填空题") {
  431. type = 3
  432. } else if (question.attr("typename").trim() === "判断题") {
  433. type = 4
  434. }
  435. //获取题目
  436. let questionName = question.find(".mark_name").text(); //题目文字
  437. questionName = questionName.substring(questionName.indexOf(")") + 1).trim();
  438. await findAnswer(false, questionName, type, question);
  439. }
  440. }
  441. }
  442. }else if(url === "/exam/test/reVersionTestStartNew"){
  443. console.log("进入考试");
  444. let div = $(
  445. '<div class="question-showdiv" style="display: none;position: fixed;top: 10px;right: 10px;height: 100px;width: 300px;">' +
  446. '<div style="font-size: medium;">已隐藏</div>' +
  447. '<button id="showButton">取消隐藏</button>' +
  448. '</div>' +
  449. '<div class="question-div" style="position: fixed;top: 10px;right: 10px;height: 500px;width: 300px;z-index: 99999;background-color: rgba(190, 231, 233 ,0.9);border: 2px dashed rgb(190 ,231 ,233);">' +
  450. '<div style="font-size: medium;height:20px;" id="question">正在搜索答案...</div>' +
  451. '<button id="hideButton" style="height:20px;">隐藏显示</button>' +
  452. '<div style="max-height: 460px; overflow-y: auto;" id="question-scdiv">'+
  453. '<table border="1" style="font-size: 12px;overflow-y: auto;">' +
  454. '<thead>' +
  455. '<tr>' +
  456. '<th>接口</th>' +
  457. '<th style="width: 60%; min-width: 130px;">题目(点击可复制)</th>' +
  458. '<th style="min-width: 130px;">答案(点击可复制)</th>' +
  459. '</tr>' +
  460. '</thead>' +
  461. '<tbody class="question-table-tbody">' +
  462. '</tbody>' +
  463. '</table>' +
  464. '</div>'+
  465. '</div>'
  466. );
  467. $("body").append(div);
  468. let thisQuestionName = $(".Cy_TItle div:eq(0)").text().trim().replace(/\(.*?\)/g,'').replace(/\(.*?\)/g,'').replace(/([^)]+)/g,'');
  469. getAnswer(thisQuestionName,true);
  470. getAnswer(thisQuestionName,false);
  471. }else if (url === "/bbscircle/grouptopic"){
  472. let ct = $(".content1118");
  473. for(let i=0;i<ct.length;i++){
  474. ct.eq(i).append("<button class='thisCT'>从此处开始</button>");
  475. }
  476. //重写message事件以接受打开表单页面2返回的值
  477. window.onmessage = function (e) {
  478. var data = e.data;
  479. if (data != undefined && data != null) {
  480. console.log(data);
  481. if(data == "close"){
  482. index += 1;
  483. if(index == taolunList.length){
  484. alert("讨论回答完毕!");
  485. return;
  486. }
  487. if(!taolunList[index].attr("href")){
  488. alert("讨论回答完毕!");
  489. return;
  490. }
  491. let val = window.open(taolunList[index].attr("href")+"&isFirstJoin=1", "讨论", "height=500, width=1500,top=200");
  492. }
  493. }
  494. };
  495. }else if(url == "/bbscircle/gettopicdetail"){
  496. $("body").append(`
  497. <script>
  498. function submitTaoLun(topicId,clazzid,cpi,ut,showChooseClazzId){
  499. var content = $("#" + topicId).val();
  500. var img=$("#images_img_"+topicId).find("img");
  501. var str="";
  502. for(var i=0;i<img.size();i++){
  503. var imgsrc=img[i];
  504. if(i==img.size()){
  505. str=str+imgsrc.src.replace("100_100","origin");
  506. }else{
  507. str=str+imgsrc.src.replace("100_100","origin")+",";
  508. }
  509. }
  510. if((content==""||content=="回复话题:"||content.trim()=='')&&str==""){
  511. alert("请输入回复内容!");
  512. return false;
  513. }
  514. if(typeof(cpi) == "undefined" || cpi == ""){
  515. cpi = 0;
  516. }
  517. if(typeof(ut) == "undefined" ){
  518. ut = "t";
  519. }
  520. var allAttachment = getAllNoticeAttachment();
  521. jQuery.ajax({
  522. type: "post",
  523. url : "https://mooc1-2.chaoxing.com/bbscircle/addreply",
  524. dataType:'html',
  525. data: {
  526. clazzid : clazzid,
  527. topicId : topicId,
  528. content : content,
  529. files : str,
  530. cpi : cpi,
  531. ut : ut,
  532. attachmentFile:allAttachment,
  533. openc : getOpenc(),
  534. showChooseClazzId: showChooseClazzId
  535. },
  536. success: function(data){
  537.  
  538. }
  539. });
  540. }
  541. </script>
  542. `);
  543. if(getQueryVariable("isFirstJoin") == 1){
  544. let replyfirstname = $($("[name=replyfirstname]")[Math.floor(Math.random()*$("[name=replyfirstname]").length)]);
  545. $(".oneDiv .tl1").click();
  546. $(".oneDiv textarea").val(replyfirstname.text());
  547. $("body").append(`<button id="subTL" onclick="submitTaoLun${$(".oneDiv textarea").parent().find("input[type=submit]").attr("onclick").match(/\((.+?)\)/g)[0]}"></button>`);
  548. $("#subTL").click();
  549. if (window.opener) {
  550. setTimeout(function(){window.opener.postMessage("close", '*');},1500);
  551. }
  552. }
  553. }
  554. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址