用BeautifulSoup解析HTML表格

2 投票
2 回答
994 浏览
提问于 2025-04-17 07:37

我想从这个课程表中获取某一天的数据:点击这里

我已经用Beautiful Soup这个工具成功地把某一天(比如说星期一或'Mon')的整行数据添加到一个列表里,使用的代码如下:

from BeautifulSoup import BeautifulSoup

day ='Mon'

with open('timetable.txt', 'rt') as input_file:
  html = input_file.read()
  soup = BeautifulSoup(html)
  #finds correct day tag
  starttag = soup.find(text=day).parent.parent
  print starttag
  nexttag = starttag
  row=[]
  x = 0
  #puts all td tags for that day in a list
  while x < 18:
    nexttag = nexttag.nextSibling.nextSibling
    row.append(nexttag)
    x += 1
print row

如你所见,这个命令返回了一个包含TD标签的列表,这些标签组成了课程表中'星期一'的那一行。

我的问题是,我不知道怎么进一步解析或搜索这个返回的列表,以找到相关的信息(比如COMP1740等课程代码)。

如果我能找到方法在列表中的每个元素里搜索课程代码,那么我就可以把这些代码和另一个时间列表结合起来,得到某一天的完整课程表。

欢迎任何帮助!(包括完全不同的方法)

2 个回答

0
from BeautifulSoup import BeautifulSoup
import re

#day input
day ='Thu'
#searches for a module (where html has rowspan="1")
module = re.compile(r'rowspan=\"1\"')
#lengths of module search (depending on html colspan attribute)
#1.5 hour
perlen15 = re.compile(r'colspan=\"3\"')
#2 hour
perlen2 = re.compile(r'colspan=\"4\"')
#2.5 hour etc.
perlen25 = re.compile(r'colspan=\"5\"')
perlen3 = re.compile(r'colspan=\"6\"')
perlen35 = re.compile(r'colspan=\"7\"')
perlen4 = re.compile(r'colspan=\"8\"')
#times correspond to first row of timetable.
times = ['8:00', '8:30', '9:00', '9:30', '10:00', '10:30', '11:00', '11:30', '12:00', '12:30', '13:00', '13:30', '14:00', '14:30', '15:00', '15:30']

#opens full timetable html
with open('timetable.txt', 'rt') as input_file:
  html = input_file.read()
  soup = BeautifulSoup(html)
  #finds correct day tag
  starttag = soup.find(text=day).parent.parent
  nexttag = starttag
  row=[]
  #movement of cursor iterating over times list
  curmv = 0
  #puts following td tags for that day in a list
  for time in times:
    nexttag = nexttag.nextSibling.nextSibling
    #detect if a module is found
    found = module.search(repr(nexttag))
    #detect length of that module
    hour15 = perlen15.search(repr(nexttag))
    hour2 = perlen2.search(repr(nexttag))
    hour25 = perlen25.search(repr(nexttag))
    hour3 = perlen3.search(repr(nexttag))
    hour35 = perlen35.search(repr(nexttag))
    hour4 = perlen4.search(repr(nexttag))
    if found: 
      row.append(times[curmv])
      row.append(nexttag)
      if hour15:
        curmv += 3
      elif hour2:
        curmv += 4
      elif hour25:
        curmv += 5
      elif hour3:
        curmv += 6
      elif hour35:
        curmv += 7
      elif hour4:
        curmv += 8
      else:
        curmv += 2
    else:
      curmv += 1
#write day to html file
with open('output.html', 'wt') as output_file:
  for e in row:
    output_file.write(str(e))  

如你所见,这段代码可以区分一小时和两小时的讲座,还有一小时半、两小时半等不同长度的讲座。

我现在唯一的问题是第32行,我需要一个更好的方法来告诉代码什么时候停止在表格中横向移动,也就是:如何知道何时停止这个循环(在之前的代码中,我用的是 while x < 18:,这只对星期一有效,因为那一行有18个标签。现在我想知道如何让循环在遇到父级的 </tr> 标签时停止?

谢谢!

编辑:我打算尝试使用一个try和except块来捕捉当我把'times'设置到18:00时出现的错误。

编辑2:成功了! :D

1

你可以通过正则表达式来找到像课程编号这样的信息,也就是通过模式匹配来查找。

我不知道你对正则表达式了解多少,但Python里有一个叫're'的模块。比如说,我们要找的模式是“四个字母C-O-M-P后面跟着一个或多个数字”。这个模式用正则表达式表示就是COMP\d+,其中\d代表一个数字,而后面的+表示要找尽可能多的数字(在这个例子里是4个)。

from BeautifulSoup import BeautifulSoup
import re

day ='Mon'
codePat = re.compile(r'COMP\d+')

with open('timetable.txt', 'rt') as input_file:
  html = input_file.read()
  soup = BeautifulSoup(html)
  #finds correct day tag
  starttag = soup.find(text=day).parent.parent
#  print starttag
  nexttag = starttag
  row=[]
  x = 0
  #puts all td tags for that day in a list
  while x < 18:
    nexttag = nexttag.nextSibling.nextSibling
    found = codePat.search(repr(nexttag))
    if found:
      row.append(found.group(0))
    x += 1
print row

这样我就得到了输出,

['COMP1940', 'COMP1550', 'COMP1740']

就像我说的,我不知道你对正则表达式的了解程度,所以如果你能描述一下你想要的模式,我可以试着帮你写出来。如果你想自己动手,这里有一个不错的资源:点击这里

撰写回答