python制作网易账号余额查询工具

来源:互联网 发布:淘宝的昵称有什么用 编辑:程序博客网 时间:2024/04/28 01:18

制作一个自动登录,手动滑动验证码,自动读取余额的工具,完成后再做验证码识别的部分。
先展示一下完成的结果。
结果展示
github地址:https://github.com/TechKuki/NeteastBalance

实现自动登录

python自带的tkinter框架没有能够支持展示网页的控件,查询到python开发gui程序还可以使用wxPython,PyQt,PySide等。
这里我们使用PyQt5,使用 pip3 install PyQt5 安装。安装完成后PyQt5的版本是5.9。
正常思路是寻找登录的接口,然后post数据上去,但是找了好久只找到要post的地址,没找到怎么生成post数据。这里如果有大佬研究过了请指教一下。
换一种思路,操作js代码进行登录。
浏览器里打开http://ecard.163.com/index_login?refer_uri=%2Findex,然后F12,进入Console,执行
document.getElementById('dologin').click()
可以看到模拟了登录的点击操作。
然后来找一找PyQt中向页面执行js代码的接口,查询到QWebEngineView的runJavaScript函数可以执行,但是这个函数只能操作打开的页面的dom对象,而登录要操作的文本框、按钮等在一个iframe当中,无论怎么写js代码都操作不到,这里卡住了。继续在api里找,找到QWebEngineScript的setRunsOnSubFrames看起来像是可以在iframe中执行代码,写几行代码实验了下果然可以。
写js的时候又发现,网页中的某些东西是动态加载进来的,我们的js执行的时候有可能网页还没加载完,所以这里用了一个计时器。
关键代码:

# -*- coding: utf-8 -*-import sysfrom PyQt5.QtCore import QUrlfrom PyQt5.QtWidgets import QApplicationfrom PyQt5.QtWebEngineWidgets import QWebEngineView, QWebEngineScriptapp = QApplication(sys.argv)browser = QWebEngineView()browser.load(QUrl("http://ecard.163.com/account/query_balance"))script = QWebEngineScript()script.setInjectionPoint(QWebEngineScript.Deferred)script.setRunsOnSubFrames(True)script.setSourceCode("""    var box = document.getElementById('cnt-box');    if(box){        function interFunc(){            if(box.children.length == 4 && document.getElementById('nerror').children.length == 2){                clearInterval(interId);                email = document.getElementsByName('email');email[0].value='username@163.com';                password = document.getElementsByName('password');password[0].value='password';                document.getElementById('dologin').click();            }        }        var interId = setInterval(interFunc, 100);    }""")browser.page().scripts().insert(script)browser.show()sys.exit(app.exec_())

实现查询数据

这里同样通过执行js的方式实现,在浏览器的开发者工具中找到需要提取的部分,然后使用QWebEnginePage的loadFinished信号。
关键代码:

def js_callback(balance):    print(balance)def load_finished(isOk):    if isOk:        if page.requestedUrl() == QUrl("http://ecard.163.com/handle_query_verify"):        page.runJavaScript("document.getElementsByClassName('red bold')[2].innerText", js_callback)    else:        print("load error")page.loadFinished.connect(load_finished)

实现连续查询

因为有多个账号需要查询余额,所以我们要实现在查询完一个账号后继续查询下个账号。这一步我将代码封装成了一个类,连续查询的逻辑没什么好讲的,直接上代码。

class Balance(QWebEngineView):    def __init__(self, accounts):        #...    def loadFinished(self, isOk):        #...    def jsCallback(self, balance):        self.index = self.index + 1        print(balance)        self.startQuery()    def startQuery(self):        if self.index < len(self.accounts):            self.load(self.urlLogin)if __name__ == "__main__":    accounts = [('user1@163.com', 'password'),        ('user2@163.com', 'password'),        ('user3@163.com', 'password')]    app = QApplication(sys.argv)    balanceView = Balance(accounts)    balanceView.startQuery()    balanceView.show()    sys.exit(app.exec_())

调整验证码显示

到上一步已经实现了查询工具的主要逻辑,但是因为我们是直接将网页加载进来,页面上有很多多余的内容十分碍眼,而且登录界面的验证码和查询界面的验证码不在一个位置,每次查询需要拖动view的滚动条且鼠标移动的距离非常远,导致使用体验非常差。
这一步我们把页面上多余的内容全部删除或者隐藏,调整验证码显示的位置,做到页面上只显示关键部分。
在chrome的开发者工具上逐个元素的删除调整,将有调整的元素都记录下来,这里需要有一丢丢的css知识。最后关键代码如下。

