2022年10月

Ashampoo UnInstaller 10 账号共享:
UI10AE-779873-4661D9

无论您安装了什么,UnInstaller 10都可以删除它们且不会残留垃圾!
Ashampoo UnInstaller 10 可以无残留的卸载程序,让您无忧的安装、测试和删除软件。
与 Windows 默认的卸载相比,其包含四种删除方法可确保更彻底地删除。
包括无用的程序,以及通过捆绑在其它软件中或网络潜入系统中的流氓软件。
Ashampoo UnInstaller 10 是此类间谍软件/恶意软件的终极杀手,为您清除所有间谍软件/恶意软件!
对于不再需要或偷偷安装进来的浏览器扩展同样可以轻松去除,即使是浏览器自身无法或不会显示的小“助手”也能轻松删除。

AIDA64 Extreme至尊版最新账号共享:
UKTR1-VF7D6-FJD9C-G4D34-FYY1R

AIDA64 Extreme至尊版是一款强大的硬件检测工具,其检测精准度和支持能力是所有软件中最好的,它为用户展示PC电脑的每一个细节,最权威的电脑硬件监测、监控与测试软件,硬件检测大师,也是每位高手玩家、菜鸟用户必备的硬件检测利器!
2032年

https://www.icloud.com/shortcuts/a28d108b69e3424688e9e1a837b46aeb
用手机浏览器打开网址,加载到快捷指令里就行了,需要先获取cookies,填入后用令牌模式,任务几乎能全部自动完成。
忘了说了,获取cookies首选Alook,这个软件虽然需要买但是非常稳定且好用,可以自己买也可以某宝买,登录上淘宝之后下方三条杠,打开选择工具箱,开发者工具,cookies拷贝就可以了。

去年分享过一次,今年又开始了,发现了一个可以刷课时的插件,之前我用的时候还是去年的版本,但是今天发现更新了,自带账号自动登录功能

使用方法:
浏览器+tampermonkey+插件


GitHub:https://github.com/WindLeaf233/QingJiaoHelper
代码:

// ==UserScript==
// @name                 QingJiaoHelper
// @namespace            http://tampermonkey.net/
// @version              0.2.6
// @description          青骄第二课堂小助手: 自动完成所有课程 + 每日领取学分
// @author               WindLeaf
// @match                *://www.2-class.com/*
// @grant                GM_addStyle
// @grant                GM_getResourceText
// @grant                GM_registerMenuCommand
// @grant                GM_getValue
// @grant                GM_setValue
// @license              GPL-3.0
// @supportURL           https://github.com/WindLeaf233/QingJiaoHelper
// @require              http://cdn.staticfile.org/jquery/3.6.1/jquery.min.js
// @require              https://cdn.bootcdn.net/ajax/libs/toastify-js/1.12.0/toastify.js
// @require              https://unpkg.com/vue@2
// @require              https://unpkg.com/buefy/dist/components/tag
// @require              https://unpkg.com/buefy/dist/components/collapse
// @require              https://unpkg.com/buefy/dist/components/switch
// @require              https://unpkg.com/buefy/dist/components/button
// @require              https://unpkg.com/buefy/dist/components/dialog
// @require              https://unpkg.com/buefy/dist/components/upload
// @require              https://unpkg.com/buefy/dist/components/field
// @require              https://cdn.bootcdn.net/ajax/libs/xlsx/0.18.5/xlsx.full.min.js
// @resource toastifycss https://cdn.jsdelivr.net/npm/toastify-js/src/toastify.min.css
// @resource buefycss    https://unpkg.com/buefy/dist/buefy.min.css
// @resource menuhtml    https://fqj.pages.dev/menu.html
// ==/UserScript==

'use strict';

if (isNone($.ajax) || isNone($.isNumeric)) {
  showMessage('无法找到脚本所需的 jQuery 函数!', 'red');
  return;
}

