You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修复openpyxl中赔率着色异常及赛事匹配丢失问题

博彩赛事赔率处理脚本问题修复

问题说明

现有Python脚本功能:

  • 调用子进程运行爬虫,从两个博彩网站抓取赛事及赔率写入xlsx文件
  • 使用Fuzzywuzzy匹配赛事名称,将更高赔率标绿、更低赔率标红,按赔率差值排序

当前存在两个问题:

  1. 赔率着色随机异常
  2. 不运行子进程的情况下第二次执行代码时,首个赛事丢失

问题根源分析

  1. 着色异常:原代码先设置单元格格式,再重新写入排序后的数据,导致格式被默认字体覆盖;且百分比差值计算逻辑嵌套在rate2存在的判断分支中,部分赛事数据未进入排序列表。
  2. 首个赛事丢失:原代码写入数据时从第1行开始,覆盖了表头;第二次读取时从第2行开始,导致第1行的赛事数据被遗漏。

修复方案及修改后代码

import subprocess
from openpyxl import load_workbook
from plyer import notification
from openpyxl.styles import Font, Color
from fuzzywuzzy import fuzz
from operator import itemgetter

# 可选:运行爬虫脚本,注释此行可跳过爬虫直接处理现有文件
subprocess.run(['python', r'C:\Users\Kryštof\PycharmProjects\pythonProject2\Combined sure bets.py'])

# 加载XLSX文件
xlsx_file = r'C:\Users\Kryštof\Desktop\Sure Bets\match_details.xlsx'
wb = load_workbook(xlsx_file)
ws = wb.active

# 存储赛事和赔率的字典
tip_sport_matches = {}
betano_matches = {}

# 读取数据(从第2行开始,保留第1行表头)
for row in ws.iter_rows(min_row=2, max_row=ws.max_row, min_col=1, max_col=7, values_only=True):
    tip_sport_name = row[0]
    betano_name = row[4]
    tip_sport_rate1 = row[1]
    tip_sport_rate2 = row[2]
    betano_rate1 = row[5]
    betano_rate2 = row[6]

    if tip_sport_name:
        tip_sport_matches[tip_sport_name] = {
            'rate1': tip_sport_rate1,
            'rate2': tip_sport_rate2
        }
    if betano_name:
        betano_matches[betano_name] = {
            'rate1': betano_rate1,
            'rate2': betano_rate2
        }

# 清空原有数据行(保留第1行表头)
ws.delete_rows(2, ws.max_row)

# 匹配赛事并收集数据,不直接写入表格
matched_data = []
unmatched_tipsport = []
unmatched_betano = []

# 匹配赛事
tip_sport_copy = tip_sport_matches.copy()
betano_copy = betano_matches.copy()

for tip_name, tip_rates in tip_sport_copy.items():
    for bet_name, bet_rates in betano_copy.items():
        if fuzz.token_set_ratio(tip_name, bet_name) >= 80:
            # 收集匹配数据,包含赔率差值计算
            rate1_ts = float(tip_rates['rate1']) if tip_rates['rate1'] else None
            rate2_ts = float(tip_rates['rate2']) if tip_rates['rate2'] else None
            rate1_bet = float(bet_rates['rate1']) if bet_rates['rate1'] else None
            rate2_bet = float(bet_rates['rate2']) if bet_rates['rate2'] else None
            
            # 计算赔率差值总和(仅当两组赔率都存在时)
            percentage_sum = 0.0
            if rate1_ts and rate1_bet:
                percentage_sum += abs((rate1_ts - rate1_bet)/rate1_ts * 100)
            if rate2_ts and rate2_bet:
                percentage_sum += abs((rate2_ts - rate2_bet)/rate2_ts * 100)
            
            matched_data.append({
                'percentage_sum': percentage_sum,
                'tip_name': tip_name,
                'rate1_ts': rate1_ts,
                'rate2_ts': rate2_ts,
                'bet_name': bet_name,
                'rate1_bet': rate1_bet,
                'rate2_bet': rate2_bet
            })
            # 从副本中删除已匹配项
            del tip_sport_matches[tip_name]
            del betano_matches[bet_name]
            break  # 避免一个赛事匹配多个对手

