ソフトウェア: Pycharm
環境: Python 3.7。 9 (互換性上の理由により、顧客が異なるオペレーティング システムを使用している可能性があることを考慮)
テクニカル ライブラリ: リクエスト、パンダ、Pyqt5 など (詳細については依存関係ファイルを参照)
顧客要求ドキュメントの分析とコミュニケーションを通じて、大まかに次の要件があります:
「単一番号所有権に基づいてデータを 3 つのインターフェイスにバッチで送信する」 "
GUI 操作インターフェイスが必要
さまざまな営業マンのログインをサポート
一般的にPOSTデータ入稿とGUI開発だそうです。
このセクションでは主にクローラー技術を使用します。何千年も変わらない手順は、最初に Web ページを分析することです。
パケット キャプチャにより、パスワードが平文であることがわかり、難易度が半分になります。その後、正しいパスワードを使用してログインします。ログイン成功後の戻り値を分析します。
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
ログインに成功すると、「IDENTIFIER」パラメータが返されることがわかります。値は暗号化された文字列です。これは明らかです。リテラルを見ただけで、つまり、これが役立つはずであることがわかっているので、最初に書き留めてください。
テスト アカウントを使用しているため、このアカウントによって送信されたデータは削除されます。他のアカウントに無効なデータが多量に注入されないように、実際のアカウントは削除されません。ここにエントリーします。ビジネスコードで説明されています。
車両情報の取得
分析の結果、顧客から車両情報が提供されたものの、まだ多くの情報が不足していることが判明しました。自分に必要な情報を補充する。パケット キャプチャにより、車両番号を入力すると Ajax リクエストが開始され、フォーム内のその他の情報が 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
人事情報の取得
パケット経由のフォームに人事情報が見つかりませんでしたキャプチャし、後でそれを発見しました。 関連するデータがページ上で見つかりました。
これは少し面倒で、データを照合するには正規表現を使用する必要があります。
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
リクエストを開始してデータを送信します
ログインによって返された識別子、車両情報、従業員情報などを取得します。顧客と通信することです。指定されたデータを組み合わせてリクエストを開始します。なお、リクエストパラメータはURLエンコードに変換する必要がありますが、このクローラで最も面倒な部分でもありますので、ここではリクエストで送信する必要があるパラメータを示します。
#パラメータが多く、形式要件も比較的厳しく、開発プロセス全体の中で、ここのデバッグも最も時間がかかります。デバッグ後はコードを簡略化する必要がありますが、私はデバッグ後にマージする必要があるマージを変更するのが面倒なので、このセクションは比較的冗長です。
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
GUI 開発は比較的単純です。美化したくない場合は、Pyqt のネイティブ プラグインで十分です。以前のプロジェクトの経験をここに借りました。一部の知識のみを使用して、境界のないインターフェースと適切な美化を実現しました。
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_() # 显示主界面
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) # 移动主窗口 ......
以上がPythonでERPシステムデータを自動入力する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。