function isNone(anyObj) {
  return anyObj == undefined || anyObj == null;
}

function showMessage(text, color) {
  Toastify({
    text,
    duration: 3 * 1000,
    newWindow: true,
    gravity: 'top',
    position: 'left',
    stopOnFocus: true,
    style: { background: color }
  }).showToast();
}

const error = err => {
  showMessage(`在请求的时候发生了个错误, 错误代码 [${err.status}], 具体响应内容在控制台中`, 'red')
  console.error(`[${err.status}]`, err.responseText);
  return;
}

function request(method, api, success, data={}) {
  let url = `https://www.2-class.com/api${api}`;
  console.debug(`[${method}] ${url}`, data);
  if (method === 'GET') {
    return $.ajax({ method: 'GET', url, success, error });
  } else {
    return $.ajax({
      method: 'POST', url, success, error,
      contentType: 'application/json;charset=UTF-8',
      dataType: 'json',
      data: JSON.stringify(data)
    });
  }
}

function processSiteScript() {
  for (let script of document.getElementsByTagName('script')) {
    if (script.innerText.indexOf('window.__DATA__') != -1) {
      eval(script.innerText);
    }
  }
}

processSiteScript();
const reqtoken = window.__DATA__.reqtoken;
const location = document.location;
const pathname = location.pathname;

function changeReactValue(element, value) {
  let lastValue = element.value;
  element.value = value;
  let event = new Event('input', { bubbles: true });
  event.simulated = true;
  let tracker = element._valueTracker;
  if (tracker) {
    tracker.setValue(lastValue);
  }
  element.dispatchEvent(event);
}

function runWhenReady(readySelector, callback) {
  var numAttempts = 0;
  var tryNow = function() {
    var elem = document.querySelector(readySelector);
    if (elem) {
      callback(elem);
    } else {
      numAttempts++;
      if (numAttempts >= 34) {
        console.warn(`无法找到元素 [${readySelector}],已放弃!`)
      } else {
        setTimeout(tryNow, 250 * Math.pow(1.1, numAttempts));
      }
    }
  };
  tryNow();
}

function startCourse(courseId, successCallback) {
  request('GET', `/exam/getTestPaperList?courseId=${courseId}`, resp => {
    let data = resp.data;
    let title = data.papaerTitle; // typo xD
    let testPaperList = data.testPaperList;
    if (!isNone(testPaperList)) {
      let answers = testPaperList.map(column => column.answer);
      console.debug(`成功获取到课程 [${courseId}] 的数据: ${title}`);
      console.debug('成功获取到答案', answers);
      commit(answers);
    } else {
      let errorMsg = data.errorMsg;
      if (errorMsg !== '该课程课时考试已经完成') {
        startCourse(courseId);
      }
    }
  });

  function commit(answers) {
    console.debug(`正在提交课程 [${courseId}] 答案...`);
    let data = {
      courseId,
      examCommitReqDataList: answers.map((answer, index) => {
        return {
          examId: index + 1, // examId = index + 1
          answer: $.isNumeric(answer) ? Number(answer) : answer // single answer must be a number
        }
      }),
      reqtoken
    };
    request('POST', '/exam/commit', resp => {
      let flag = resp.data;
      if (flag) {
        console.debug(`成功提交课程 [${courseId}] 答案!`);
        successCallback();
      } else {
        console.error(`无法提交课程 [${courseId}] 答案!`, resp);
      }
    }, data);
  }
}

function checkDone(getCommittedCallBack, allDoneCallBack) {
  let committed = getCommittedCallBack();
  let beforeCommitted = committed;
  let checkCommitUpdate = setInterval(() => {
    if (committed != 0) {
      if (committed == beforeCommitted) {
        showMessage(`成功完成了 ${committed} 个课程!`, 'green');
        allDoneCallBack(committed);
        clearInterval(checkCommitUpdate);
      } else {
        beforeCommitted = committed;
      }
    }
  }, 500);
}

function getGMValue(name, defaultValue) {
  let value = GM_getValue(name);
  if (value === undefined) {
    value = defaultValue;
    GM_setValue(defaultValue);
  }
  return value;
}

let course = getGMValue('course', true);
let selfCourse = getGMValue('selfCourse', true);
let credits = getGMValue('credits', true);
let isLogined = getGMValue('isLogined', null);
let loginedAccount = getGMValue('loginedAccount', '');
let accounts = getGMValue('accounts', []);
let autoCompleteCourseDone = getGMValue('autoCompleteCourseDone', false);
let autoCompleteSelfCourseDone = getGMValue('autoCompleteSelfCourseDone', false);
let autoCompleteCreditsDone = getGMValue('autoCompleteCreditsDone', false);

let notAvailable = name => showMessage(`[${name}] 当前功能不可用,请刷新重试!`, 'red');

let autoComplete = () => notAvailable('autoComplete');
let startFromDatas = (_) => notAvailable('startFromDatas');
let resetStartFromDatas = () => {
  isLogined = null;
  GM_setValue('isLogined', null);
  showMessage('重置成功!', 'green');
  location.pathname = '/';
};

function showMenu() {
  let menucss = `.fqj-menu-container{position:fixed;z-index:9999;right:20px;top:10px}`;
  GM_addStyle(menucss);
  
  let menuhtml = GM_getResourceText('menuhtml');
  let container = document.createElement('div');
  container.classList.add('fqj-menu-container');
  container.innerHTML = menuhtml;
  document.body.appendChild(container);

  new Vue({
    el: '#fqj-app',
    data() {
      return {
        isOpen: -1,
        version: 'v0.2.6',
        collapses: [
          { title: '功能开关' },
          { title: '批量导入' },
          { title: '其他' }
        ],
        file: null
      }
    },
    computed: {
      course: {
        set(value) {
          GM_setValue('course', value);
          course = value;
        },
        get() {
          return course;
        }
      },
      selfCourse: {
        set(value) {
          GM_setValue('selfCourse', value);
          selfCourse = value;
        },
        get() {
          return selfCourse;
        }
      },
      credits: {
        set(value) {
          GM_setValue('credits', value);
          credits = value;
        },
        get() {
          return credits;
        }
      }
    },
    methods: {
      autoComplete() {
        autoComplete();
      },

      startFromDatas() {
        const file = this.file;
        if (file != null) {
          const fileReader = new FileReader();
          fileReader.onload = event => {
            try {
              const { result } = event.target;
              const workbook = XLSX.read(result, { type: 'binary' });
              let data = [];
              for (const sheet in workbook.Sheets) {
                if (workbook.Sheets.hasOwnProperty(sheet)) {
                  data = data.concat(XLSX.utils.sheet_to_json(workbook.Sheets[sheet]));
                  break;
                }
              }
              startFromDatas(data);
            } catch (e) {
              showMessage('在读取 xls 文件的过程中发生了个错误,请检查文件格式是否正确');
              console.error(e);
            }
          }
          fileReader.readAsBinaryString(file);
        } else {
          showMessage('无法读取文件对象,请检查文件格式是否正确!', 'red');
        }
      },

      reset() {
        resetStartFromDatas();
      },

      closeMenu() {
        document.body.removeChild(container);
      }
    }
  });
}

function login(account, password) {
  if (pathname !== '/') {
    // jump to main page
    location.pathname = '/';
    return;
  }

  // todo
}

function logout() {
  runWhenReady('#app > div > div > div > header > div > div.header-right-panel.hover-black > div.header-user-info > div > div > ul > li:nth-child(6) > a', logoutButton => {
    GM_setValue('isLogined', false);
    GM_setValue('account', '');
    logoutButton.click(); // logout
  });
}


