使用BeautifulSoup遍历标签仅获最后一个主题,如何为每条记录匹配正确主题?
问题分析
你的问题出在内层的for subject in subjects循环上——每次遍历课程容器时,你都会把所有主题过一遍,最后一次赋值的主题会覆盖之前的所有结果,所以每条记录最终都只保留了最后一个主题的内容。
核心解决思路是让每个课程容器和它对应的主题关联起来:从页面结构来看,每个<h2>主题下面应该对应着一组课程容器(panel-heading),所以我们要先遍历每个主题,再抓取该主题下的所有课程,这样就能保证一一对应。
修改后的代码
from urllib.request import urlopen from bs4 import BeautifulSoup as soup import json uci_urls = ['http://ocw.uci.edu/courses'] data =[] # 打开连接并获取页面内容 for uci_url in uci_urls: uClient = urlopen(uci_url) page_html = uClient.read() uClient.close() # HTML解析 page_soup = soup(page_html, "html.parser") # 先遍历每个主题(h2标签) subjects = page_soup.findAll("h2") for subject in subjects: # 定位当前主题对应的课程组:找到h2后面的panel-group容器 panel_group = subject.find_next_sibling("div", {"class": "panel-group"}) if not panel_group: continue # 如果没有找到对应课程组,跳过当前主题 # 获取该主题下的所有课程容器 containers = panel_group.findAll("div", {"class": "panel-heading"}) # 遍历当前主题下的每一门课程 for container in containers: item = {} item['type'] = "Course" item['title'] = container.h3.text.strip() # 清理文本中的多余空白 item['author'] = "University of California Irvine" item['link'] = "http://ocw.uci.edu" + container.a["href"] # 修正链接拼接逻辑 item['source'] = "UCI Open" item['subject'] = subject.text.strip() # 直接关联当前主题,无需重复遍历 item['base_url'] = "http://ocw.uci.edu/" data.append(item) # 写入JSON文件,添加缩进让格式更美观 with open("./json/uci.json", "w") as writeJSON: json.dump(data, writeJSON, ensure_ascii=False, indent=4)
关键修改说明
- 调整遍历顺序:从「先遍历所有课程,再遍历所有主题」改成「先遍历主题,再遍历该主题下的课程」,从根源上保证课程和主题的对应关系。
- 精准定位课程组:用
find_next_sibling()找到当前主题对应的课程容器组,避免全局抓取导致的关联错误。 - 移除冗余循环:直接将当前遍历的主题文本赋值给课程的
subject字段,不再重复遍历所有主题。 - 细节优化:
- 用
strip()清理文本中的多余空白,让数据更整洁; - 修正了链接拼接的逻辑(原
href是相对路径,直接和域名拼接即可); - 给
json.dump()添加indent=4,生成格式化的JSON文件,方便后续查看。
- 用
内容的提问来源于stack exchange,提问作者brawlins4
相关产品推荐
相关产品推荐

