One HTTP GET per season, no browser: the page is server-rendered, so every row arrives in one response and the extraction becomes a pure function of the HTML. - layouts[] declares one profile per version of the site's table (modern and legacy), each identified by its header row, so a new version of the page is a new profile plus a fixture instead of a guess. - The table is located by header signature, not by a CSS path. - Every cell is shape-checked, and facts the site renders twice (desktop and mobile date, time in the tooltip) must agree. - Cross-field invariants: periods sum to the score, ids are unique, played games always have an event link and unplayed ones never do. - Output is sorted by date, time and id, so it does not inherit the site's row order, and it carries no fetch timestamp: same HTML, same bytes. - Drift is a typed error and exit code 3, with the header it actually found. - Tests run on committed HTML fixtures and golden JSON; TestLive is opt-in. Verified over the full SHL archive: 27/27 seasons, 2119 games, 1779 played.
47 lines
9.8 KiB
HTML
47 lines
9.8 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head><meta charset="utf-8"><title>SHL | stats.swehockey.se</title></head>
|
||
<body>
|
||
<h1>SHL</h1>
|
||
<div class="ad"><a href="/Ad/Object/99">annons</a></div>
|
||
<div id="groupStandingResultContent" class="row"><table class="tblWrapper table table-borderless"><tr><td class="tdWrapper"><table class="tblBorderNoPad"><tr><td class="tdTblBorder"><table class="tblContent"><tr><th colspan="3" class="tdTitle"><h2>Schedule and Results</h2></th><th class="tdTitle d-none d-sm-table-cell" /><th class="tdTitle d-none d-md-table-cell" /><th colspan="2" class="tdTitleRight d-none d-sm-table-cell">
|
||
Last update: 2026-09-26 22:41</th><th colspan="2" class="tdTitleRight d-table-cell d-sm-none" /></tr><tr><th class="tdHeader">Date</th><th class="tdHeader d-none d-sm-table-cell">Time</th><th class="tdHeader">Game</th><th class="tdHeader">Result</th><th class="tdHeader d-none d-sm-table-cell" /><th class="tdHeader d-none d-md-table-cell" style="text-align:right">Spectators</th><th class="tdHeader">Venue</th></tr><tr><td class="tdOdd standardPaddingTop d-none d-sm-table-cell">2026-09-19</td><td class="tdOdd standardPaddingTop d-table-cell d-sm-none"><bold>2026-09-19</bold><br />15:15</td><td class="tdOdd standardPaddingTop d-none d-sm-table-cell" style="white-space: nowrap;"><div class="dateLink"><span href="#" class="lnkTooltip" title="90001001">15:15</span></div></td><td class="tdOdd standardPaddingTop">Frölunda HC
|
||
-
|
||
Växjö Lakers HC</td><td class="tdOdd standardPaddingTop" style="white-space: nowrap;"><a href="
 javascript:openonlinewindow('/Game/Events/1109941','')
 ">5 - 4</a></td><td class="tdOdd standardPaddingTop d-none d-sm-table-cell" style="white-space: nowrap;">
|
||
(1-1, 2-1, 2-2)
|
||
</td><td class="tdOdd standardPaddingTop d-none d-md-table-cell" style="text-align: right">12044</td><td class="tdOdd standardPaddingTop">Scandinavium</td></tr><tr><td class="tdNormal standardPaddingTop d-table-cell d-sm-none">15:15</td><td class="tdNormal standardPaddingTop d-none d-sm-table-cell" /><td class="tdNormal standardPaddingTop d-none d-sm-table-cell" style="white-space: nowrap;"><div class="dateLink"><span href="#" class="lnkTooltip" title="90001002">15:15</span></div></td><td class="tdNormal standardPaddingTop">HV 71
|
||
-
|
||
IF Malmö Redhawks</td><td class="tdNormal standardPaddingTop" style="white-space: nowrap;"><a href="
 javascript:openonlinewindow('/Game/Events/1109942','')
 ">4 - 5</a></td><td class="tdNormal standardPaddingTop d-none d-sm-table-cell" style="white-space: nowrap;">
