Maison > Article > développement back-end > Comment saisir automatiquement les données du système ERP en Python
Logiciel : Pycharm
Environnement : Python 3.7.9 (en tenant compte du fait que les clients peuvent avoir des systèmes d'exploitation différents, pour des raisons de compatibilité)
Bibliothèque technique : demandes, pandas, Pyqt5, etc. (voir les fichiers de dépendances pour plus de détails)
Grâce à l'analyse et à la communication avec les documents de demande des clients, il existe à peu près les exigences suivantes :
Soumettre les données à 3 interfaces par lots en fonction des "impairs" attribution du numéro"
Nécessite une interface d'opération GUI
Aide différents vendeurs à se connecter
En général, il s'agit d'une soumission de données POST et d'un développement d'interface graphique.
Cette section utilise principalement la technologie des robots. Les étapes qui restent inchangées depuis des milliers d'années consistent d'abord à analyser la page Web.
Il s'avère grâce à la capture de paquets que le mot de passe est en texte brut, ce qui réduit la difficulté de moitié. Utilisez ensuite le mot de passe correct pour analyser le retour après une connexion réussie.
def login(self, username: str, password: str): """ 登录 """ url = "http://cloud.tiamaes.com:11349/erp/portal.bootstrap/SSOLoginAction/login.do" data = { "_tp_data": '{"parameters":{"userName":' + username + ',"pwd":' + password + '},"rowsets":{},"headers":{},"requestComponent":"0"}' } data = parse.urlencode(data).replace("+", "") resp = requests.post(url, headers=self.headers, data=data, verify=False) self.IDENTIFIER = resp.json()["headers"]["IDENTIFIER"] return self.IDENTIFIER
J'ai découvert qu'après une connexion réussie, un paramètre "IDENTIFIER" sera renvoyé et la valeur est une chaîne cryptée. Rien qu'en regardant le sens littéral, je sais que cela doit être utile, alors enregistrez-le d'abord.
Étant donné que j'utilise un compte test, les données soumises par ce compte seront supprimées afin de ne pas injecter trop de données invalides dans les autres, la saisie proprement dite ne sera pas effectuée ici, ainsi que le code métier. sera utilisé pour l’illustrer.
Obtenir des informations sur le véhicule
Grâce à l'analyse, il a été constaté que même si le client a fourni une partie des informations sur le véhicule, il restait encore de nombreuses informations manquantes qui devaient être complétées par lui-même. Grâce à la capture de paquets, nous avons constaté qu'après avoir saisi le numéro du véhicule, une requête Ajax sera lancée et que les autres informations du formulaire sont les données renvoyées par la requête Ajax.
def get_car_details(self, car_no: str, IDENTIFIER: str): """ 获取车辆信息 """ # print(self.IDENTIFIER) url = "http://cloud.tiamaes.com:11349/money/basis.inter/JwBusAction/getCacheJwBusByNo.do" data = { '_tp_data': '{"parameters": {"busNo": ' + str(car_no) + ', "dsName": "83"}, "rowsets": {}, "headers": {"IDENTIFIER": ' + IDENTIFIER + '}, "requestComponent": "0"}' } data = parse.urlencode(data).replace("+", "") resp = requests.post(url, headers=self.headers, data=data, verify=False) rows = resp.json()["rowsets"]["com.tp.basis.entity.entity.bus.BaJwBus"]["rows"][0] return rows
Obtenir des informations sur le personnel
Je n'ai pas trouvé les informations sur le personnel dans le formulaire grâce à la capture de paquets, mais j'ai ensuite trouvé les données pertinentes sur une autre page.
C'est un peu plus gênant. Vous devez utiliser des expressions régulières pour faire correspondre les données.
def get_personal_info(self, IDENTIFIER: str): """ 获取个人信息 """ url = "http://cloud.tiamaes.com:11349/money/money.action/CharteredAction/showDetail.do" data = { '_tp_data': '{"parameters":{"dsName":"83","method":"add","recId":"-1"},"rowsets":{},"headers":{"IDENTIFIER":' + IDENTIFIER + '},"requestComponent":"1"}' } data = parse.urlencode(data).replace("+", "") resp = requests.post(url, headers=self.headers, data=data, verify=False) json_data = eval(re.findall(r'<code>.*?"rows":\[(.*?)\]', resp.text)[0]) return json_data
Initiez une demande et soumettez des données
Obtenez l'identifiant, les informations sur le véhicule et les informations personnelles renvoyées par la connexion. Le reste consiste à les combiner avec les données fournies par le client pour lancer la demande. Il convient de noter que les paramètres de requête doivent être convertis en codage URL. Les paramètres de requête sont également la partie la plus gênante de ce robot. Nous vous montrons ici les paramètres qui doivent être envoyés dans une requête.
Il existe de nombreux paramètres et les exigences de format sont relativement strictes dans l'ensemble du processus de développement, le débogage ici prend également le plus de temps. Après le débogage, le code devrait être simplifié. Je suis trop paresseux pour modifier la fusion qui doit être fusionnée après le débogage, cette section est donc relativement redondante.
def submit_data(self, i: dict, IDENTIFIER: str): """ 众意数据提交 """ personal_info = self.get_personal_info(IDENTIFIER) # 获取个人信息 personal_info_data = str(personal_info).replace("'", '"') # 将personal_info转换为字符串 url = "http://cloud.tiamaes.com:11349/money/money.action/CharteredAction/saveForm.do" print(f'开始处理--{i["单号归属"]}--数据') memo = f'工单号{i["工单号"]}、餐费{i["餐费"]}、住宿{i["住宿"]}、过路过桥费{i["过路过桥费"]}、油费{i["油费"]}、备注{i["备注"]}' # 拼接备注信息 car_infos = self.get_car_details(str(i["车号"]), IDENTIFIER) # 获取车辆信息 pay_type = { "现金": "3", "转账": "2", "欠款": "1" } single_and_double = { "单程": "1", "双程": "2" } colType = pay_type[i["结账方式"]] # 获取结账方式编码 oddEven = single_and_double[i["单双程"]] # 获取单双程编码 now_date = datetime.datetime.now().date().strftime("%Y-%m-%d") # 获取当前日期 .......(此处省略) data["_tp_data"] = data["_tp_data"].replace('"dsName":"83"', '"dsName":"82"') data = parse.urlencode(data).replace("+", "") # 将字典转换成url编码 resp = requests.post(url, headers=self.headers, data=data, verify=False).json() order_id = resp["rowsets"]["com.tp.money.entity.basic.Chartered"]["rows"][0]["recNo"] # 获取订单编号 i["包车单号"] = order_id return data
Le développement d'interface graphique est relativement simple. Si vous ne voulez pas l'embellir, le plug-in natif de Pyqt fera l'affaire. Ici, j'ai emprunté l'expérience du projet précédent et utilisé mes seules connaissances pour créer un. interface sans frontières et embellissement approprié.
Login
from PyQt5.QtCore import Qt from PyQt5.QtGui import QColor from PyQt5.QtWidgets import (QFrame, QMessageBox, QGraphicsDropShadowEffect) from Ui import login_ui from Ui.submit_ui_main import MySubmitForm from submit import TransitSubmit class MyLogin(login_ui.Ui_LoginForm, QFrame): def __init__(self, submit: TransitSubmit): super().__init__() # self.IDENTIFIER = None # self.my_main_window = None self.setupUi(self) self.submit = submit # 设置无边框模式 self.setWindowFlag(Qt.FramelessWindowHint) # 将界面设置为无框 self.setAttribute(Qt.WA_TranslucentBackground) # 将界面属性设置为半透明 self.shadow = QGraphicsDropShadowEffect() # 设定一个阴影,半径为10,颜色为#444444,定位为0,0 self.shadow.setBlurRadius(10) self.shadow.setColor(QColor("#444444")) self.shadow.setOffset(0, 0) self.frame.setGraphicsEffect(self.shadow) # 为frame设定阴影效果 # ------------------------------------------------ self.show() self.pushButton_3.clicked.connect(self.close) # 关闭按钮 self.pushButton_login.clicked.connect(self.do_login) # 登录按钮 # 以下是控制窗口移动的代码 def mousePressEvent(self, event): # 鼠标左键按下时获取鼠标坐标,按下右键取消 if event.button() == Qt.LeftButton: self.m_flag = True self.m_Position = event.globalPos() - self.pos() event.accept() elif event.button() == Qt.RightButton: self.m_flag = False def mouseMoveEvent(self, QMouseEvent): # 鼠标在按下左键的情况下移动时,根据坐标移动界面 if Qt.LeftButton and self.m_flag: self.move(QMouseEvent.globalPos() - self.m_Position) QMouseEvent.accept() def mouseReleaseEvent(self, QMouseEvent): # 鼠标按键释放时,取消移动 self.m_flag = False # 登录事件 def do_login(self): username = self.lineEdit_username.text() password = self.lineEdit_password.text() if not username or not password: QMessageBox.warning(self, '警告', '用户名或密码不能为空', QMessageBox.Yes) return else: IDENTIFIER = self.submit.login(username, password) if not IDENTIFIER: QMessageBox.warning(self, '警告', '用户名或密码错误', QMessageBox.Yes) return self.hide() # 隐藏登录界面 my_submit_form = MySubmitForm(self.submit, IDENTIFIER) my_submit_form.exec_() # 显示主界面
business Operations
class MySubmitForm(submitform_ui.Ui_Dialog_Submit, QDialog): def __init__(self, submit: TransitSubmit, IDENTIFIER: str): super().__init__() ...... self.setupUi(self) ...... self.progressBar.hide() # 关闭进度条显示 self.setWindowFlags(Qt.FramelessWindowHint) # 无边框 self.setAttribute(Qt.WA_TranslucentBackground) # 设置窗口透明 self.pushButton_mini.clicked.connect(self.showMinimized) # 实现最小化 self.pushButton_close.clicked.connect(self.close) # 实现关闭功能 ...... self.show() # 实现鼠标拖拽功能 def mousePressEvent(self, event): self.pressX = event.x() # 记录鼠标按下的时候的坐标 self.pressY = event.y() def mouseMoveEvent(self, event): x = event.x() y = event.y() # 获取移动后的坐标 moveX = x - self.pressX moveY = y - self.pressY # 计算移动了多少 positionX = self.frameGeometry().x() + moveX positionY = self.frameGeometry().y() + moveY # 计算移动后主窗口在桌面的位置 self.move(positionX, positionY) # 移动主窗口 ......
Permettez-moi de dire une chose de plus ici. exec (), il ne peut pas apparaître après une connexion réussie. Il se peut que mes connaissances soient limitées et que je ne puisse pas le faire. En analysant le code source, j'ai découvert que QDialog disposait de cette méthode pour créer une fenêtre contextuelle. Plus tard, je l'ai modifié et j'ai utilisé QDialog pour créer une interface sans bordure.
Je ne dirai pas grand-chose sur le reste du packaging. Il existe de nombreux tutoriels sur Internet. Ce que j'utilise ici, c'est le packaging D, la compression upx et les icônes modifiées. L'ensemble du projet packagé fait plus de 50 Mo.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!