# 收集未匹配数据
for tip_name, tip_rates in tip_sport_matches.items():
    unmatched_tipsport.append({
        'tip_name': tip_name,
        'rate1_ts': float(tip_rates['rate1']) if tip_rates['rate1'] else None,
        'rate2_ts': float(tip_rates['rate2']) if tip_rates['rate2'] else None
    })

for bet_name, bet_rates in betano_matches.items():
    unmatched_betano.append({
        'bet_name': bet_name,
        'rate1_bet': float(bet_rates['rate1']) if bet_rates['rate1'] else None,
        'rate2_bet': float(bet_rates['rate2']) if bet_rates['rate2'] else None
    })

# 按赔率差值总和降序排序匹配数据
matched_data.sort(key=itemgetter('percentage_sum'), reverse=True)

# 写入匹配数据(从第2行开始)
current_row = 2
for item in matched_data:
    ws.cell(row=current_row, column=1).value = item['tip_name']
    ws.cell(row=current_row, column=2).value = item['rate1_ts']
    ws.cell(row=current_row, column=3).value = item['rate2_ts']
    ws.cell(row=current_row, column=4).value = f"{item['percentage_sum']:.2f}%"
    ws.cell(row=current_row, column=5).value = item['bet_name']
    ws.cell(row=current_row, column=6).value = item['rate1_bet']
    ws.cell(row=current_row, column=7).value = item['rate2_bet']
    current_row += 1

# 写入未匹配TipSport数据
for item in unmatched_tipsport:
    ws.cell(row=current_row, column=1).value = item['tip_name']
    ws.cell(row=current_row, column=2).value = item['rate1_ts']
    ws.cell(row=current_row, column=3).value = item['rate2_ts']
    current_row += 1

# 写入未匹配Betano数据
for item in unmatched_betano:
    ws.cell(row=current_row, column=5).value = item['bet_name']
    ws.cell(row=current_row, column=6).value = item['rate1_bet']
    ws.cell(row=current_row, column=7).value = item['rate2_bet']
    current_row += 1

# 着色逻辑:所有数据写入完成后统一设置格式
GREEN = '00FF00'
RED = 'FF0000'
for row_num in range(2, current_row):
    # 获取单元格值
    rate1_ts = ws.cell(row=row_num, column=2).value
    rate2_ts = ws.cell(row=row_num, column=3).value
    rate1_bet = ws.cell(row=row_num, column=6).value
    rate2_bet = ws.cell(row=row_num, column=7).value

    # 处理rate1着色
    if rate1_ts is not None and rate1_bet is not None:
        if rate1_ts > rate1_bet:
            ws.cell(row=row_num, column=2).font = Font(color=Color(rgb=GREEN))
            ws.cell(row=row_num, column=6).font = Font(color=Color(rgb=RED))
        elif rate1_ts < rate1_bet:
            ws.cell(row=row_num, column=2).font = Font(color=Color(rgb=RED))
            ws.cell(row=row_num, column=6).font = Font(color=Color(rgb=GREEN))
    
    # 处理rate2着色
    if rate2_ts is not None and rate2_bet is not None:
        if rate2_ts > rate2_bet:
            ws.cell(row=row_num, column=3).font = Font(color=Color(rgb=GREEN))
            ws.cell(row=row_num, column=7).font = Font(color=Color(rgb=RED))
        elif rate2_ts < rate2_bet:
            ws.cell(row=row_num, column=3).font = Font(color=Color(rgb=RED))
            ws.cell(row=row_num, column=7).font = Font(color=Color(rgb=GREEN))

# 保存文件
wb.save(xlsx_file)

# 发送完成通知
notification.notify(
    title='代码执行完成',
    message='赛事赔率处理已完成',
    app_icon=None,
    timeout=10
)

关键修改点

  1. 保留表头:写入数据从第2行开始,避免覆盖表头;读取数据始终从第2行开始,确保不会遗漏数据。
  2. 数据先收集后写入:先把所有匹配、未匹配数据收集到列表,排序后再统一写入表格,避免多次修改单元格导致的格式丢失。
  3. 着色逻辑后置:所有数据写入完成后再执行着色操作,确保格式不会被后续的数据写入覆盖。
  4. 修复差值计算逻辑:将百分比差值计算从rate2的判断分支中移出,确保所有匹配赛事都能计算差值并参与排序。

内容的提问来源于stack exchange,提问作者Kryštof Bochníček

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 10:16:38