|
||
(2-0, 1-3, 1-1, 0-1)
|
||
</td><td class="tdNormal standardPaddingTop d-none d-md-table-cell" style="text-align: right">6800</td><td class="tdNormal standardPaddingTop">Husqvarna Garden</td></tr><tr><td class="tdOdd standardPaddingTop d-table-cell d-sm-none">15:15</td><td class="tdOdd standardPaddingTop d-none d-sm-table-cell" /><td class="tdOdd standardPaddingTop d-none d-sm-table-cell" style="white-space: nowrap;"><div class="dateLink"><span href="#" class="lnkTooltip" title="90001003">15:15</span></div></td><td class="tdOdd standardPaddingTop">Linköping HC
|
||
-
|
||
Timrå IK</td><td class="tdOdd standardPaddingTop" style="white-space: nowrap;"><a href="
 javascript:openonlinewindow('/Game/Events/1109943','')
 ">3 - 2</a></td><td class="tdOdd standardPaddingTop d-none d-sm-table-cell" style="white-space: nowrap;">
|
||
(1-0, 2-2, 0-0)
|
||
</td><td class="tdOdd standardPaddingTop d-none d-md-table-cell" style="text-align: right">7900</td><td class="tdOdd standardPaddingTop">Saab Arena</td></tr><tr><td class="tdNormal standardPaddingTop d-table-cell d-sm-none">18:00</td><td class="tdNormal standardPaddingTop d-none d-sm-table-cell" /><td class="tdNormal standardPaddingTop d-none d-sm-table-cell" style="white-space: nowrap;"><div class="dateLink"><span href="#" class="lnkTooltip" title="90001004">18:00</span></div></td><td class="tdNormal standardPaddingTop">Djurgårdens IF
|
||
-
|
||
IF Björklöven</td><td class="tdNormal standardPaddingTop" style="white-space: nowrap;"><a href="
 javascript:openonlinewindow('/Game/Events/1109944','')
 ">0 - 3</a></td><td class="tdNormal standardPaddingTop d-none d-sm-table-cell" style="white-space: nowrap;">
|
||
(0-1, 0-1, 0-1)
|
||
</td><td class="tdNormal standardPaddingTop d-none d-md-table-cell" style="text-align: right">14100</td><td class="tdNormal standardPaddingTop">Avicii Arena</td></tr><tr><td class="tdOdd standardPaddingTop d-table-cell d-sm-none">18:00</td><td class="tdOdd standardPaddingTop d-none d-sm-table-cell" /><td class="tdOdd standardPaddingTop d-none d-sm-table-cell" style="white-space: nowrap;"><div class="dateLink"><span href="#" class="lnkTooltip" title="90001005">18:00</span></div></td><td class="tdOdd standardPaddingTop">Färjestad BK
|
||
-
|
||
Örebro HK</td><td class="tdOdd standardPaddingTop" style="white-space: nowrap;"><a href="
 javascript:openonlinewindow('/Game/Events/1109945','')
 ">7 - 0</a></td><td class="tdOdd standardPaddingTop d-none d-sm-table-cell" style="white-space: nowrap;">
|
||
(4-0, 2-0, 1-0)
|
||
</td><td class="tdOdd standardPaddingTop d-none d-md-table-cell" style="text-align: right">8250</td><td class="tdOdd standardPaddingTop">Löfbergs Arena</td></tr><tr><td class="tdNormal standardPaddingTop d-table-cell d-sm-none">18:00</td><td class="tdNormal standardPaddingTop d-none d-sm-table-cell" /><td class="tdNormal standardPaddingTop d-none d-sm-table-cell" style="white-space: nowrap;"><div class="dateLink"><span href="#" class="lnkTooltip" title="90001006">18:00</span></div></td><td class="tdNormal standardPaddingTop">Luleå HF
|
||
-
|
||
Rögle BK</td><td class="tdNormal standardPaddingTop" style="white-space: nowrap;"><a href="
 javascript:openonlinewindow('/Game/Events/1109946','')
 ">4 - 2</a></td><td class="tdNormal standardPaddingTop d-none d-sm-table-cell" style="white-space: nowrap;">