def loadFinished(self, isOk):    if isOk:        requestedUrl = self.page().requestedUrl()        if requestedUrl == self.urlLogin:            self.page().runJavaScript("""                //#footer,#header,#urs_tab,#phone_tab删掉                $('#footer').remove()                $('#header').remove()                $('#urs_tab').remove()                $('#phone_tab').remove()                //.nowbg的class属性删掉                $('.nowbg').removeAttr('class')                //#wrap的min-width属性去掉                $('#wrap').css('min-width', 'initial');                //#center的width属性去掉                $('#center').css('width', 'initial');                //#login的border-top,height,position,right,top属性去掉,加margin:auto;                $('#login').css('border-top', 'initial');                $('#login').css('height', 'initial');                $('#login').css('position', 'initial');                $('#login').css('right', 'initial');                $('#login').css('top', 'initial');                $('#login').css('margin', 'auto');            """)        elif requestedUrl == self.urlVerify:            self.page().runJavaScript("""                //#footer,#header,.situation删掉                $('#footer').remove()                $('#header').remove()                $('.situation').remove()                //#wrap的min-width属性去掉                $('#wrap').css('min-width', 'initial');                //#main的width属性去掉                $('#main').css('width', 'initial');                //.mb-content的margin: 100px auto 78px auto;                $('.mb-content').css('margin', '100px auto 78px auto')            """)        elif requestedUrl == self.urlBalance:            self.page().runJavaScript("document.getElementsByClassName('red bold')[2].innerText", self.jsCallback)    else:        print("load error")if __name__ == "__main__":    #...    balanceView.resize(360, 363)    #...

到这里工具已经基本可用了,调整完后使用的界面如下:
这里写图片描述

验证码拖动后自动点击确定

每次拖完验证码后还需要再点一下按钮,这个点按钮的工作也可以让js来做。验证码验证成功后右边会出现一个绿色的对勾,通过检查这个对勾是否存在来确定点击按钮的时机。关键代码如下。

//登录界面function verifyFunc(){    if(document.getElementsByClassName('u-suc').length == 2){        clearInterval(verifyId);        document.getElementById('dologin').click();    }}var verifyId = setInterval(verifyFunc, 100);//查询界面function verifyFunc(){    if($('.TxtStatus').children().length == 1){        clearInterval(verifyId);        $('#query_verify_form').submit();    }}var verifyId = setInterval(verifyFunc, 100);

查询结果展示到窗体上

查询结果目前都是直接打印到控制台里,查看起来十分不方便,这一步我们把查询结果显示在一个表格上。并且整理了下界面的显示。
表格代码:

# -*- coding: utf-8 -*-from PyQt5.QtWidgets import QTableWidget, QTableWidgetItem, QAbstractItemView, QHeaderViewclass BalanceTable(QTableWidget):    def __init__(self):        QTableWidget.__init__(self)        self.setEditTriggers(QAbstractItemView.NoEditTriggers)        self.setColumnCount(2)        self.horizontalHeader().setSectionResizeMode(0, QHeaderView.Stretch)        self.horizontalHeader().setSectionResizeMode(1, QHeaderView.ResizeToContents)        self.setHorizontalHeaderLabels(["账号", "余额"])    def addItem(self, account, balance):        rowCount = self.rowCount()        self.insertRow(rowCount)        self.setItem(rowCount, 0, QTableWidgetItem(account))        self.setItem(rowCount, 1, QTableWidgetItem(balance))

之前的回调函数处理成调用BalanceTable的addItem函数。

class BalanceView(QWebEngineView):    #...    def jsCallback(self, balance):        if self.queryCallBack:            self.queryCallBack(self.accounts[self.index][0], balance)        self.index = self.index + 1        self.startQuery()    #...    def startQuery(self, queryCallBack=None):        if queryCallBack:            self.queryCallBack = queryCallBack        #...class Neteast(QWidget):    def startQuery(self):        if self.accounts:            self.balanceView.startQuery(self.queryCallBack)    def queryCallBack(self, account, balance):        self.balanceTable.addItem(account, balance)

增加查询进度条

进度条的使用比较简单,我们要用到的只有2个函数。

progressBar = QProgressBar()progressBar.setTextVisible(False)progressBar.setValue(val)vboxLayout.addWidget(progressBar)

账号密码提出到单独文件

账号和密码直接写到代码里看起来总有那么一点不舒服,最后一步我们把账号单独放在一个文件里。

#neteast.pyif __name__ == "__main__":    from account import accounts    #...#account.pyaccounts = [('user1@163.com', 'password'),    ('user2@163.com', 'password'),    ('user3@163.com', 'password')]

最后完成的代码可以在github上查看。

原创粉丝点击