269 lines
10 KiB
Python
Executable File
269 lines
10 KiB
Python
Executable File
import requests
|
|
import os
|
|
import time
|
|
from datetime import datetime
|
|
import hashlib
|
|
import uuid
|
|
from sqlalchemy import select, create_engine, Table, Column, String, MetaData, text
|
|
from sqlalchemy.dialects.mysql import insert
|
|
|
|
class LoginClient:
|
|
def __init__(self):
|
|
self.base_url = "https://116.10.244.81:28001"
|
|
self.session = requests.Session()
|
|
# 禁用SSL验证警告
|
|
requests.packages.urllib3.disable_warnings()
|
|
|
|
def get_captcha(self):
|
|
"""获取验证码图片"""
|
|
# 生成随机cid
|
|
cid = uuid.uuid4().hex.encode()
|
|
cid = hashlib.sha256(cid).hexdigest()
|
|
|
|
url = f"{self.base_url}/api/vss-auth-center/v1/captcha"
|
|
headers = {
|
|
"Accept": "image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8",
|
|
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
|
|
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 Edg/135.0.0.0",
|
|
"Referer": f"{self.base_url}/vss-em-iui/"
|
|
}
|
|
params = {"cid": cid}
|
|
|
|
response = self.session.get(url, headers=headers, params=params, verify=False)
|
|
|
|
# 缓存验证码到本地
|
|
captcha_path = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))),
|
|
'static', 'captcha.png')
|
|
with open(captcha_path, "wb") as f:
|
|
f.write(response.content)
|
|
|
|
return cid
|
|
|
|
def login(self, account, password, validcode, cid):
|
|
"""执行登录"""
|
|
url = f"{self.base_url}/api/vss-auth-center/v1/user/login"
|
|
|
|
headers = {
|
|
"Accept": "application/json, text/plain, */*",
|
|
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
|
|
"Content-Type": "application/json",
|
|
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 Edg/135.0.0.0",
|
|
"Referer": f"{self.base_url}/vss-em-iui/",
|
|
"language": "zh-CN"
|
|
}
|
|
|
|
params = {
|
|
"cutype": "12"
|
|
}
|
|
|
|
data = {
|
|
"account": account,
|
|
"password": password,
|
|
"validcode": validcode,
|
|
"cid": cid
|
|
}
|
|
|
|
response = self.session.post(
|
|
url,
|
|
headers=headers,
|
|
params=params,
|
|
json=data,
|
|
verify=False
|
|
)
|
|
|
|
return response.json()
|
|
|
|
def get_online_info(self, token, page=1, page_size=1500):
|
|
"""获取在线信息"""
|
|
url = f"{self.base_url}/api/vss-user-business/v1/pus/queryPage/4109"
|
|
|
|
headers = {
|
|
"Accept": "application/json, text/plain, */*",
|
|
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
|
|
"Authoration": token,
|
|
"Cache-Control": "no-cache",
|
|
"Connection": "keep-alive",
|
|
"Content-Type": "application/json",
|
|
"Referer": f"{self.base_url}/vss-em-iui/",
|
|
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 Edg/135.0.0.0",
|
|
"language": "zh-CN"
|
|
}
|
|
|
|
# 生成防伪标识
|
|
forgery_defense = uuid.uuid4().hex
|
|
|
|
params = {
|
|
"page_size": page_size,
|
|
"page": page,
|
|
"pu_name": "",
|
|
"puid": "",
|
|
"protocol": "",
|
|
"nodeid": "",
|
|
"popunitid": "",
|
|
"status": "",
|
|
"forgerydefense": forgery_defense,
|
|
"csrftoken": forgery_defense
|
|
}
|
|
|
|
response = self.session.get(
|
|
url,
|
|
headers=headers,
|
|
params=params,
|
|
verify=False
|
|
)
|
|
|
|
return response.json()
|
|
|
|
def get_existing_channels(engine, channels_table):
|
|
"""获取数据库中现有的通道状态"""
|
|
with engine.connect() as conn:
|
|
query = select(channels_table.c.puid, channels_table.c.status)
|
|
result = conn.execute(query)
|
|
return {row.puid: row.status for row in result}
|
|
|
|
def update_device_status(engine):
|
|
"""更新设备状态"""
|
|
with engine.connect() as conn:
|
|
# 获取channels表和device表的数据
|
|
channels_query = """
|
|
SELECT puid, status, pu_name
|
|
FROM channels
|
|
"""
|
|
channels_result = conn.execute(text(channels_query))
|
|
channels_data = {row.puid: {'status': row.status, 'pu_name': row.pu_name} for row in channels_result}
|
|
|
|
# 获取device表中的puid
|
|
device_query = """
|
|
SELECT puid
|
|
FROM device
|
|
"""
|
|
device_result = conn.execute(text(device_query))
|
|
|
|
# 更新设备状态
|
|
updates = []
|
|
for row in device_result:
|
|
puid = row.puid
|
|
if puid in channels_data:
|
|
# 更新在线状态
|
|
is_normal = 1 if channels_data[puid]['status'] == 'online' else 0
|
|
|
|
# 检查使用状态
|
|
pu_name = channels_data[puid]['pu_name']
|
|
in_use = 0 if any(keyword in pu_name for keyword in ['无学生', '丢失']) else 1
|
|
|
|
# 构建更新语句
|
|
update_query = """
|
|
UPDATE device
|
|
SET is_normal = :is_normal, in_use = :in_use
|
|
WHERE puid = :puid
|
|
"""
|
|
updates.append({
|
|
'puid': puid,
|
|
'is_normal': is_normal,
|
|
'in_use': in_use
|
|
})
|
|
|
|
if updates:
|
|
update_stmt = text("""
|
|
UPDATE device
|
|
SET is_normal = :is_normal, in_use = :in_use
|
|
WHERE puid = :puid
|
|
""")
|
|
conn.execute(update_stmt, updates)
|
|
conn.commit()
|
|
print(f"成功更新 {len(updates)} 个设备状态")
|
|
|
|
def main():
|
|
client = LoginClient()
|
|
|
|
while True:
|
|
cid = client.get_captcha()
|
|
print("验证码已保存为captcha.png")
|
|
validcode = input("请查看captcha.png并输入验证码: ")
|
|
password = "Root1234#"
|
|
hashed_password = hashlib.sha256(password.encode()).hexdigest()
|
|
|
|
result = client.login(
|
|
account="DHDX001",
|
|
password=hashed_password,
|
|
validcode=validcode,
|
|
cid=cid
|
|
)
|
|
|
|
if result.get("result") == 0:
|
|
token = result.get("token")
|
|
|
|
online_info = client.get_online_info(token)
|
|
if online_info.get("result") == 0:
|
|
rows = online_info.get("rows", [])
|
|
filtered_rows = [
|
|
row for row in rows
|
|
if "大化4+N摄像头" not in row.get("pu_name", "")
|
|
and "大化幼儿园监控" not in row.get("pu_name", "")
|
|
]
|
|
|
|
engine = create_engine('mysql+pymysql://4an:GtbJp6Ai5azntnTB@10.10.10.253/4an')
|
|
metadata = MetaData()
|
|
channels = Table(
|
|
'channels', metadata,
|
|
Column('puid', String(50), primary_key=True),
|
|
Column('pu_name', String(200)),
|
|
Column('status', String(20)),
|
|
Column('update_time', String(50))
|
|
)
|
|
metadata.create_all(engine)
|
|
|
|
existing_channels = get_existing_channels(engine, channels)
|
|
|
|
current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
update_data = []
|
|
|
|
for row in filtered_rows:
|
|
puid = row.get('puid')
|
|
current_status = row.get('status')
|
|
|
|
if puid not in existing_channels or existing_channels[puid] != current_status:
|
|
|
|
update_data.append({
|
|
'puid': puid,
|
|
'pu_name': row.get('pu_name'),
|
|
'status': current_status,
|
|
'update_time': current_time
|
|
})
|
|
|
|
# 执行更新
|
|
if update_data:
|
|
with engine.connect() as conn:
|
|
stmt = insert(channels).on_duplicate_key_update(
|
|
pu_name=channels.c.pu_name,
|
|
status=channels.c.status,
|
|
update_time=channels.c.update_time
|
|
)
|
|
conn.execute(stmt, update_data)
|
|
conn.commit()
|
|
print(f"\n成功更新 {len(update_data)} 条记录")
|
|
else:
|
|
print("\n没有需要更新的记录")
|
|
|
|
# 更新设备状态
|
|
print("\n开始更新设备状态...")
|
|
update_device_status(engine)
|
|
|
|
return
|
|
else:
|
|
print("获取通道信息失败!")
|
|
print(f"错误信息: {online_info.get('err_msg', '未知错误')}")
|
|
return # 获取信息失败也退出程序
|
|
|
|
else:
|
|
print("登录失败!")
|
|
print(result)
|
|
if result.get("result") == 12: # 验证码错误
|
|
retry = input("验证码错误,是否重新获取验证码?(y/n): ")
|
|
if retry.lower() != 'y':
|
|
return
|
|
else:
|
|
return # 其他错误直接退出
|
|
|
|
if __name__ == "__main__":
|
|
main() |