You need to enable JavaScript to run this app. 使用BeautifulSoup爬取cronometer.com无法获取登录后数据怎么办
优惠活动
大模型
产品
解决方案
定价
更多

使用BeautifulSoup爬取cronometer.com无法获取登录后数据怎么办

问题根源
  • cronometer属于单页应用(SPA),所有个人数据都是登录后由JavaScript异步调用接口、再动态渲染到页面上的。你用requests请求拿到的只是站点的初始HTML骨架,requests不会执行JS代码,自然拿不到渲染后的个人数据。
  • 你当前的登录请求虽无报错,但大概率未通过站点的完整身份校验:这类站点通常会在登录时校验JS生成的额外参数、环境指纹等字段,仅靠requests模拟提交表单很容易绕过校验失败,实际并没有真正拿到登录身份。
  • URL中#后面的锚点内容是前端路由使用的,不会发送到服务端,你直接请求带锚点的URL,服务端返回的内容和根域名完全一致,自然拿不到对应页面的数据。
解决方案(基于Selenium实现)

你已经导入了Selenium相关依赖,直接用Selenium替代requests即可:Selenium会自动处理浏览器环境模拟、Cookie存储、JS执行、页面渲染全流程,完全模拟真人操作的效果,不需要自己处理登录校验、异步请求的逻辑。

调整后的代码如下(Hass/AppDaemon相关逻辑保留):

import appdaemon.plugins.hass.hassapi as hass
from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.chrome.options import Options

class Scraper(hass.Hass):

  def initialize(self):
    self.log("Scraper Initialized")
    self.get_values(self)

  def get_values(self,kwargs):
    self.login_url = "https://cronometer.com/login/"
    self.target_url = "https://cronometer.com/#diary"
    self.sensorname = "sensor.scraper"
    self.friendly_name = "Fasting Status"

    # 配置Chrome无头模式,适配AppDaemon无桌面的运行环境
    chrome_options = Options()
    chrome_options.add_argument("--headless=new")
    chrome_options.add_argument("--no-sandbox")
    chrome_options.add_argument("--disable-dev-shm-usage")
    chrome_options.add_argument("user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36")
    # 可选:添加下面这行保留登录状态,下次运行不用重复登录
    # chrome_options.add_argument("--user-data-dir=./chrome_cronometer_data")

    driver = webdriver.Chrome(options=chrome_options)
    
    try:
      # 打开登录页
      driver.get(self.login_url)
      # 等待账号输入框加载完成,超时时间10秒
      WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.NAME, "username")))
      
      # 自动填入账号密码
      driver.find_element(By.NAME, "username").send_keys("替换成你的实际账号")
      driver.find_element(By.NAME, "password").send_keys("替换成你的实际密码")
      # 点击登录按钮
      driver.find_element(By.CSS_SELECTOR, 'button[type="submit"]').click()
      
      # 等待登录后页面加载完成,检测核心容器元素
      WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.ID, "cronometerApp")))
      
      # 跳转到目标页面(比如日记页),等待目标内容加载
      driver.get(self.target_url)
      WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.CLASS_NAME, "diary-item-title")))
      
      # 获取渲染完成的完整页面源码,用BeautifulSoup解析即可
      page = driver.page_source
      soup = BeautifulSoup(page, "html.parser")

      # 你原来的测试选择器可以直接使用
      fasting1 = soup.select('#cronometerApp > div:nth-child(2) > div:nth-child(1) > div > table > tbody > tr > td:nth-child(1) > div > div:nth-child(8) > div > div.diary-item-title > div')
      self.log("TEST 1")
      self.log(fasting1)

      # 拿到数据后更新HomeAssistant传感器
      fasting_status = fasting1[0].text.strip() if fasting1 else "无数据"
      self.set_state(self.sensorname, state= fasting_status, attributes = {"friendly_name": self.friendly_name})

    except Exception as e:
      self.log(f"运行出错:{str(e)}")
    finally:
      # 必须关闭浏览器进程,避免资源残留
      driver.quit()
注意事项
  • 需要确保AppDaemon运行环境已经安装了Chrome/Chromium浏览器和对应版本的ChromeDriver;如果是Docker部署的AppDaemon,需要使用内置浏览器的镜像,或者自行安装对应的依赖包。
  • 如果CSS选择器失效,直接在登录后的浏览器页面右键你需要提取的元素,选择「复制」-「复制选择器」替换即可,不需要手动编写。
  • 如果登录时出现验证码,可根据需求接入打码服务,个人使用建议开启登录状态保留配置,避免重复触发验证码校验。

内容的提问来源于stack exchange,提问作者user1798956

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.14 13:06:05