(function() {
  // script pre-loads
  GM_addStyle(GM_getResourceText('toastifycss')); // apply toastifycss style file
  GM_addStyle(GM_getResourceText('buefycss')); // apply buefy style file
  GM_registerMenuCommand('菜单', showMenu); // register menu

  // if (isLogined === true) {
  //   autoComplete();
  //   let waiting = setInterval(() => {
  //     if (autoCompleteCourseDone && autoCompleteSelfCourseDone && autoCompleteCreditsDone) {
  //       showMessage(`账号 [${loginedAccount}] 已完成!`, 'green');
  //       clearInterval(waiting);
  //       logout();
  //     }
  //   }, 500);
  //   return;
  // } else if (isLogined === false) {
  //   let nextAccount = accounts[0];
  //   if (!isNone(nextAccount)) {
  //     login(nextAccount.account, nextAccount.password);
  //   } else {
  //     showMessage('全部账号 (除出错误的) 已完成!', 'green');
  //   }
  //   return;
  // }

  // add vue@2
  let vueScript = document.createElement('script');
  vueScript.setAttribute('src', 'https://unpkg.com/vue@2');
  document.body.appendChild(vueScript);
  
  const features = [
    { path: ['/courses', '/drugControlClassroom/courses'], title: '自动完成所有课程 (不包括考试)', func: taskCourses, enabled: course },
    { path: ['/selfCourse', '/drugControlClassroom/selfCourse'], title: '自动完成所有课程 (自学) (不包括考试)', func: taskSelfCourses, enabled: selfCourse },
    { path: ['/admin/creditCenter'], title: '自动获取每日学分', func: taskCredit, enabled: credits }
  ];

  for (let feature of features) {
    if (feature.path.indexOf(pathname) != -1 && feature.enabled) {
      showMessage(`激活功能: ${feature.title}`, 'green');
      feature.func();
    }
  }

  function taskCourses() {
    request('GET', '/course/getHomepageGrade', resp1 => {
      let grades = resp1.data.map(it => it.value);
      console.debug('获取年级列表', grades);
      for (let grade of grades) {
        // get courses
        request('GET', `/course/getHomepageCourseList?grade=${grade}&pageSize=24&pageNo=1`, resp2 => {
          let courses = resp2.data.list
            .filter(k => !k.isFinish && k.title != '期末考试') // skip finished and final exam
            .map(j => j.courseId); // courseId => list
          console.debug(`年级 [${grade}] 可用的课程 (没学过的):`, courses);
          if (courses.length === 0) {
            console.debug(`[!] 年级 [${grade}] 所有课程都是完成状态, 已跳过!`);
            return;
          }

          let committed = 0;
          for (let courseId of courses) {
            // [skip final exam]
            if (courseId == 'finalExam') {
              console.debug('已跳过期末考试!');
              return;
            }
            // start course
            if (!isNone(courseId)) {
              startCourse(courseId, () => {
                committed++;
              });
            } else {
              console.debug('[!] 无法找到 `courseId`, 已跳过!');
            }
          }

          checkDone(() => committed, _ => {
            autoCompleteCourseDone = true;
          });
        });
      }
    });
  }

  function taskSelfCourses() {
    // get all grades (bad method)
    let gradesTabElements = [];
    let timer = setInterval(() => {
      gradesTabElements = document.getElementsByClassName('ant-tabs-tab');
      if (gradesTabElements.length != 0) {
        resolveGrades();
      }
    }, 500);

    function resolveGrades() {
      clearInterval(timer);
      console.debug('获取年级列表 (自学)', gradesTabElements);
      for (let element of gradesTabElements) {
        let grade = element.innerText;
        request('GET', `/course/getHomepageCourseList?grade=自学&pageNo=1&pageSize=500&sort=&type=${grade}`, resp => {
          let courses = resp.data.list
            .filter(k => !k.isFinish && k.title != '期末考试') // skip finished and final exam
            .map(j => j.courseId); // courseId => list
            console.debug(`年级 [${grade}] 可用的课程 (自学) (没学过的):`, courses);
          if (courses.length === 0) {
            showMessage(`年级 [${grade}] 所有课程都是完成状态, 已跳过!`, 'blue');
            return;
          }

          let committed = 0;
          for (let courseId of courses) {
            // [skip final exam]
            if (courseId == 'finalExam') {
              console.debug('已跳过期末考试!'); // seems that selfCourses don't have final exam
              return;
            }
            // start course
            if (!isNone(courseId)) {
              startCourse(courseId, () => {
                committed++;
              });
            } else {
              console.debug('[!] 无法找到 `courseId`, 已跳过!');
            }
          }

          checkDone(() => committed, _ => {
            autoCompleteSelfCourseDone = true;
          });
        });
      }
    }
  }

  function taskCredit() {
    // medal: 领取禁毒学子勋章
    request('GET', '/medal/addMedal', medalResp => {
      let data = medalResp.data;
      let status = data.status;
      let num = data.medalNum;
      if (status) {
        showMessage(`成功领取禁毒徽章 [${num}]!`, 'green');
      } else {
        console.debug(`[!] 无法领取徽章 (可能已领取过), 已跳过!`)
      }
    });

    // resources: 心理减压, 耕读学堂 [耕读, 电影, 音乐, 体育, 美术, 自然, 公开课], 校园安全
    let categorys = [
      { name: 'public_good', tag: 'read' },
      { name: 'ma_yun_recommend', tag: 'labour' }, // the `ma_yun_recommend` has lots of sub-categorys
      { name: 'ma_yun_recommend', tag: 'movie' },
      { name: 'ma_yun_recommend', tag: 'music' },
      { name: 'ma_yun_recommend', tag: 'physicalEducation' },
      { name: 'ma_yun_recommend', tag: 'arts' },
      { name: 'ma_yun_recommend', tag: 'natural' },
      { name: 'ma_yun_recommend', tag: 'publicWelfareFoundation' },
      { name: 'school_safe', tag: 'safeVolunteer' }
    ];
    let synced = 0;
    let liked = 0;

    for (let category of categorys) {
      request('POST', '/resource/getBeforeResourcesByCategoryName', resourcesResp => {
        let resources = resourcesResp.data.list.map(it => {
          return {
            title: it.description, resourceId: it.resourceId
          };
        });

        console.debug(`获取分类 ${category.name} 的资源`, resources);
        for (let resource of resources) {
          let resourceId = resource.resourceId;
          let data = { resourceId, reqtoken };
          // sync resource
          request('POST', '/growth/sync/resource', resourcePostResp => {
            let result = resourcePostResp.data.result;
            if (result) {
              console.debug(`成功同步资源 [${resourceId}]: ${resource.title}!`);
              synced++;
            } else {
              console.debug(`[!] 同步资源 [${resourceId}] 失败, 已跳过!`);
            }
          }, data);

          // like resource
          request('POST', '/resource/likePC', resourceLikeResp => {
            let count = resourceLikeResp.data;
            let flag = resourceLikeResp.success;
            let already_like = !$.isNumeric(count) && count.errorCode === 'ALREADY_like';
            if ($.isNumeric(count) && flag) {
              console.debug(`成功点赞资源 [${resourceId}]: ${count}!`);
              liked++;
            } else {
              console.debug(`[!] 无法点赞资源 [${resourceId}], 是否已点赞: ${already_like}, 已跳过!`);
            }
          }, data);
        }
      }, { categoryName: category.name, pageNo: 1, pageSize: 100, reqtoken, tag: category.tag });
    }

    let beforeSynced = synced;
    let checkSuccess = setInterval(() => {
      if (synced != 0) {
        if (synced == beforeSynced) {
          showMessage(`成功同步 ${synced} 个资源, 点赞 ${liked} 个!`, 'green');
          autoCompleteCreditsDone = true;
          GM_setValue('autoCompleteCreditsDone', true);
          clearInterval(checkSuccess);
        } else {
          beforeSynced = synced;
        }
      }
    }, 500);
  }

  autoComplete = () => {
    for (let feature of features) {
      showMessage(`已激活 ${feature.title}`, 'green');
      feature.func();
    }
  }

  // startFromDatas = (data) => {
  //   GM_setValue('accounts', data.map(line => {
  //     let account = line.账号;
  //     let password = line.密码;
  //     if (!isNone(account) && !isNone(password)) {
  //       return { account, password };
  //     } else {
  //       console.debug(`[!] 读取行 [${line.__rowNum__}] 时找不到账号和密码,已跳过!`, line);
  //       return;
  //     }
  //   }));
  //   GM_setValue('isLogined', false);
  //   location.pathname = '/';
  // }
})();

