Comment corriger le code HTML non conforme afin qu'Expat analyse le contenu (htmltidy ne fonctionne pas)

StackOverflow https://stackoverflow.com/questions/1814731

Question

J'essaie d'extraire des informations de http://www.nfl.com/scores . (en particulier, découvrez la fin d'un jeu pour que mon ordinateur puisse arrêter de l'enregistrer). Je peux télécharger le code HTML assez facilement, et cette déclaration concerne le respect des normes:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">

Mais

  1. Une tentative d’analyse avec Expat génère l’erreur mal formée. (jeton non valide) .

  2. Le service de validation en ligne du W3C rapporte 399 erreurs et 121 avertissements.

  3. J'ai essayé d'exécuter HTML tidy (simplement appelé tidy ) sur mon système Linux avec l'option -xml , mais nettoie 56 avertissements et 117 erreurs et est incapable de récupérer un bon fichier XML. Les erreurs ressemblent à ceci:

    line 409 column 122 - Warning: unescaped & or unknown entity "&role"
    ...
    line 409 column 172 - Warning: unescaped & or unknown entity "&tabSeq"
    ...
    line 1208 column 65 - Error: unexpected </td> in <br>
    line 1209 column 57 - Error: unexpected </tr> in <br>
    line 1210 column 49 - Error: unexpected </table> in <br>
    

    Mais lorsque je vérifie la saisie, les "entités inconnues" semble faire partie d'une URL correctement citée, donc je ne sais pas si un guillemet double manque quelque part ou quoi.

Je sais qu’il existe quelque chose capable d’analyser ces informations car Firefox et w3m affichent tous les deux une valeur raisonnable. Quel outil corrigera le code HTML non conforme afin qu'il puisse être analysé avec Expat?

Était-ce utile?

La solution

Il y a un tableau de bord à mise à jour automatique basé sur Flash au sommet de nfl.com. Une certaine surveillance de son trafic réseau détecte:

http://www.nfl.com/liveupdate/scorestrip/ss.xml

Cela sera probablement un peu plus facile à analyser que le tableau de bord HTML.

Autres conseils

Ils utilisent une sorte de Javascript sur les boîtes de score, vous devrez donc jouer des astuces plus astucieuses (la ligne casse la mienne):

/* box of awesome */
// iscurrentweek ? true;
(new nfl.scores.Game('2009112905','54635',{state:'pre',container:'scorebox-2009112905',
wrapper:'sb-wrapper-2009112905',template:($('scorebox-2009112905').innerHTML),homeabbr:'NYJ',
awayabbr:'CAR'}));

Cependant, pour répondre à votre question, BeautifulSoup l’analyse (apparemment) très bien:

fp = urlopen("http://www.nfl.com/scores")
data = ""
while 1:
    r = fp.read()
    if not r:
        break
    data += r
fp.close()

soup = BeautifulSoup(data)
print soup.contents[2].contents[1].contents[1]

Sorties:

<title>NFL Scores: 2009 - Week 12</title>

Il serait peut-être plus facile de gratter le le tableau de bord NFL de Yahoo , à mon avis ... en fait , off pour l'essayer.

MODIFIER: Utilisez votre question comme excuse pour apprendre à utiliser BeautifulSoup. Alex Martelli a chanté ses louanges, alors je me suis dit que cela valait la peine d’être essayé - mec, je suis impressionné.

Quoi qu’il en soit, j’ai pu concocter un grattoir à partitions rudimentaire de Yahoo! tableau de bord, comme suit:

def main():
    soup = BeautifulSoup(YAHOO_SCOREBOARD)
    on_first_team = True
    scores = []
    hold = None

    # Iterate the tr that contains a team's box score
    for item in soup(name="tr", attrs={"align": "center", "class": "ysptblclbg5"}):
        # Easy
        team = item.b.a.string

        # Get the box scores since we're industrious
        boxscore = []
        for quarter in item(name="td", attrs={"class": "yspscores"}):
            boxscore.append(int(quarter.string))

        # Final score
        sub = item(name="span", attrs={"class": "yspscores"})[0]
        if sub.b:
            # Winning score
            final = int(sub.b.string)
        else:
            data = sub.string.replace("&nbsp;", "")
            if ":" in data:
                # Catch TV: XXX and 0:00pm ET
                final = None
            else:
                try: final = int(data)
                except: final = None

        if on_first_team:
            hold = { team : (boxscore, final) }
            on_first_team = False
        else:
            hold[team] = (boxscore, final)
            scores.append(hold)
            on_first_team = True

    for game in scores:
        print "--- Game ---"
        for team in game:
            print team, game[team]

Je voudrais modifier cela dimanche pour voir comment cela fonctionne, car c'est vraiment difficile. Voici ce qu’il affiche en ce moment:

--- Game ---
Green Bay ([0, 13, 14, 7], 34)
Detroit ([7, 0, 0, 5], 12)
--- Game ---
Oakland ([0, 0, 7, 0], 7)
Dallas ([3, 14, 0, 7], 24)

Regardez ça, j'ai aussi accroché des scores dans les box ... pour un jeu qui n'a pas encore eu lieu, nous obtenons:

--- Game ---
Washington ([], None)
Philadelphia ([], None)

Quoi qu’il en soit, un piquet à partir duquel vous pourrez sauter. Bonne chance.

Recherchez tagsoup . Si vous voulez vous retrouver avec une arborescence DOM ou un flux SAX en Java, c'est le ticket. Si vous souhaitez simplement extraire des informations spécifiques, Beautiful Soup est une belle chose.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top