乐趣区

关于程序员:每日自动健康打卡Python腾讯云服务器

每日主动衰弱打卡(Python+ 腾讯云服务器)

1. 配置须要

python3.7,Chrome 或者 Edeg 浏览器,Chrome 驱动或者 Edge 驱动

# 须要配置 selenium 库,baidu-aip 库,pillOW 库,在终端执行以下命令
pip install selenium
pip install pillow
pip install baidu-aip

2. 实现性能

1. 模仿登录说唱大学微服务,须要百度 OCR 智能辨认 API 接口辨认验证码(收费获取)

2. 虚构地位信息填写,正文:其余信息保留上一天信息

3. 反馈打卡信息到 QQ 邮箱,正文:须要自行配置 POP3/ SMTP 服务

4. 挂到腾讯云服务上,每天定时主动打卡

3. 参考链接

百度 OCR 智能辨认的 API 调用链接

QQ 邮箱配置链接

腾讯云服务器上运行(收费 1 个月)抉择轻量应用服务器,我选的 linux 零碎,这里的实例也是 linux

4.linux 服务器配置

参考腾讯文档,近程登录 linux 实例

1. 以 root 登录

2. 下载 Python3.7,降级 pip,yum,更换国内源

3. 装置库,执行以下命令

pip3 install selenium
pip3 install pillow
pip3 install baidu-aip

4. 在 linux 上装置谷歌浏览器和驱动

在目录 /etc/yum.repos.d/ 下新建文件 google-chrome.repo

cd /etc/yum.repos.d/
vim google-chrome.repo

vim 命名编辑 google-chrome.repo 文件,输出如下内容:

[google-chrome]
name=google-chrome
baseurl=http://dl.google.com/linux/chrome/rpm/stable/$basearch
enabled=1
gpgcheck=1
gpgkey=https://dl-ssl.google.com/linux/linux_signing_key.pub

具体操作:按 i 插入,按 Esc,而后Shift+;,输出qw,而后按Enter 退出

装置浏览器,顺次输出以下命令

yum -y install google-chrome-stable --nogpgcheck

# 查看版本信息
google-chrome --version
# 找到 google_chrome 门路:我对应的门路是 /usr/bin/google-chrome, 输出门路创立软连贯
which google-chrome
# 创立软连贯
ln -s /usr/bin/google-chrome /bin/chrome

# 装置驱动
wget https://npm.taobao.org/mirrors/chromedriver/88.0.4324.96/chromedriver_linux64.zip
# 解压
yum -y install zip
unzip chromedriver_linux64.zip

# 转移 chromedriver 到 /user/bin 目录下
sudo mv chromedriver /usr/bin

# 解决 root 运行 chrome 问题
vim /opt/google/chrome/google-chrome
# 将最初一行改为如下:exec -a "$0" "$HERE/chrome" "$@" --no-sandbox $HOME

将 Python 主动运行程序写到 linux 里:

vim automatic.py
# 而后把程序复制进去

测试运行:

python3 automatic.py

利用 crontab 定时运行 python 脚本:(输出如下命令)

crontab -e

# 从左到右顺次示意分、时、日、月、周,设置为每天 0:01 主动打卡
1 0 * * * /usr/bin/python3 /root/automatic.py

# 启动服务
service crond restart

5. 代码局部

有具体解释

import sys
import time
from aip import AipOcr
from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.chrome.service import Service
from PIL import Image
import smtplib
from email.mime.text import MIMEText
from email.utils import formataddr