这个是python脚本,还有插件版的,有空了会发出来,包括自动登录账号,刷视频课时和练习,知识竞赛,还有普法插件等。

使用步骤

考虑到使用有些复杂,准备出个视频版的教程和资源整合包,比较忙还没录视频,现在就先看着吧.....会用的自己就可以用了
1.安装python
2.安装python运行所需要的模块
3.移动selenium驱动文件到指定地点
4.要登录的账号进行配置

1.安装

python官网下载双击打开,记得勾选path

2.安装模块

用的有两个selenium,requests

3.下载对应浏览器的selenium驱动,放到浏览器目录下

你用的哪个浏览器就放到哪个浏览器下面去

4.要登录的账号进行配置

先去第二课堂把账号密码列表下载下来,是excel的
然后把账号密码放到python文件夹下的 账户.txt 文件夹里面

最后点击运行即可

全部代码如下

from selenium import webdriver
import time
import json
import requests
import random
requests.packages.urllib3.disable_warnings()

# 设置driver路径,这个是我的浏览器路径,要改成你的
location = r'D:\我的程序\360极速\360Chrome\Chrome\Application\360chrome.exe'

# selenium设置与启动
options = webdriver.ChromeOptions()
prefs = {"profile.managed_default_content_settings.images": 2}  # 无图模式访问,这样的话加载会快很多
options.add_experimental_option("prefs", prefs)
options.binary_location = location
driver=webdriver.Chrome(chrome_options=options)  
driver.get('https://www.2-class.com/competition')
# 这里是等待加载完成才这样设置的
time.sleep(5)

