1

最近有人帮助我从雅虎 NHL 页面获取分数,该页面将以相应的方式打印出球队及其上述分数。这是我的代码:

from bs4 import BeautifulSoup
from urllib.request import urlopen

url = urlopen("http://sports.yahoo.com/nhl/scoreboard?d=2013-01-19")

content = url.read()

soup = BeautifulSoup(content)

def yahooscores():
    results = {}

    for table in soup.find_all('table', class_='scores'):
        for row in table.find_all('tr'):
            scores = []
            name = None
            for cell in row.find_all('td', class_='yspscores'):
                link = cell.find('a')
                if link:
                    name = link.text
                elif cell.text.isdigit():
                    scores.append(cell.text)
            if name is not None:
                results[name] = scores

    for name, scores in results.items():
        print ('%s: %s' % (name, ', '.join(scores)) + '.')

yahooscores()

现在,首先:我将这些东西关联到一个函数中,因为我将不得不不断更改 url 以获取 1 月份每一天的所有值。

这里的问题是,虽然我可以很好地打印分数和团队文本,但我正在努力做到这一点:

Ottawa: 1, 1, 2.
Winnipeg: 1, 0, 0.

Pittsburgh: 2, 0, 1
Philadelphia: 0, 1, 0.

看,我的代码没有这样做。我正在努力实现这一目标,但使过程复杂化的是,这些表都属于同一类“分数”,而且似乎我在它们之间找不到任何不同之处。

简而言之,将团队正确地相互关联,并在两者之间留出空间用于组织。

4

2 回答 2

1

问题是,您将每个团队的结果放入 adict中,但 a 中没有顺序,dict因此您无法跟踪页面上哪个表格的得分(即哪个游戏)。

为了解决这个问题,您可以直接打印结果而不是存储它们,并在外部 for 循环中添加一个额外的换行符:

def yahooscores():
    results = {}

    for table in soup.find_all('table', class_='scores'):

        for row in table.find_all('tr'):
            scores = []
            name = None
            for cell in row.find_all('td', class_='yspscores'):
                link = cell.find('a')
                if link:
                    name = link.text
                elif cell.text.isdigit():
                    scores.append(cell.text)
            if name is not None:
                print ('%s: %s' % (name, ', '.join(scores)) + '.')

        print ""

yahooscores()

或者,如果您想存储分数并稍后显示,您也可以存储每场比赛的球队,并使用它们对结果进行分组:

def yahooscores():
    results = {}

    games = []

    for table in soup.find_all('table', class_='scores'):
        teams = []

        for row in table.find_all('tr'):
            scores = []
            name = None
            for cell in row.find_all('td', class_='yspscores'):
                link = cell.find('a')
                if link:
                    name = link.text
                elif cell.text.isdigit():
                    scores.append(cell.text)
            if name is not None:
                results[name] = scores
                teams.append(name)

        games.append(teams)

    for teams in games:
        for name in teams:
            scores = results[name]
            print ('%s: %s' % (name, ', '.join(scores)) + '.')
        print ""

yahooscores()
于 2013-08-21T01:24:01.270 回答
0

问题是您将表格视为团队的平面列表,而不是分数列表,每个分数列表中有两个团队。

解决此问题的干净方法是更改​​解析页面的方式,以便循环播放游戏,然后为每个游戏存储类似名称和分数的内容。


但也有一个快速而肮脏的解决方案:如果你让团队保持秩序,你可以在事后将它们配对。Adict没有固有的顺序,但OrderedDict保留了插入的顺序。因此,只需更改results = {}results = collections.OrderedDict.

(虽然如果你对这个 dict 做的唯一事情就是迭代它items(),我不确定你为什么想要一本字典。只需做results = [],替换results[name] = scoresresults.append((name, scores)),然后迭代results而不是results.items()。)

现在,如果你想成对打印它们……好吧,你可以很容易地从任何可迭代对象中创建一个迭代器。例如:

def pairs(iterable):
    return zip(*[iter(iterable)]*2)

for (name1, score1), (name2, score2) in pairs(results.items()):
    print ('%s: %s' % (n1, ', '.join(s1)) + '.')
    print ('%s: %s' % (n2, ', '.join(s2)) + '.')
    print

或者,如果你不明白这意味着什么,那么像这样的 hacky 也可以:

pair_done = False
for name, scores in results.items():
    print ('%s: %s' % (name, ', '.join(scores)) + '.')
    if pair_done:
        print
    pair_done = not pair_done

… 或者:

for i, (name, scores) in enumerate(results.items()):
    print ('%s: %s' % (name, ', '.join(scores)) + '.')
    if i % 2:
        print
于 2013-08-21T01:40:47.970 回答