class LogIn:
    def __init__(self, user, passwd, path, lat=30.630869, long=104.083748):
        self.target = 'https://wfw.scu.edu.cn/ncov/wap/default/index'  # 说唱大学微服务地址
        self.username = str(user)  # 用户名
        self.password = str(passwd)  # 明码
        self.lat = lat  # 纬度
        self.long = long  # 经度
        self.path = path


    def main(self):
        attempt = 0
        print('\n 筹备')
        chrome_options = webdriver.ChromeOptions()
        # 设置无界面显示参数,因为要放在 linux 服务器上运行,无奈显示界面,调试的时候须要把上面五行正文掉,显示 chrome 界面
        chrome_options.add_argument('--no-sandbox')
        chrome_options.add_argument('window-size=1920x1080')
        chrome_options.add_argument('--disable-gpu')
        chrome_options.add_argument('--hide-scrollbars')
        chrome_options.add_argument('--headless')

        s = Service(self.path)
        browser = webdriver.Chrome(service=s, options=chrome_options)# 加载 chromedriver,用 edge 的就去下载 edgedriver
        print('开始')
        while True:
            browser.delete_all_cookies()  # 清空 cookie
            browser.get(self.target)
            try:  # 切换为账号密码登录
                browser.switch_to.frame('loginIframe')  # 切换 frame
                switch_element = WebDriverWait(browser, 10).until(EC.element_to_be_clickable((By.XPATH, '/html/body/div/div/div[2]/div[2]/div[1]/div/div[3]'))
                ) # 找到对应元素地位
                switch_element.click() # 点击切换
            except Exception as error:
                print('network wrong...\n', error)

            # 输出账号和明码
            input_user = browser.find_element(by=By.XPATH, value='/html/body/div/div/div[2]/div[2]/div[2]/div[3]/div[1]/div[2]/div/input')
            input_user.send_keys(self.username)
            input_pwd = browser.find_element(by=By.XPATH, value='/html/body/div/div/div[2]/div[2]/div[2]/div[3]/div[2]/div[2]/div/input')
            input_pwd.send_keys(self.password)
            time.sleep(1)

            # 截图验证码并辨认(这里用的百度云的收费 OCR),须要自行注册,不会的能够参考这篇博客:https://www.cnblogs.com/xiaowenshu/p/11792012.html

            ver_btn = browser.find_element(by=By.CLASS_NAME, value='van-field__button')
            ver_btn.click()# 刷新验证码
            # 获取图片元素的地位
            loc = ver_btn.location
            # 获取图片的宽高
            size = ver_btn.size
            # 获取验证码上下左右的地位
            left = loc['x']
            top = loc['y']
            right = (loc['x'] + size['width'])
            botom = (loc['y'] + size['height'])
            val = (left, top, right, botom)

            print(loc)
            print(size)
            # 验证码截图保留到当前目录下 ver.png
            # 关上网页截图
            browser.save_screenshot('full.png')
            # 通过上下左右的值,去截取验证码
            pic = Image.open('full.png')
            ver_pic = pic.crop(val)
            ver_pic.save('ver.png')

            verification = self.Vertification('ver.png')
            print('verification code:' + verification) # 辨认验证码结束

            input_ver = browser.find_element(by=By.XPATH, value='/html/body/div/div/div[2]/div[2]/div[2]/div[3]/div[3]/div[2]/div/input')
            input_ver.send_keys(verification)
            browser.find_element(by=By.XPATH, value='/html/body/div/div/div[2]/div[2]/div[2]/div[3]/button').click()  # 点击登录
            time.sleep(5)  # 期待跳转
            if browser.current_url == self.target:
                break # 登录胜利,退出循环
            attempt += 1
            if attempt == 5: # 有时候网页会卡,即便明码正确也登录不下来,每次循环尝试 5 次登录(个别 5 次内能登录下来)print('请查看账号密码,或稍后再试!')
                browser.quit()
                sys.exit()

        # 获取地理位置并提交
        browser.execute_cdp_cmd(
            "Browser.grantPermissions",  # 受权地理位置信息
            {
                "origin": "https://wfw.scu.edu.cn/",
                "permissions": ["geolocation"]
            },
        )
        browser.execute_cdp_cmd(
            "Emulation.setGeolocationOverride",  # 虚构地位
            {
                "latitude": self.lat,
                "longitude": self.long,
                "accuracy": 50,
            },
        )
        try:  # 提交地位信息
            area_element = WebDriverWait(browser, 10).until(EC.element_to_be_clickable((By.NAME, 'area'))
            )
            area_element.click()
        except Exception as error:
            print('get location wrong...\n', error)

        time.sleep(2)  # 期待地位信息


        """
        邮箱信息,没有独自写个函数,须要配置 QQ 邮箱,开启 POP3/ SMTP 服务,并获取受权码
        因为是揭示本人打卡,所以本人是发件人,本人是收件人
        填入受权码
        """
        # 建设邮箱信息
        my_sender = 'XXX@qq.com'  # 发件人邮箱账号
        my_pass = 'XXX'  # 发件人邮箱明码(过后申请 smtp 给的口令)
        my_user = 'XXX@qq.com'  # 收件人邮箱账号

        browser.find_element(by=By.XPATH, value='/html/body/div[1]/div/div/section/div[5]/div/a').click()  # 提交信息
        try:
            ok_element = WebDriverWait(browser, 3).until(EC.element_to_be_clickable((By.XPATH, '/html/body/div[4]/div/div[2]/div[2]'))  # 提交按钮
            )
            ok_element.click()
            print(self.username, 'success!')

            WebDriverWait(browser, 3).until(EC.presence_of_element_located((By.XPATH, '/html/body/div[5]/div/div[1]'))  # 胜利对话框题目
            )
            title_success = browser.find_element(by=By.XPATH, value='/html/body/div[5]/div/div[1]').get_attribute("innerHTML")
            print('From website:', title_success)

            msg = MIMEText('打卡胜利', 'plain', 'utf-8')
            msg['From'] = formataddr(["终极打卡人", my_sender])  # 括号里的对应发件人邮箱昵称、发件人邮箱账号
            msg['To'] = formataddr(["打工人", my_user])  # 括号里的对应收件人邮箱昵称、收件人邮箱账号
            msg['Subject'] = "打卡提醒"  # 邮件的主题,也能够说是题目

            server = smtplib.SMTP_SSL("smtp.qq.com", 465)  # 发件人邮箱中的 SMTP 服务器,端口是 465
            server.login(my_sender, my_pass)  # 括号中对应的是发件人邮箱账号、邮箱明码
            server.sendmail(my_sender, [my_user,], msg.as_string())  # 括号中对应的是发件人邮箱账号、收件人邮箱账号、发送邮件
            server.quit()  # 敞开连贯
        except:
            info = browser.find_element(by=By.CLASS_NAME, value='wapat-title').get_attribute('innerHTML')
            print('From website |', self.username, ':', info)

            msg = MIMEText('打卡失败,请手动打卡', 'plain', 'utf-8')
            msg['From'] = formataddr(["终极打卡人", my_sender])
            msg['To'] = formataddr(["打工人", my_user])
            msg['Subject'] = "打卡提醒"

            server = smtplib.SMTP_SSL("smtp.qq.com", 465)
            server.login(my_sender, my_pass)
            server.sendmail(my_sender, [my_user,], msg.as_string())
            server.quit()
        browser.quit()

    """
    函数申明:调用百度 OCR 的 API,须要输出以下 API 接口:APP_ID = '***'
            API_KEY = '***'
            SECRET_KEY = '***'
    传入截取图片 url,传出辨认后果字符串
    """
    def Vertification(self, url):

        # 创立 AipOcr
        """你的 APPID AK SK"""
        APP_ID = 'XXX'
        API_KEY = 'XXX'
        SECRET_KEY = 'XXX'

        client = AipOcr(APP_ID, API_KEY, SECRET_KEY)

        # 文字辨认高精度版本

        """读取图片"""
        def get_file_content(url):
            with open(url, 'rb') as fp:
                return fp.read()

        image = get_file_content('ver.png')

        """调用通用文字辨认(含地位高精度版)"""
        result = client.accurate(image)
        print(str(result))
        res = result['words_result'][0]['words']
        return str(res)

        # """如果有可选参数"""
        # options = {}
        # options["recognize_granularity"] = "big"
        # options["detect_direction"] = "true"
        # options["vertexes_location"] = "true"
        # options["probability"] = "true"
        #
        # """带参数调用通用文字辨认(含地位高精度版)"""
        # client.accurate(image, options)


if __name__ == '__main__':

    """
    用户输入区:学号用户名
    明码(个别为身份证后六位)定位地点的经纬度
    """username ='XXX'  # 用户名(学号)password = 'XXX'  # 明码
    latitude = 30.630869  # 虚构地位纬度
    longitude = 104.083748  # 经度

    path = '.\chromedriver\chromedriver.exe' #chromedriver 门路
    # path = '/usr/bin/chromedriver' # linux 服务器上的 chromedriver 门路
    t = LogIn(user=username, passwd=password, lat=latitude, long=longitude, path=path)
    t.main()

运行后果图:

退出移动版