页面需两次加载完成,如何用BeautifulSoup抓取目标数据?
问题:抓取需二次渲染页面的目标元素
我尝试抓取页面https://toptees.store/linux-funny-cloud-computing中包含sold文本的<span>元素,但该网站需要两次加载才能完成页面渲染,导致数据无法被抓取。
尝试过的代码
1. requests + BeautifulSoup
import requests from bs4 import BeautifulSoup url = "https://toptees.store/linux-funny-cloud-computing" reqs = requests.get(url) soup = BeautifulSoup(reqs.text, 'lxml') sold = soup.find_all("span", class_='ng-binding') print(sold)
2. Selenium + BeautifulSoup
import time from bs4 import BeautifulSoup from selenium import webdriver from selenium.webdriver.chrome.service import Service from webdriver_manager.chrome import ChromeDriverManager driver = webdriver.Chrome(service=Service(ChromeDriverManager().install())) # ,options=options filepath = 'urls.txt' with open(filepath) as f: urls = [i.strip() for i in f.readlines()] titles = [] for url in urls: driver.get(url) driver.maximize_window() time.sleep(3) soup = BeautifulSoup(driver.page_source, 'lxml') sold = soup.find('span', class_="ng-binding") print(sold)
上述代码的输出均为[],请问如何使用BeautifulSoup成功抓取该页面的目标数据?
解决方案
核心原因
该网站基于AngularJS开发(从ng-binding类可判断),目标数据是通过异步请求动态加载后二次渲染的:
requests只能获取初始静态HTML,拿不到异步加载的内容;- 固定
time.sleep(3)的Selenium代码可能等待时间不足,或者没有精准定位到目标元素。
方案1:优化Selenium + BeautifulSoup(推荐)
用显式等待替代固定睡眠,精准等待目标元素渲染完成,再解析页面:
from bs4 import BeautifulSoup from selenium import webdriver from selenium.webdriver.chrome.service import Service from webdriver_manager.chrome import ChromeDriverManager from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC driver = webdriver.Chrome(service=Service(ChromeDriverManager().install())) filepath = 'urls.txt' with open(filepath) as f: urls = [i.strip() for i in f.readlines()] for url in urls: driver.get(url) driver.maximize_window() try: # 最多等待10秒,直到包含'sold'文本的span元素出现 WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.XPATH, "//span[contains(text(), 'sold')]")) ) # 解析页面并过滤目标元素 soup = BeautifulSoup(driver.page_source, 'lxml') sold_spans = soup.find_all( "span", class_='ng-binding', string=lambda text: text and 'sold' in text.lower() ) print("找到目标元素:", sold_spans) # 提取文本内容 for span in sold_spans: print(span.get_text(strip=True)) except Exception as e: print(f"加载超时或未找到元素: {str(e)}") driver.quit()
关键改进点:
- 显式等待:动态等待元素出现,比固定睡眠更可靠,适配不同网络速度;
- 精准过滤:同时用
class_和文本内容过滤,避免匹配无关的ng-binding元素; - 异常捕获:处理加载超时情况,避免程序崩溃。
方案2:直接抓取数据接口(效率更高)
如果不想用Selenium渲染页面,可以通过浏览器开发者工具(F12)的Network面板,找到返回销量数据的异步接口(通常是XHR/Fetch请求),直接用requests请求接口获取数据:
import requests # 需替换为实际抓包得到的接口地址 api_url = "https://toptees.store/api/product/linux-funny-cloud-computing" headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" } response = requests.get(api_url, headers=headers) if response.status_code == 200: product_data = response.json() # 需根据实际接口返回的字段名调整 sold_count = product_data.get('sold') print(f"{sold_count} sold") else: print("请求接口失败")
说明:
- 接口地址和字段名需要自己抓包确认,不同网站的接口规则不同;
- 这种方式不需要渲染页面,速度远快于Selenium,但需要一定的抓包基础。
内容的提问来源于stack exchange,提问作者Rasedul Islam
相关产品推荐
相关产品推荐