|
||
(0-2, 3-0, 1-0)
|
||
</td><td class="tdNormal standardPaddingTop d-none d-md-table-cell" style="text-align: right">6150</td><td class="tdNormal standardPaddingTop">Coop Norrbotten Arena </td></tr><tr><td class="tdNormal paddingTop d-none d-sm-table-cell">2026-09-22</td><td class="tdNormal paddingTop d-table-cell d-sm-none"><bold>2026-09-22</bold><br />19:00</td><td class="tdNormal paddingTop d-none d-sm-table-cell" style="white-space: nowrap;"><div class="dateLink"><span href="#" class="lnkTooltip" title="90001008">19:00</span></div></td><td class="tdNormal paddingTop">Frölunda HC
|
||
-
|
||
Färjestad BK</td><td class="tdNormal paddingTop" style="white-space: nowrap;"><a href="
 javascript:openonlinewindow('/Game/Events/1109948','')
 ">3 - 2</a></td><td class="tdNormal paddingTop d-none d-sm-table-cell" style="white-space: nowrap;">
|
||
(1-1, 0-1, 1-0, 0-0, 1-0)
|
||
</td><td class="tdNormal paddingTop d-none d-md-table-cell" style="text-align: right">11449</td><td class="tdNormal paddingTop">Scandinavium</td></tr><tr><td class="tdOdd standardPaddingTop d-table-cell d-sm-none">19:00</td><td class="tdOdd standardPaddingTop d-none d-sm-table-cell" /><td class="tdOdd standardPaddingTop d-none d-sm-table-cell" style="white-space: nowrap;"><div class="dateLink"><span href="#" class="lnkTooltip" title="90001009">19:00</span></div></td><td class="tdOdd standardPaddingTop">Linköping HC
|
||
-
|
||
Brynäs IF</td><td class="tdOdd standardPaddingTop" style="white-space: nowrap;"><a href="
 javascript:openonlinewindow('/Game/Events/1109949','')
 ">2 - 9</a></td><td class="tdOdd standardPaddingTop d-none d-sm-table-cell" style="white-space: nowrap;">
|
||
(0-2, 1-3, 1-4)
|
||
</td><td class="tdOdd standardPaddingTop d-none d-md-table-cell" style="text-align: right">6812</td><td class="tdOdd standardPaddingTop">Saab Arena</td></tr><tr><td class="tdNormal paddingTop d-none d-sm-table-cell">2027-03-16</td><td class="tdNormal paddingTop d-table-cell d-sm-none"><bold>2027-03-16</bold><br />19:00</td><td class="tdNormal paddingTop d-none d-sm-table-cell" style="white-space: nowrap;"><div class="dateLink"><span href="#" class="lnkTooltip" title="90001367">19:00</span></div></td><td class="tdNormal paddingTop">Brynäs IF
|
||
-
|
||
Frölunda HC</td><td class="tdNormal paddingTop" colspan="1"> </td><td class="tdNormal paddingTop d-none d-sm-table-cell" /><td class="tdNormal paddingTop d-none d-md-table-cell" /><td class="tdNormal paddingTop">Monitor ERP Arena</td></tr><tr><td class="tdOdd standardPaddingTop d-table-cell d-sm-none">19:00</td><td class="tdOdd standardPaddingTop d-none d-sm-table-cell" /><td class="tdOdd standardPaddingTop d-none d-sm-table-cell" style="white-space: nowrap;"><div class="dateLink"><span href="#" class="lnkTooltip" title="90001368">19:00</span></div></td><td class="tdOdd standardPaddingTop">HV 71
|
||
-
|
||
Färjestad BK</td><td class="tdOdd standardPaddingTop" colspan="1"> </td><td class="tdOdd standardPaddingTop d-none d-sm-table-cell" /><td class="tdOdd standardPaddingTop d-none d-md-table-cell" /><td class="tdOdd standardPaddingTop">Husqvarna Garden</td></tr></table></td></tr></table></td></tr></table></div>
|
||
</body>
|
||
</html>
|