def login(account):
    #点击登录
    el = driver.find_element_by_xpath('//*[@id="app"]/div/div[1]/div/header/div/div[2]/div[2]/div/span/a')
    el.click()
    time.sleep(2)

    #account
    el = driver.find_element_by_xpath('//*[@id="account"]')
    el.send_keys(account)
    print(account)
    time.sleep(1)

    #password
    el = driver.find_element_by_xpath('//*[@id="password"]')
    el.send_keys('a1234567')

    #登录
    el = driver.find_element_by_css_selector("[type='submit']")
    el.click()
    time.sleep(2)

    #cookie和数据
    cookie = ''
    cookies=driver.get_cookies()
    for i in cookies:
        cookie = cookie + i['name'] + '=' + i['value'] + ';'
    reqtoken = driver.execute_script('return window.__DATA__.reqtoken')

    yi_jian_man_fen(cookie,reqtoken,account)

    #点击退出
    el = driver.find_element_by_xpath('//*[@id="app"]/div/div[1]/div/header/div/div[2]/div[2]/div/a')
    el.click()
    time.sleep(1)
    el = driver.find_element_by_xpath('//*[@id="app"]/div/div[1]/div/header/div/div[2]/div[2]/div/div/ul/li[6]/a')
    el.click()
    time.sleep(2)

