Dockerfile 部署

This commit is contained in:
hjq
2026-06-12 16:30:57 +08:00
parent 9d31b37c7a
commit 86898265c0
2 changed files with 138 additions and 77 deletions

View File

@@ -28,7 +28,7 @@ def get_local_count(conn):
return cursor.fetchone()[0]
def item_exists(cursor, item):
"""判断某条发料明细是否已在数据库中存在(基于发料单号+行号+物料代码组合判断)"""
"""判断某条发料明细是否已在数据库中存在(基于 发料单号 + 行号 + 物料代码 组合判断)"""
wo_number = item.get("workOrdersNumber")
line_no = item.get("lineNumber")
mat_code = item.get("materialCode")
@@ -98,49 +98,61 @@ def fetch_issue_receipt_incremental():
page = get_page(port=9222)
try:
log("INFO", f"正在回到主页起点: {HOME_URL}")
page.get(HOME_URL)
log("INFO", f"正在直接跳转到发料单明细页面...")
page.get("https://yunmes.tftykj.cn/WorkOrdersQuery")
page.wait.load_start()
time.sleep(2)
menus = [
("第一层: 业务统计报表", 'xpath://*[@id="app"]/div/div[1]/div[1]/div[2]/div/div[1]/div/div[10]/div/p'),
("第二层: 生产业务报表(推测)", 'xpath:/html/body/div[7]/div/div[1]/div/div[9]/div/p'),
("第三层: 发料单报表", 'xpath:/html/body/div[8]/div/div[1]/div/div[6]/div/p')
]
log("INFO", "模拟点击左侧导航菜单...")
for name, xpath in menus:
ele = page.ele(xpath, timeout=5)
if ele:
try: ele.click()
except: page.run_js("arguments[0].click();", ele)
time.sleep(1.5)
else:
log("ERR", f"找不到菜单元素: {name}")
return
log("OK", "✅ 成功点开发料单报表界面!")
# 隐藏菜单
blank_xpath = 'xpath://*[@id="app"]/div/div[1]/div[2]/div[1]/div[2]/div[2]/div/div[1]/div'
blank_ele = page.ele(blank_xpath, timeout=3)
if blank_ele:
try: blank_ele.click()
except: page.run_js("arguments[0].click();", blank_ele)
time.sleep(0.5)
log("INFO", f"开启底层数据拦截网: {API_TARGET}")
page.listen.start(API_TARGET)
# 为了能够获取当月的数据,强制设置时间为当月第一天到最后一天,并清理其他条件
import datetime, calendar
now = datetime.datetime.now()
first_day = datetime.date(now.year, now.month, 1).strftime('%Y-%m-%d')
last_day = datetime.date(now.year, now.month, calendar.monthrange(now.year, now.month)[1]).strftime('%Y-%m-%d')
log("INFO", f"正在自动设置查询时间范围: {first_day}{last_day}")
page.run_js(f"""
try {{
var dates = document.querySelectorAll('.datebox-f, .datetimebox-f, .el-date-editor input');
if (dates.length >= 2) {{
dates[0].value = '{first_day}';
dates[1].value = '{last_day}';
dates[0].dispatchEvent(new Event('input', {{ bubbles: true }}));
dates[0].dispatchEvent(new Event('change', {{ bubbles: true }}));
dates[1].dispatchEvent(new Event('input', {{ bubbles: true }}));
dates[1].dispatchEvent(new Event('change', {{ bubbles: true }}));
}}
}} catch(e) {{ console.log(e); }}
""")
time.sleep(1)
# 因为是直接打开 URL数据通常不会自动加载所以尝试点击查询按钮
packet = page.listen.wait(timeout=10)
if not packet:
query_btn_xpath = 'xpath://*[@id="app"]/div/div[1]/div[2]/div[2]/div[1]/div[1]/div/button[1]/span'
query_btn = page.ele(query_btn_xpath, timeout=3)
# 兼容多种查询按钮的查找方式
log("INFO", "尝试寻找并点击页面上的【查询】按钮...")
query_btn = page.ele('text=查询', timeout=3)
if not query_btn:
query_btn = page.ele('xpath://button[contains(., "查询")]', timeout=3)
if query_btn:
try: query_btn.click()
except: page.run_js("arguments[0].click();", query_btn)
packet = page.listen.wait(timeout=15)
else:
log("WARN", "常规选择器找不到查询按钮,尝试使用全局 JS 强行寻找...")
page.run_js("""
var btns = document.querySelectorAll('button, a, .l-btn, .el-button');
for(var i=0; i<btns.length; i++) {
if(btns[i].innerText && btns[i].innerText.indexOf('查询') !== -1) {
btns[i].click();
break;
}
}
""")
packet = page.listen.wait(timeout=15)
if not packet:
log("ERR", "未能拦截到第一页数据,无法获取线上总条数。")
@@ -191,53 +203,49 @@ def fetch_issue_receipt_incremental():
log("INFO", f"🔍 正在检查本页第一条数据: 发料单 {first_item.get('workOrdersNumber')} 行号 {first_item.get('lineNumber')} 物料 {first_item.get('materialCode')}")
for raw_item in items:
# 1. 检查是否存在
if item_exists(cursor, raw_item):
# 发料单的新数据都在最前面。当我们遇到一条已经在数据库里的数据时,
# 说明这之前的数据都是新的,这之后的数据肯定都抓过了,直接停止。
log("INFO", f"🛑 在第 {current_page} 页发现本地已存在的记录 (发料单: {raw_item.get('workOrdersNumber')} 行号: {raw_item.get('lineNumber')} 物料: {raw_item.get('materialCode')}),增量扫描结束!")
should_stop = True
break
# 2. 如果不存在,提取并插入
item = _extract_fields(raw_item)
cursor.execute('''
INSERT INTO issue_receipt_details (
production_order_no, product_material_code, product_material_name, product_material_specification,
work_orders_number, status, material_specification, material_name, material_code,
issue_number, has_issue_number, amount, cost_price, issue_amount,
production_order_remark, detailed_remark, unit_name, warehouse_name, line_number,
work_orders_remark, executor_user_name, material_model, execution_time, materials_user_name,
product_material_model, custom_field, department_information_code, department_information_name,
image_file, issue_amount_total, material_group_code, material_group_name,
numnber_of_reserved_digits, place_ment_strategy, price, sales_order_code
) VALUES (
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
)
''', (
item.get("生产任务单号"), item.get("生产物料代码"), item.get("生产物料名称"), item.get("生产物料规格"),
item.get("发料单号"), item.get("状态"), item.get("物料规格"), item.get("物料名称"), item.get("物料代码"),
item.get("发料数量"), item.get("已发料数量"), item.get("金额"), item.get("成本价"), item.get("发料金额"),
item.get("生产订单备注"), item.get("明细备注"), item.get("单位名称"), item.get("仓库名称"), item.get("行号"),
item.get("发料单备注"), item.get("执行人名称"), item.get("物料型号"), item.get("执行时间"), item.get("领料人"),
item.get("生产物料型号"), item.get("自定义字段"), item.get("部门代码"), item.get("部门名称"),
item.get("图片文件"), item.get("汇总金额"), item.get("物料组代码"), item.get("物料组名称"),
item.get("单价小数位数"), item.get("单价进位策略"), item.get("单价"), item.get("销售订单号")
))
inserted_this_page += 1
total_inserted += 1
# 1. 如果不存在,提取并插入
if not item_exists(cursor, raw_item):
item = _extract_fields(raw_item)
cursor.execute('''
INSERT INTO issue_receipt_details (
production_order_no, product_material_code, product_material_name, product_material_specification,
work_orders_number, status, material_specification, material_name, material_code,
issue_number, has_issue_number, amount, cost_price, issue_amount,
production_order_remark, detailed_remark, unit_name, warehouse_name, line_number,
work_orders_remark, executor_user_name, material_model, execution_time, materials_user_name,
product_material_model, custom_field, department_information_code, department_information_name,
image_file, issue_amount_total, material_group_code, material_group_name,
numnber_of_reserved_digits, place_ment_strategy, price, sales_order_code
) VALUES (
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
)
''', (
item.get("生产任务单号"), item.get("生产物料代码"), item.get("生产物料名称"), item.get("生产物料规格"),
item.get("发料单号"), item.get("状态"), item.get("物料规格"), item.get("物料名称"), item.get("物料代码"),
item.get("发料数量"), item.get("已发料数量"), item.get("金额"), item.get("成本价"), item.get("发料金额"),
item.get("生产订单备注"), item.get("明细备注"), item.get("单位名称"), item.get("仓库名称"), item.get("行号"),
item.get("发料单备注"), item.get("执行人名称"), item.get("物料型号"), item.get("执行时间"), item.get("领料人"),
item.get("生产物料型号"), item.get("自定义字段"), item.get("部门代码"), item.get("部门名称"),
item.get("图片文件"), item.get("汇总金额"), item.get("物料组代码"), item.get("物料组名称"),
item.get("单价小数位数"), item.get("单价进位策略"), item.get("单价"), item.get("销售订单号")
))
inserted_this_page += 1
total_inserted += 1
conn.commit()
log("OK", f"{current_page} 页处理完毕,成功插入 {inserted_this_page} 条新数据。")
if should_stop:
break
else:
log("ERR", f"{current_page} 页数据结构异常,中止。")
break
# 如果当页没有新数据插入,说明已经追上了旧数据,停止抓取
if inserted_this_page == 0 and current_page > 1:
log("OK", "🎉 本页未发现任何新数据,说明增量部分已全部抓取完毕,停止翻页!")
break
# 如果没遇到旧数据,继续点击下一页
delay = random.uniform(1.5, 3.5)
log("INFO", f"⏳ 停顿 {delay:.2f} 秒后点击下一页...")
@@ -245,7 +253,10 @@ def fetch_issue_receipt_incremental():
next_btn = None
for _ in range(3):
next_btn = page.ele('xpath://button[contains(@class, "btn-next")]', timeout=3)
# 优先使用 pagination-next如果不行再尝试 btn-next
next_btn = page.ele('xpath://*[contains(@class, "pagination-next")]', timeout=3)
if not next_btn:
next_btn = page.ele('xpath://button[contains(@class, "btn-next")]', timeout=3)
if next_btn:
break
time.sleep(1)
@@ -259,12 +270,24 @@ def fetch_issue_receipt_incremental():
aria_disabled = next_btn.attr("aria-disabled")
is_disabled_attr = next_btn.attr("disabled") is not None
if "disabled" in class_str or is_disabled_attr or aria_disabled == "true":
# 检查父元素 <li> 是否被禁用
parent_class_str = ""
try:
parent_ele = next_btn.parent()
parent_class_str = str(parent_ele.attr("class"))
except:
pass
if "disabled" in class_str or "disabled" in parent_class_str or is_disabled_attr or aria_disabled == "true":
log("OK", "🏁 下一页按钮已被禁用,已经翻到最后一页。")
break
try: next_btn.click()
except: page.run_js("arguments[0].click();", next_btn)
try:
# 优先使用 JS 点击防止遮挡
page.run_js("arguments[0].click();", next_btn)
except Exception as e:
log("ERR", f"JS 点击失败: {e},尝试普通点击...")
next_btn.click()
packet = page.listen.wait(timeout=15)
if not packet: