Python爬虫脚本问题:如何从函数返回多个值优化Garmin数据爬取
问题解决与代码优化
1. 函数返回多个值的正确方式
你用return result_2 and hr_value是错误的——这是逻辑运算,只会返回最后一个为真的值,而非两个独立结果。Python中返回多个值只需用逗号分隔,返回一个元组即可:
return result_2, hr_value
调用时直接将元组解包到两个变量,这样只需要执行一次搜索,不用重复调用函数:
distance_walked, heart_rate_walk = get_distance_and_hr("Walking")
2. 心率提取的潜在问题修复
核心问题点:
- XPath定位可能失效:Garmin页面结构若有变动,
div[5]//div[4]未必对应心率模块,建议基于元素属性或文本特征定位; - 文本处理不健壮:
rstrip(" bpm")无法适配非标准格式的文本,改用replace或split更稳妥; - 未处理元素缺失情况:若找不到心率元素,直接读取
val.text会抛出异常,需增加异常捕获或存在性判断。
修改后的get_distance_and_hr函数:
def get_distance_and_hr(activity): time.sleep(2) search_box = driver.find_element("name", "search") search_box.clear() search_box.send_keys(activity) search_box.send_keys(Keys.RETURN) time.sleep(3) total_distance = 0.0 total_hr = 0 count_hr = 0 # 统计有效心率数据的次数,用于计算平均值 # 定位当天的所有活动项 activity_items = driver.find_elements(By.XPATH, f"//span[text()='{x}']//ancestor::div[@class='list-item-container']") for item in activity_items: # 提取距离 try: distance_elem = item.find_element(By.XPATH, ".//div[5]//div[1]//span//span[1]") if distance_elem.text: distance_val = float(distance_elem.text.replace(" km", "")) total_distance += distance_val except: pass # 无距离数据则跳过 # 提取心率 try: hr_elem = item.find_element(By.XPATH, ".//div[5]//div[4]//span//span") if hr_elem.text and "bpm" in hr_elem.text: hr_val = float(hr_elem.text.replace(" bpm", "")) total_hr += hr_val count_hr += 1 except: pass # 无心率数据则跳过 # 计算平均心率,避免除以0的情况 avg_hr = total_hr / count_hr if count_hr > 0 else 0 return total_distance, avg_hr
3. 其他优化点
- 补充缺失的
webdriver导入:原代码中缺少from selenium import webdriver,会导致运行报错; - 用显式等待替代固定
time.sleep:比如WebDriverWait(driver, 10).until(EC.presence_of_element_located(...)),比固定等待时间更可靠; - 脚本结束后关闭浏览器:添加
driver.quit()释放资源。
完整修改后的代码
from selenium.webdriver.common.keys import Keys from selenium.webdriver.common.by import By import login as login from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC import datetime import time from selenium import webdriver # 补充缺失的导入 x = datetime.datetime.now() x = x.strftime("%b %d") driver = webdriver.Firefox() driver.set_window_size(1512, 1000) driver.get("https://connect.garmin.com/modern/activities") # 显式等待登录iframe加载 iframe = WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.ID, "gauth-widget-frame-gauth-widget")) ) driver.switch_to.frame(iframe) # 登录操作 WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.NAME, "username"))).send_keys(login.username) password_box = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.NAME, "password"))) password_box.send_keys(login.password) password_box.send_keys(Keys.RETURN) driver.switch_to.default_content() # 等待主页搜索框加载完成 WebDriverWait(driver, 15).until(EC.presence_of_element_located((By.NAME, "search"))) def get_distance_and_hr(activity): search_box = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.NAME, "search"))) search_box.clear() search_box.send_keys(activity) search_box.send_keys(Keys.RETURN) # 等待搜索结果加载 WebDriverWait(driver, 10).until(EC.presence_of_all_elements_located((By.XPATH, f"//span[text()='{x}']//ancestor::div[@class='list-item-container']"))) total_distance = 0.0 total_hr = 0 count_hr = 0 activity_items = driver.find_elements(By.XPATH, f"//span[text()='{x}']//ancestor::div[@class='list-item-container']") for item in activity_items: # 提取距离 try: distance_elem = item.find_element(By.XPATH, ".//div[5]//div[1]//span//span[1]") if distance_elem.text: distance_val = float(distance_elem.text.replace(" km", "")) total_distance += distance_val except: pass # 提取心率 try: hr_elem = item.find_element(By.XPATH, ".//div[5]//div[4]//span//span") if hr_elem.text and "bpm" in hr_elem.text: hr_val = float(hr_elem.text.replace(" bpm", "")) total_hr += hr_val count_hr += 1 except: pass avg_hr = total_hr / count_hr if count_hr > 0 else 0 return total_distance, avg_hr # 一次调用获取距离和心率 distance_walked, heart_rate_walk = get_distance_and_hr("Walking") print(f"Distance walked today is {distance_walked:.2f} km and average BPM is {heart_rate_walk:.1f}") # 关闭浏览器释放资源 driver.quit()
内容的提问来源于stack exchange,提问作者Zeno
相关产品推荐
相关产品推荐

