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

Python价格检查器无法运行,卡在Requests网络请求步骤

Python价格检查器无法运行,卡在Requests网络请求步骤

看起来你遇到的核心问题是同步网络请求阻塞了GUI主线程,同时代码里还有几个小bug导致功能无法正常工作,我来一步步帮你解决:


1. 核心问题:网络请求阻塞GUI主线程

你的代码在启动GUI主循环root.mainloop()之前,直接调用了get_price()函数,而requests.get(URL)是同步操作——它会一直等待网络响应,期间GUI主线程完全被卡住,根本没机会渲染界面。

解决办法是把网络请求放到子线程里执行,这样GUI主线程能正常运行。我们可以用Python内置的threading模块实现。


2. 其他代码错误修复

除了主线程阻塞问题,你的代码还有几个逻辑错误:

  • get_price()里的price变量未赋值,且if False:分支永远不会执行,导致数据保存逻辑完全无效
  • load_data()的循环逻辑错误,从最大行号开始遍历还不断递增,会直接越界
  • delete_data()只是清空单元格,不如直接删除行更高效
  • 页面解析逻辑需要调整,才能正确从Komplett的页面提取价格

修改后的完整代码

from customtkinter import *
import openpyxl
from bs4 import BeautifulSoup
import datetime
import requests
import threading

root = CTk()
root.title("Price Checker App")
root.iconbitmap("C:/Users/Axelr/PycharmProjects/PC01/main/Self built/Price checker/icon.ico")
root.geometry("550x300")
set_appearance_mode("dark")
set_default_color_theme("green")

# 初始化Excel文件(如果不存在先创建)
try:
    workbook = openpyxl.load_workbook(filename="price_data.xlsx")
    sheet = workbook.active
except FileNotFoundError:
    workbook = openpyxl.Workbook()
    sheet = workbook.active
    sheet.append(["Date", "Price"])
    workbook.save("price_data.xlsx")

URL = "https://www.komplett.no/product/1217710/mobiler-klokker/mobiltelefoner/iphone-14-128gb-blaa"

def view_history():
    hroot = CTk()
    hroot.title("Price Checker App - History")
    hroot.iconbitmap("C:/Users/Axelr/PycharmProjects/PC01/main/Self built/Price checker/icon.ico")
    hroot.geometry("700x500")
    set_appearance_mode("dark")
    set_default_color_theme("dark-blue")

    def load_data():
        # 清空历史页面已有标签
        for widget in hroot.winfo_children():
            if isinstance(widget, CTkLabel) and widget.cget("text").endswith("Kr"):
                widget.destroy()
        
        # 从第2行开始遍历(第1行是表头)
        row_count = sheet.max_row
        for row in range(2, row_count + 1):
            date = sheet.cell(row, 1).value
            price = sheet.cell(row, 2).value
            if date and price:
                date_price = f"{date}: {price} Kr"
                CTkLabel(master=hroot, text=date_price, text_font=("Roboto", 18)).pack(padx=10, pady=5)

    def delete_data():
        # 从最后一行删除到第2行(保留表头)
        row_count = sheet.max_row
        for row in range(row_count, 1, -1):
            sheet.delete_rows(row)
        workbook.save(filename="price_data.xlsx")
        print("All data deleted!")
        load_data()  # 删除后刷新历史记录

    load_data()
    delete_btn = CTkButton(master=hroot, text="Delete All Data", text_font=("Roboto", 20), command=delete_data)
    delete_btn.pack(padx=20, pady=20)
    hroot.mainloop()

def get_price():
    # 更新GUI价格标签为"加载中..."
    price_label.configure(text="Price: Loading...")
    root.update()

    try:
        htmlpage = requests.get(URL, timeout=10)  # 添加超时避免无限等待
        htmlpage.raise_for_status()  # 抛出HTTP错误
        content = BeautifulSoup(htmlpage.content, "html.parser")
        
        # 从页面提取价格(适配Komplett的页面结构)
        price_element = content.find("span", class_="product-price-now")
        if price_element:
            price = price_element.get_text().replace("kr", "").strip().replace(" ", "")
            price_label.configure(text=f"Price: {price} Kr")
        else:
            price_label.configure(text="Price: Failed to fetch")
            return

        # 保存数据逻辑
        current_datetime = datetime.datetime.now().strftime("%Y-%m-%d")
        placement = sheet.max_row + 1
        
        # 检查当天是否已保存数据
        row_to_check = sheet.max_row
        latest_date_saved = sheet.cell(row_to_check, 1).value if row_to_check >=2 else None
        if latest_date_saved != current_datetime:
            sheet.append([current_datetime, price])
            workbook.save(filename="price_data.xlsx")
            print("Data Saved!")
        else:
            print("Data Already Saved!")
    except Exception as e:
        price_label.configure(text=f"Price: Error - {str(e)}")
        print(f"Request error: {str(e)}")

def start_price_check():
    # 用子线程执行网络请求,避免阻塞GUI
    threading.Thread(target=get_price, daemon=True).start()

# GUI组件
title_label = CTkLabel(master=root, text="Price Checker", text_font=("Roboto", 24))
title_label.pack(padx=20, pady=20)

price_label = CTkLabel(master=root, text="Price: ", text_font=("Roboto", 24))
price_label.pack(padx=20, pady=30)

# 添加检查价格按钮,点击后启动子线程
check_btn = CTkButton(master=root, text="Check Current Price", text_font=("Roboto", 20), command=start_price_check)
check_btn.pack(padx=20, pady=10)

history_btn = CTkButton(master=root, text="Open History", text_font=("Roboto", 24), command=view_history)
history_btn.pack(padx=20, pady=20)

root.mainloop()

关键修改说明

  1. 线程化网络请求:新增start_price_check()函数,用threading.Thread把get_price()放到子线程执行,避免阻塞GUI
  2. 添加超时和错误处理:给requests.get()加了10秒超时,并用try-except捕获网络异常,同时更新GUI提示用户状态
  3. 修复Excel操作逻辑:
    • 处理文件不存在的情况,自动创建带表头的Excel文件
    • 修复历史记录加载的循环逻辑,从第2行(表头后)开始遍历
    • 优化删除数据的逻辑,直接删除行而非清空单元格
  4. 完善价格解析:适配Komplett页面的价格元素结构,正确提取价格
  5. 新增检查按钮:原来的代码自动执行get_price(),现在改成用户点击按钮触发,更符合GUI交互逻辑

备注:内容来源于stack exchange,提问作者axelrothing

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.23 07:54:12