#开始答题
def yi_jian_man_fen(cookie,reqtoken,account):
    url = 'https://www.2-class.com/api/quiz/commit'
    headers = {
        'Cookie': cookie,
        'Content-Type': 'application/json',
        'User-Agent': 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50'
    }
    time = random.randint(100, 350)
    data = {
        "list": [
            {
                "questionId": 2986,
                "questionContent": "B"
            },
            {
                "questionId": 2989,
                "questionContent": "C"
            },
            {
                "questionId": 2990,
                "questionContent": "D"
            },
            {
                "questionId": 2959,
                "questionContent": "C"
            },
            {
                "questionId": 2928,
                "questionContent": "C"
            },
            {
                "questionId": 2960,
                "questionContent": "A"
            },
            {
                "questionId": 2961,
                "questionContent": "C"
            },
            {
                "questionId": 2897,
                "questionContent": "B"
            },
            {
                "questionId": 2930,
                "questionContent": "D"
            },
            {
                "questionId": 2898,
                "questionContent": "B"
            },
            {
                "questionId": 2963,
                "questionContent": "A"
            },
            {
                "questionId": 2932,
                "questionContent": "D"
            },
            {
                "questionId": 2901,
                "questionContent": "A"
            },
            {
                "questionId": 2966,
                "questionContent": "D"
            },
            {
                "questionId": 2934,
                "questionContent": "C"
            },
            {
                "questionId": 2904,
                "questionContent": "D"
            },
            {
                "questionId": 2907,
                "questionContent": "D"
            },
            {
                "questionId": 2972,
                "questionContent": "C"
            },
            {
                "questionId": 2973,
                "questionContent": "A"
            },
            {
                "questionId": 2912,
                "questionContent": "B"
            }
        ],
        "time": time,
        "reqtoken": reqtoken
    }

    result = requests.post(url=url, data=json.dumps(data), headers=headers, verify=False)
    print(account + '已经完成')

if __name__ == '__main__':
    accounts = []
    with open('账户.txt','r') as f:
        accounts = f.read().split('\n')

    try:
        for account in accounts:
            login(account)
    except:
        print('程序运行错误')

    driver.quit()   # 使用完, 记得关闭浏览器, 不然chromedriver.exe进程为一直在内存中.

仅限浙江地区使用!!!禁止商用!!!仅用于学习讨论!!!

使用
运行代码前,需要先获得openid,每个账号只要获得一次openid即可,以后无需重复抓包

安卓获得openId流程【部分手机无法用】

视频教程:https://wwd.lanzouy.com/isVnb0cc5jba 密码:bcg5
安卓下载抓包软件 httpcanary,安装并打开软件,有三步骤:1、同意条款 2、允许安装证书 3、root可以跳过
微信:打开大学习
软件httpcanary:点击右下角小飞机图标开始抓包
微信:点击“立即参与”->点击“去学习”。随后切到httpcanary,再点击右下角小飞机图标停止抓包。
软件httpcanary:点击右上角,找到“搜索”,直接搜索“openId”,注意:只要url是qczj.h5yunban.com的包。一般可以在包名为“qczj.h5yunban.com/qczj-youth-learning/cgi-bin/user-api/course/last-info”的响应中,找到openId
注意:记录openId,因为以后没必要再次抓包!!!

PC获得openid教程【推荐】

视频教程:https://wwd.lanzouy.com/isVnb0cc5jba 密码:bcg5
需要的软件:Fiddler、电脑版微信
打开Fiddler,安装证书
切换到微信,点击大学习,此时弹窗需要授权,点击“同意”。
点击“同意”后,切换到Fiddler,按“ctrl+f”,搜索openid,双击标黄处的包,并点击“WebForms”,在里面找到openid即可
注意:记录openId,因为以后没必要再次抓包!!!

运行代码

获得openid后,将openid填入config.yml,运行index.py即可。config.yml里面的name用来标识不同的openid,无实际意义。

注意

