You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

新手爬虫求助:无法定位UCLA课程页面元素提取信息

解决UCLA课程目录爬虫无法定位元素的问题

核心问题

该UCLA课程目录页面采用动态渲染机制:你通过requests.get()获取的只是页面的初始空白框架,课程数据是在浏览器加载完成后,通过JavaScript异步请求并渲染出来的。因此BeautifulSoup解析的初始HTML中,根本不存在你指定的courseblock、result-item-title这类元素。

解决方案1:用Selenium模拟浏览器加载(适合新手直观理解)

Selenium可以模拟真实浏览器的完整加载流程,等待动态内容渲染完成后再提取数据,代码示例如下:

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
import csv
import time

# 初始化Chrome浏览器(需提前下载对应版本的chromedriver)
driver = webdriver.Chrome()
url = 'https://catalog.registrar.ucla.edu/search?parentAcademicOrg=7e561ea0db6fa0107f1572f5f39619b1&ct=subject'
driver.get(url)

# 等待课程列表元素加载完成,最长等待10秒
wait = WebDriverWait(driver, 10)
course_links = wait.until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, 'a.result-item-link')))

course_data = []

for link in course_links:
    # 提取课程代码与名称
    course_full_title = link.find_element(By.CLASS_NAME, 'result-item-title').text.strip()
    course_code, course_name = course_full_title.split('. ', 1)
    
    # 跳转至详情页提取课程描述
    link.click()
    time.sleep(1)  # 短暂等待详情页加载
    try:
        description = driver.find_element(By.CLASS_NAME, 'courseblockdesc').text.strip()
    except:
        description = '无课程描述'
    
    course_data.append([course_code, course_name, description])
    # 返回课程列表页
    driver.back()
    wait.until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, 'a.result-item-link')))

# 导出数据至CSV文件
with open('ucla_courses.csv', 'w', newline='', encoding='utf-8') as f:
    writer = csv.writer(f)
    writer.writerow(['课程代码', '课程名称', '课程描述'])
    writer.writerows(course_data)

driver.quit()

解决方案2:直接调用API接口(高效推荐)

通过浏览器开发者工具(F12 → 网络面板)可发现,课程数据来自一个POST类型的API接口,直接请求该接口能获取结构化的JSON数据,无需处理页面渲染,效率更高:

import requests
import csv
from bs4 import BeautifulSoup
import time

# 模拟浏览器请求头,避免被反爬拦截
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',
    'Content-Type': 'application/json'
}

# 课程列表API接口
api_url = 'https://catalog.registrar.ucla.edu/api/search'
# 请求参数,可调整pageSize控制每页返回数量
payload = {
    "parentAcademicOrg": "7e561ea0db6fa0107f1572f5f39619b1",
    "ct": "subject",
    "page": 1,
    "pageSize": 100
}

# 获取课程列表
response = requests.post(api_url, json=payload, headers=headers)
course_list = response.json()['results']

course_data = []

for course in course_list:
    course_code = course['code']
    course_name = course['title']
    # 拼接课程详情页URL
    detail_url = f"https://catalog.registrar.ucla.edu/course/{course['slug']}"
    
    # 请求详情页提取课程描述
    detail_res = requests.get(detail_url, headers=headers)
    soup = BeautifulSoup(detail_res.content, 'html.parser')
    desc_element = soup.find('div', class_='courseblockdesc')
    description = desc_element.text.strip() if desc_element else '无课程描述'
    
    course_data.append([course_code, course_name, description])
    time.sleep(0.5)  # 添加短暂延迟,避免请求过于频繁

# 导出至CSV
with open('ucla_courses.csv', 'w', newline='', encoding='utf-8') as f:
    writer = csv.writer(f)
    writer.writerow(['课程代码', '课程名称', '课程描述'])
    writer.writerows(course_data)

注意事项

  • 使用Selenium时,需确保浏览器驱动(如chromedriver)版本与本地浏览器版本一致,并将驱动路径配置到环境变量或代码中。
  • 调用API时,若课程总数超过pageSize,需循环递增page参数,获取所有分页数据。
  • 所有请求需添加合理延迟,避免给目标服务器造成过大压力,同时降低被反爬拦截的概率。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 23:44:55