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

使用BeautifulSoup 4解析排班表:关联班次时间与日期的问题

排班表解析问题:班次时间与日期关联失败

问题背景

我正在编写自动化脚本,用于登录公司排班软件,解析排班表数据并打印本周所有排班班次。目前已成功提取班次时间,但无法将其与对应日期关联,尝试ChatGPT协助仍未解决问题,现寻求技术帮助。

排班表HTML结构

<table class="sc-bTmccw sc-laFCIP sc-ctuRtO ibflim hoCFsG gsXXhe">
  <thead>
    <tr>
      <th class="sc-ccJWcV pRLto">America/Chicago</th>
      <th class="sc-gZVZiL kofAkN">
        <div class="sc-bgnbwU cSZwXw">Monday</div>
        <div class="sc-bgnbwU cSZwXw">Sep 25, 2023</div>
      </th>
      <th class="sc-gZVZiL kofAkN">
        <div class="sc-bgnbwU cSZwXw">Tuesday</div>
        <div class="sc-bgnbwU cSZwXw">Sep 26, 2023</div>
      </th>
      <th class="sc-gZVZiL kofAkN">
        <div class="sc-bgnbwU cSZwXw">Wednesday</div>
        <div class="sc-bgnbwU cSZwXw">Sep 27, 2023</div>
      </th>
      <th class="sc-gZVZiL kofAkN">
        <div class="sc-bgnbwU cSZwXw">Thursday</div>
        <div class="sc-bgnbwU cSZwXw">Sep 28, 2023</div>
      </th>
      <th class="sc-gZVZiL kofAkN">
        <div class="sc-bgnbwU cSZwXw">Friday</div>
        <div class="sc-bgnbwU cSZwXw">Sep 29, 2023</div>
      </th>
      <th class="sc-gZVZiL kofAkN">
        <div class="sc-bgnbwU cSZwXw">Saturday</div>
        <div class="sc-bgnbwU cSZwXw">Sep 30, 2023</div>
      </th>
      <th class="sc-gZVZiL kofAkN">
        <div class="sc-bgnbwU cSZwXw">Sunday</div>
        <div class="sc-bgnbwU cSZwXw">Oct 1, 2023</div>
      </th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td class="sc-gVAlfg bWxTWJ">
        <div class="sc-iRaSfU kkorew">12:00 AM</div>
        <div class="sc-iRaSfU kkorew">1:00 AM</div>
        <div class="sc-iRaSfU kkorew">2:00 AM</div>
        <div class="sc-iRaSfU kkorew">3:00 AM</div>
        <div class="sc-iRaSfU kkorew">4:00 AM</div>
        <div class="sc-iRaSfU kkorew">5:00 AM</div>
        <div class="sc-iRaSfU kkorew">6:00 AM</div>
        <div class="sc-iRaSfU kkorew">7:00 AM</div>
        <div class="sc-iRaSfU kkorew">8:00 AM</div>
        <div class="sc-iRaSfU kkorew">9:00 AM</div>
        <div class="sc-iRaSfU kkorew">10:00 AM</div>
        <div class="sc-iRaSfU kkorew">11:00 AM</div>
        <div class="sc-iRaSfU kkorew">12:00 PM</div>
        <div class="sc-iRaSfU kkorew">1:00 PM</div>
        <div class="sc-iRaSfU kkorew">2:00 PM</div>
        <div class="sc-iRaSfU kkorew">3:00 PM</div>
        <div class="sc-iRaSfU kkorew">4:00 PM</div>
        <div class="sc-iRaSfU kkorew">5:00 PM</div>
        <div class="sc-iRaSfU kkorew">6:00 PM</div>
        <div class="sc-iRaSfU kkorew">7:00 PM</div>
        <div class="sc-iRaSfU kkorew">8:00 PM</div>
        <div class="sc-iRaSfU kkorew">9:00 PM</div>
        <div class="sc-iRaSfU kkorew">10:00 PM</div>
        <div class="sc-iRaSfU kkorew">11:00 PM</div>
      </td>
      <td class="sc-gVAlfg sc-bRDiDf bWxTWJ hISnGZ"></td>
      <td class="sc-gVAlfg sc-bRDiDf bWxTWJ hISnGZ">
        <a class="sc-qxRCG sc-gBMFIu iTTzGz ifHVoI" style="height: 325px; transform: translateY(775px);">
          <span class="sc-cQAbrN bHxBCY">
                          <h4 class="sc-gdnLxT sc-dMxQAh fbZdSM tkxgA">Coverage</h4>
                          <span class="sc-jRztuO sc-hAJyxc bGJrvP hdkZRS"><time>3:30 PM - 10:00 PM</time></span>
          <aside></aside>
          </span>
        </a>
      </td>
      <td class="sc-gVAlfg sc-bRDiDf bWxTWJ hISnGZ"></td>
      <td class="sc-gVAlfg sc-bRDiDf bWxTWJ hISnGZ">
        <a class="sc-qxRCG sc-gBMFIu iTTzGz ifHVoI" style="height: 350px; transform: translateY(750px);">
          <span class="sc-cQAbrN bHxBCY">
                          <h4 class="sc-gdnLxT sc-dMxQAh fbZdSM tkxgA">Keyholder</h4>
                          <span class="sc-jRztuO sc-hAJyxc bGJrvP hdkZRS"><time>3:00 PM - 10:00 PM</time></span>
          <aside></aside>
          </span>
        </a>
      </td>
      <td class="sc-gVAlfg sc-bRDiDf bWxTWJ hJzsUD">
        <a class="sc-qxRCG sc-gBMFIu iTTzGz ifHVoI" style="height: 225px; transform: translateY(900px);">
          <span class="sc-cQAbrN bHxBCY">
                          <h4 class="sc-gdnLxT sc-dMxQAh fbZdSM tkxgA">Coverage</h4>
                          <span class="sc-jRztuO sc-hAJyxc bGJrvP hdkZRS"><time>6:00 PM - 10:30 PM</time></span>
          <aside></aside>
          </span>
        </a>
      </td>
      <td class="sc-gVAlfg sc-bRDiDf bWxTWJ hISnGZ">
        <a class="sc-qxRCG sc-gBMFIu iTTzGz ifHVoI" style="height: 350px; transform: translateY(500px);">
          <span class="sc-cQAbrN bHxBCY">
                          <h4 class="sc-gdnLxT sc-dMxQAh fbZdSM tkxgA">Coverage</h4>
                          <span class="sc-jRztuO sc-hAJyxc bGJrvP hdkZRS"><time>10:00 AM - 5:00 PM</time></span>
          <aside></aside>
          </span>
        </a>
      </td>
      <td class="sc-gVAlfg sc-bRDiDf bWxTWJ hISnGZ">
        <a class="sc-qxRCG sc-gBMFIu iTTzGz ifHVoI" style="height: 325px; transform: translateY(250px);">
          <span class="sc-cQAbrN bHxBCY">
                          <h4 class="sc-gdnLxT sc-dMxQAh fbZdSM tkxgA">Keyholder</h4>
                          <span class="sc-jRztuO sc-hAJyxc bGJrvP hdkZRS"><time>5:00 AM - 11:30 AM</time></span>
          <aside></aside>
          </span>
        </a>
      </td>
    </tr>
  </tbody>