如果没有需要第2步授权步骤,而是直接进入大学习页面,则无法获得openid。需要彻底关掉微信,并重新打开微信,再尝试。
无论手机端或电脑端,如果实现得不到openid,需要点击“开始学习”进入到选择省市的选项。再切到Fiddler或httpcanary,按“ctrl+f”,搜索accessToken。得到accessToken后,比如accessToken为xxxx-xxxx-xxxx-xxxx,
将其合并到下面的链接 https://qczj.h5yunban.com/qczj-youth-learning/cgi-bin/user-api/info?accessToken=xxxx-xxxx-xxxx-xxxx替换上面的xxxx-xxxx-xxxx-xxxx。随后进行访问此链接,可以在返回的结果里面,找到openid

import re
import requests
import json
import yaml
 
getToken_url = 'https://qczj.h5yunban.com/qczj-youth-learning/cgi-bin/login/we-chat/callback'
getUserInfo_url = 'https://qczj.h5yunban.com/qczj-youth-learning/cgi-bin/user-api/course/last-info'
getClass_url = 'https://qczj.h5yunban.com/qczj-youth-learning/cgi-bin/common-api/course/current'
checkin_url = 'https://qczj.h5yunban.com/qczj-youth-learning/cgi-bin/user-api/course/join'
 
headers = {
    'Content-Type': 'text/plain'
}
 
def getYmlConfig(yaml_file='config.yml'):
    with open(yaml_file, 'r', encoding='utf-8') as f:
        file_data = f.read()
    return dict(yaml.load(file_data, Loader=yaml.FullLoader))
 
 
def getToken(openId):
    # 根据openId获得token
    try:
        getToken = requests.get(url=getToken_url, params=openId, headers=headers)
        Token_raw = getToken.text
        Token = re.findall('[A-Z0-9]{8}[-][A-Z0-9]{4}[-][A-Z0-9]{4}[-][A-Z0-9]{4}[-][A-Z0-9]{12}', Token_raw)[0]
        print('获取Token为:' + Token)
        accessToken = {
            'accessToken': Token
        }
        return accessToken
    except:
        print('获取Token失败,请检查openId是否正确')
 
 
def getinfo(accessToken):
    # 根据accessToken获得用户信息
    try:
        getUserInfo = requests.get(getUserInfo_url, params=accessToken, headers=headers)
        userInfo = getUserInfo.json()
        cardNo = userInfo["result"]["cardNo"]
        nid = userInfo["result"]["nid"]
        getClass = requests.get(getClass_url, params=accessToken, headers=headers)
        Class = getClass.json()
        classId = Class["result"]["id"]
        infos: list = userInfo['result']['nodes']
        Faculty = [item['title'] for item in infos]
        print('签到课程为:' + classId, '\n您填写的个人信息为:' + cardNo, '\n您的签到所属组织为:' + str(Faculty))
        checkinData = {
            'course': classId,
            'subOrg': None,
            'nid': nid,
            'cardNo': cardNo
        }
        return checkinData
    except Exception as e:
        if "is not subscriptable" in str(e):
            print("openid出错,无法获得您的信息")
        print(f'获取历史信息失败,请您手动打卡:{e}')
 
 
 
 
def signup(accessToken, checkinData):
    # 根据token和data完成打卡
    checkin = requests.post(checkin_url, params=accessToken, data=json.dumps(checkinData), headers=headers)
    result = checkin.json()
 
    if result["status"] == 200:
        print("签到成功")
    else:
        print('出现错误,错误码:' + result["status"])
        print('错误信息:' + result["message"])
 
 
if __name__ == "__main__":
    config = getYmlConfig()
    for index, user in enumerate(config['users']):
        print(user['user']['name'], 'openId为 ', user['user']['openid'])
        openid = {
            'appid': 'wx56b888a1409a2920',
            'openid': user['user']['openid']
        }
        accesstoken = getToken(openid)
        checkindata = getinfo(accesstoken)
        if checkindata is not None:
            signup(accesstoken, checkindata)
        print('===========================================')