async def func(): start = time.time() while True: if time.time() - start > timeout: LOGGER.warning( f'Login failed: {account_id} <<<{page.page_source=}>>>') await notify('Login failed', f'{account_id}') return False # noinspection PyProtectedMember try: await page.goto( 'http://fresh.ahau.edu.cn/yxxt-v5/web/jkxxtb/tbJkxx.zf') except playwright._impl._api_types.Error as e: LOGGER.exception(e) continue await sleep(2) await page.evaluate(js_codes.login()) await sleep(2) await page.fill('#zh', account_id) await page.fill('#mm', password) await sleep(2) await page.click('#dlan') await sleep(2) if page.url != 'http://fresh.ahau.edu.cn/yxxt-v5/web/jkxxtb/tbJkxx.zf': await sleep(60 * 10) continue await sleep(5) return True
async def main(): global BROWSER REQUEST_LIMITS['pushplus.plus'] = Limit(SleepTime(120)) async with contextlib.AsyncExitStack() as stack: play = await stack.enter_async_context(async_playwright()) BROWSER = await play.chromium.launch() stack.push_async_callback(play.stop) stack.push_async_callback(BROWSER.close) scheduler = AsyncIOScheduler(job_defaults={ 'misfire_grace_time': 3600, 'coalesce': True }, timezone=str(tzlocal.get_localzone())) loop = asyncio.get_running_loop() for s in (signal.SIGINT, signal.SIGTERM, signal.SIGQUIT): loop.add_signal_handler(s, lambda: create_task(shutdown())) event = asyncio.Event() SHUTDOWN_VARIABLES['event'] = event if RUN_IMMEDIATELY: try: task = create_task(run(return_cancelled_error=True)) TASKS.add(task) await task TASKS.discard(task) LOGGER.warning('immediately running finished') except CancelledError: return scheduler.add_job(run, 'cron', hour=7) scheduler.add_job(run, 'cron', hour=12) scheduler.add_job(run, 'cron', hour=19, minute=30) scheduler.start() stack.callback(scheduler.shutdown) stack.push_async_callback(event.wait)
async def shutdown(): if SHUTDOWN_VARIABLES['killed']: os._exit(1) SHUTDOWN_VARIABLES['killed'] = True LOGGER.warning('Exiting') for t in TASKS: t.cancel() if TASKS: await asyncio.wait(TASKS) LOGGER.debug(f'{TASKS=}') SHUTDOWN_VARIABLES['event'].set()
async def func(): async with contextlib.AsyncExitStack() as stack: if not RUN_IMMEDIATELY: await sleep(random() * 30 * 60) account_id = account['account-id'] password = account['password'] context, page = await new_context() stack.push_async_callback(context.close) stack.push_async_callback(page.close) logged = await login(page, account_id, password) if not logged: return html = HTML(await page.content()) source = await get_script_source(html=html) if SCRIPT_SOURCE: if diff := '\n'.join( get_diff(SCRIPT_SOURCE, source.splitlines())): await handle_page_changing(diff, source) return name = html.xpath("//input[@id='xm']/@value")[0] await page.evaluate(js_codes.submit()) await sleep(2) async with page.expect_response('**/tbBcJkxx.zf') as response: await page.click("//button[text()='提交']") await sleep(5) response = await (await response.value).json() if response['status'] == 'success': await page.wait_for_selector("//div[text()='保存数据成功']", state='attached') LOGGER.warning(f'Success: {account_id} {name}') else: LOGGER.warning( f'Submit failed: {account_id} {name} <<<{source=}>>>') await notify('Submit failed', f'{account_id} {name}')
async def on_command_error(_, error): LOGGER.warning("Command error: %s", error)
def read_stats(args): # This is the command to grab all of the necessary info. # Note that -v is passed to tail - this is so we always the filename # given to us, which is needed for parsing. # As processes can be transient, we can get errors here about # non-existent files, so ignore them, this is expected. cmd = 'nice tail -v -n +1 '\ '/proc/%s/{cmdline,smaps} '\ '/proc/meminfo '\ '/proc/loadavg '\ '/proc/uptime '\ '/proc/vmstat '\ '2>/dev/null; ' \ 'nice find /proc/%s -type f -name stat '\ '-exec tail -v -n +1 {} \; 2>/dev/null | '\ 'awk \''\ '/==>/ {print} '\ '/^[0-9]/ {print \$2, \$10, \$12, \$14, \$15, \$22}\';' # Accept a space-separated list of pids as that is what pidof(8) returns and # it's quite likely you'll want to invoke this script with something like: # # --pid "`pidof foobar`" # # at some point. if args.pid.isdigit() or args.pid == '*': pids = args.pid else: pids = '{%s}' % args.pid.replace(' ', ',') # root can see all of /proc, another user is likely not going to be able # to read all of it. This isn't a hard error, but won't give a full view # of the system. if (args.host == '' and getpass.getuser() != "root") or\ (args.host != '' and args.user != 'root'): LOGGER.warning("If not running as root you may not see all info.") if args.host == '': LOGGER.info('Loading local procfs files') cmd = "bash -c \"%s\"" % (cmd % (pids, pids)) elif args.host != '': ssh = ( "ssh %s@%s" " -o UserKnownHostsFile=/dev/null" " -o StrictHostKeyChecking=no" " -o LogLevel=error" % (args.user, args.host) ) if args.password: ssh = "sshpass -p %s %s" % (args.password, ssh) else: ssh = "%s -o PasswordAuthentication=no" % ssh cmd = """%s "%s" """ % (ssh, cmd % (pids, pids)) LOGGER.info('Reading procfs with cmd: %s' % cmd) p = Popen(cmd, shell=True, bufsize=-1, stdout=PIPE, stderr=PIPE) stats = read_tailed_files(p.stdout) if p.poll() != 0: LOGGER.error("Command failed with: %r" % p.stderr.read().strip()) sys.exit(1) return stats
async def handle_page_changing(diff, current): LOGGER.warning('Page changed:\n{}'.format(diff)) PREVIOUS_PATH.write_text(current) await notify(f'Page changed', f'```diff\n{diff}\n```') create_task(shutdown())