</table>

当前BeautifulSoup解析代码

soup = BeautifulSoup(browser.page_source, 'html.parser')

# Find the table headers
table_headers = soup.find_all('th', class_='sc-gZVZiL kofAkN')

# Initialize a dictionary to store the data
data = {}

# Extract column headers (dates) from the table headers
column_headers = [header.find('div', class_='sc-bgnbwU cSZwXw').text.strip() for header in table_headers]

# Find the rows
rows = soup.find_all('tr')

# Initialize variables to store date and time
current_date = ""
current_time_ranges = []

# Extract the data from the rows
for row in rows:
    cells = row.find_all('td')
    if cells:
        # Check if the cell contains coverage information
        coverage_cell = cells[1].find('span', class_='sc-cNAXLz bGJrvP PQKTa')
        if coverage_cell:
            # Extract the time range from the coverage cell
            time_range = coverage_cell.find('time').text.strip()
            current_time_ranges.append(time_range)
        else:
            # If the cell doesn't contain coverage information, use an empty string for the time range
            time_range = ""

        # Extract the data for the remaining cells
        data_row = [column_headers[1]] + current_time_ranges + [info.text.strip() for info in cells[2:]]

        # Store the data in the dictionary
        data[row] = data_row

# Print the extracted data
for key, value in data.items():
    print(key)
    for item in value:
        print(item)

当前输出

Coverage - 3:30 PM - 10:00 PM

Keyholder - 3:00 PM - 10:00 PM
Coverage - 6:00 PM - 10:30 PM
Coverage - 10:00 AM - 5:00 PM
Keyholder - 5:00 AM - 11:30 AM

期望输出

Tue 3:30 PM - 10:00 PM
Thu 3:00 PM - 10:00 PM
Fri 6:00 PM - 10:30 PM
Sat 10:00 AM - 5:00 PM
Sun 5:00 AM - 11:30 AM

解决方案

原代码存在两个核心问题:一是仅检查周一的单元格(cells[1]),未遍历所有日期列;二是班次元素的类名匹配错误。以下是修正后的代码:

from bs4 import BeautifulSoup

soup = BeautifulSoup(browser.page_source, 'html.parser')

# 提取表头中的星期缩写(如Tue、Thu)
day_headers = soup.find_all('th', class_='sc-gZVZiL kofAkN')
day_short_names = [header.find_all('div')[0].text.strip()[:3] for header in day_headers]

# 获取排班数据行及所有日期对应的单元格(跳过左侧时间列)
schedule_row = soup.find('tbody').find('tr')
day_cells = schedule_row.find_all('td')[1:]

# 遍历每个日期单元格,匹配并输出班次信息
for idx, cell in enumerate(day_cells):
    shift_element = cell.find('span', class_='sc-jRztuO sc-hAJyxc bGJrvP hdkZRS')
    if shift_element:
        time_range = shift_element.find('time').text.strip()
        print(f"{day_short_names[idx]} {time_range}")

修正说明

  1. 日期与单元格对齐:通过索引对应表头的星期缩写和tbody中的日期单元格,确保班次与日期一一匹配。
  2. 遍历所有日期列:不再局限于单个单元格,遍历所有日期列查找班次。
  3. 修正类名匹配:使用HTML中实际存在的班次元素类名,确保能正确提取时间信息。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 17:05:54