使用Beautiful Soup无法从Angular站点NPTEL抓取课程列表
解决NPTEL课程页面爬取不到
app-course-card标签的问题 问题根源分析
- Requests+BeautifulSoup失效原因:NPTEL课程页面基于Angular框架构建,初始请求返回的HTML仅包含框架占位符,
app-course-card标签是JavaScript动态渲染生成的,不会出现在静态HTML源码中。 - Selenium代码的疏漏:
- 仅使用
implicitly_wait不足以确保元素完全渲染:隐式等待是针对元素查找操作的超时等待,而你直接在页面加载后立即获取page_source,此时Angular可能还未完成课程卡片的渲染。 - 未针对目标元素做显式等待:没有等待
app-course-card元素实际出现在DOM中。 - Headless模式可能导致页面渲染异常:无界面模式下默认窗口尺寸过小,部分页面内容可能不会触发加载。
- 最终代码未尝试提取
app-course-card标签:你的Selenium代码仅返回了页面全部文本,根本没有执行查找目标标签的逻辑。
- 仅使用
修正后的Selenium方案
使用显式等待确保目标元素加载完成,同时优化Headless模式配置:
from selenium import webdriver from selenium.webdriver.chrome.options import Options from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By from bs4 import BeautifulSoup chrome_options = Options() chrome_options.add_argument('--headless=new') # 使用新版Headless模式,兼容性更好 chrome_options.add_argument('--window-size=1920,1080') # 设置窗口尺寸,避免内容不加载 chrome_options.add_argument('--disable-gpu') # 禁用GPU加速,避免Headless模式异常 driver = webdriver.Chrome(options=chrome_options) def extract_nptel_courses(url): driver.get(url) # 显式等待,直到至少一个app-course-card元素出现,超时20秒 try: WebDriverWait(driver, 20).until( EC.presence_of_element_located((By.TAG_NAME, 'app-course-card')) ) except Exception as e: print(f"等待课程卡片加载失败: {e}") return None # 获取渲染完成的页面源码 page_source = driver.page_source soup = BeautifulSoup(page_source, 'html.parser') # 提取所有课程卡片内容 courses = [] for card in soup.select('app-course-card'): # 根据实际DOM结构提取课程名称(可自行扩展提取链接、简介等) course_name = card.find('h3').get_text(strip=True) if card.find('h3') else "未知课程" courses.append(course_name) return courses url = "https://nptel.ac.in/courses" course_list = extract_nptel_courses(url) if course_list: print("获取到的课程列表:") for idx, course in enumerate(course_list, 1): print(f"{idx}. {course}") driver.quit()
更高效的替代方案:直接调用API
Angular页面通常通过API获取数据,你可以通过浏览器开发者工具的「网络」面板,筛选XHR/Fetch请求,找到返回课程列表的API接口。直接请求API可以避免Selenium的性能开销,示例代码:
import requests def get_courses_via_api(): # 替换为实际找到的API地址(需通过浏览器开发者工具确认) api_url = "https://nptel.ac.in/api/courses/list" headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36" } response = requests.get(api_url, headers=headers) if response.status_code == 200: data = response.json() # 根据API返回的JSON结构提取课程信息 courses = [item['courseName'] for item in data.get('courses', [])] return courses else: print(f"API请求失败,状态码:{response.status_code}") return None course_list = get_courses_via_api() if course_list: print("API获取的课程列表:") for course in course_list: print(course)
注意:API接口可能会有变化,需要自行通过浏览器开发者工具确认最新的接口地址和请求参数。
内容的提问来源于stack exchange,提问作者MsA
相关产品推荐
相关产品推荐

