使用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
相关产品推荐
相关产品推荐

