如何使用Python的Selenium实现Booking.com页面滚动并循环点击“Load more results”按钮加载更多结果
嘿,我看了你遇到的问题——在Booking.com上用Selenium循环加载更多结果的时候卡壳了对吧?别担心,咱们一步步来解决你提出的两个问题,同时优化你的现有代码,让加载逻辑更稳定。
问题1:如何正确滚动以加载更多结果?
Booking.com的“Load more results”按钮有时候会处于视口之外,直接点击可能会因为元素不可见而触发异常(比如元素不可点击)。所以在点击之前,我们需要先把按钮滚动到浏览器的可见区域内,确保Selenium可以正常定位并点击它。
我们可以用Selenium的execute_script方法调用JavaScript的scrollIntoView来实现,这样能精准地把按钮滚动到页面中间,确保它处于可交互状态。
问题2:如何确保循环点击直到没有更多结果?
你的现有循环逻辑方向是对的,但有几个可以优化的点:
- 每次点击按钮后,需要给页面留出足够的时间加载新结果,避免重复点击或者提前终止循环
- 加入滚动到按钮的步骤,避免因元素不可见导致的点击失败
- 补充处理
StaleElementReferenceException——有时候页面刷新后原来定位的按钮会失效,需要重新定位
修改后的完整代码
# Relevant imports from selenium import webdriver from selenium.webdriver.chrome.service import Service from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By from selenium.common.exceptions import ( TimeoutException, NoSuchElementException, StaleElementReferenceException ) import time import random # WebDriver setup driver = webdriver.Chrome(service=Service()) driver.get("https://www.booking.com/searchresults.en-gb.html?ss=cornwall...") driver.maximize_window() # 最大化窗口,减少按钮被遮挡的概率 def handle_no_such_element_exception(data_extraction_task): try: return data_extraction_task() except NoSuchElementException: return None items = [] # 优化后的Load more results逻辑 while True: try: # 等待加载更多按钮可点击 load_more_button = WebDriverWait(driver, 8).until( EC.element_to_be_clickable((By.CSS_SELECTOR, "[data-testid='load-more-button']")) ) # 滚动到按钮所在位置,确保它在视口中可见 driver.execute_script("arguments[0].scrollIntoView({block: 'center', behavior: 'smooth'});", load_more_button) time.sleep(random.uniform(0.8, 1.5)) # 随机等待,模拟人类操作 # 再次确认按钮可点击(避免滚动后元素状态变化) load_more_button = WebDriverWait(driver, 5).until( EC.element_to_be_clickable((By.CSS_SELECTOR, "[data-testid='load-more-button']")) ) load_more_button.click() print("Clicked load more button...") # 等待新结果加载完成(等待Booking.com的加载spinner消失) WebDriverWait(driver, 10).until( EC.invisibility_of_element_located((By.CSS_SELECTOR, "[data-testid='spinner']")) ) time.sleep(random.uniform(0.5, 1)) # 额外缓冲时间,确保页面完全加载 except (TimeoutException, NoSuchElementException, StaleElementReferenceException): print("No more results to load.") break # 原有的Scraping逻辑(保持不变) property_items = driver.find_elements(By.CSS_SELECTOR, "[data-testid='property-card']") for property_item in property_items: title = handle_no_such_element_exception(lambda: property_item.find_element(By.CSS_SELECTOR, "[data-testid='title']").text) address = handle_no_such_element_exception(lambda: property_item.find_element(By.CSS_SELECTOR, "[data-testid='address']").text) review_score = handle_no_such_element_exception(lambda: property_item.find_element(By.CSS_SELECTOR, "[data-testid='review-score']").text) link = handle_no_such_element_exception(lambda: property_item.find_element(By.CSS_SELECTOR, "[data-testid='title-link']").get_attribute("href")) item = { "title": title, "address": address, "review_score": review_score, "link": link } items.append(item) print(f"Scraped {len(items)} properties in total.") driver.quit()
关键修改点说明
滚动到按钮可见区域:
用scrollIntoView把按钮滚动到页面中间,同时加入behavior: 'smooth'让滚动更自然,减少被反爬机制检测到的概率。更稳定的异常处理:
新增了StaleElementReferenceException的捕获——点击按钮后页面DOM可能会更新,原来定位的按钮元素会失效,这个异常可以覆盖这种情况。等待页面加载完成:
点击按钮后,等待Booking.com的加载spinner消失,确保新的结果已经完全加载,再进入下一次循环,避免提前终止或者重复点击。模拟人类操作的随机等待:
用random.uniform设置随机等待时间,代替固定的休眠,降低被反爬机制识别的风险。最大化浏览器窗口:
启动浏览器时调用driver.maximize_window(),减少按钮被页面元素遮挡的可能性。
额外提醒
Booking.com有比较严格的反爬机制,如果你频繁点击加载更多按钮,可能会触发验证码或者IP封禁。建议不要把等待时间设置得太短,必要时可以使用代理IP或者切换浏览器指纹。
备注:内容来源于stack exchange,提问作者ElisJD

