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.
42 lines
4.8 KiB
HTML
42 lines
4.8 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head><meta charset="utf-8"><title>SHL | stats.swehockey.se</title></head>
|
|
<body>
|
|
<h1>SHL</h1>
|
|
<ul>
|
|
<a href="/ScheduleAndResults/Live/20961" onclick="pageVisited('/ScheduleAndResults/Live/20961','SHL')" target="_self">SHL</a><a href="/ScheduleAndResults/Overview/20962" onclick="pageVisited('/ScheduleAndResults/Overview/20962','HockeyAllsvenskan')" target="_self">HockeyAllsvenskan</a><a href="/ScheduleAndResults/Schedule/21041" onclick="pageVisited('/ScheduleAndResults/Schedule/21041','Hockeyettan')" target="_self">Hockeyettan</a><a href="/ScheduleAndResults/Overview/21970" onclick="pageVisited('/ScheduleAndResults/Overview/21970','Svenska Universitetshockeyligan')" target="_self">Svenska Universitetshockeyligan</a><a href="/ScheduleAndResults/Schedule/19767" onclick="pageVisited('/ScheduleAndResults/Schedule/19767','Svenska Cupen U20')" target="_self">Svenska Cupen U20</a><a href="/ScheduleAndResults/Overview/20964" onclick="pageVisited('/ScheduleAndResults/Overview/20964','U20 Nationell')" target="_self">U20 Nationell</a>
|
|
</ul>
|
|
<select class="form-control form-control-sm" onchange="doNavigate(this)">
|
|
<option id="/ScheduleAndResults/Live/20961" selected="selected" value="/ScheduleAndResults/Live/20961">2026-27</option>
|
|
<option id="/ScheduleAndResults/Overview/18263" value="/ScheduleAndResults/Overview/18263">2025-26</option>
|
|
<option id="/ScheduleAndResults/Overview/17556" value="/ScheduleAndResults/Overview/17556">2024-25</option>
|
|
<option id="/ScheduleAndResults/Overview/15791" value="/ScheduleAndResults/Overview/15791">2023-24</option>
|
|
<option id="/ScheduleAndResults/Overview/14296" value="/ScheduleAndResults/Overview/14296">2022-23</option>
|
|
<option id="/ScheduleAndResults/Overview/13348" value="/ScheduleAndResults/Overview/13348">2021-22</option>
|
|
<option id="/ScheduleAndResults/Overview/12267" value="/ScheduleAndResults/Overview/12267">2020-21</option>
|
|
<option id="/ScheduleAndResults/Overview/10371" value="/ScheduleAndResults/Overview/10371">2019-20</option>
|
|
<option id="/ScheduleAndResults/Overview/9820" value="/ScheduleAndResults/Overview/9820">2018-19</option>
|
|
<option id="/ScheduleAndResults/Overview/9006" value="/ScheduleAndResults/Overview/9006">2017-18</option>
|
|
<option id="/ScheduleAndResults/Overview/7978" value="/ScheduleAndResults/Overview/7978">2016-17</option>
|
|
<option id="/ScheduleAndResults/Overview/6699" value="/ScheduleAndResults/Overview/6699">2015-16</option>
|
|
<option id="/ScheduleAndResults/Overview/5995" value="/ScheduleAndResults/Overview/5995">2014-15</option>
|
|
<option id="/ScheduleAndResults/Overview/4870" value="/ScheduleAndResults/Overview/4870">2013-14</option>
|
|
<option id="/ScheduleAndResults/Schedule/3810" value="/ScheduleAndResults/Schedule/3810">2012-13</option>
|
|
<option id="/ScheduleAndResults/Schedule/965" value="/ScheduleAndResults/Schedule/965">2011-12</option>
|
|
<option id="/ScheduleAndResults/Overview/841" value="/ScheduleAndResults/Overview/841">2010-11</option>
|
|
<option id="/ScheduleAndResults/Overview/9025" value="/ScheduleAndResults/Overview/9025">2009-10</option>
|
|
<option id="/ScheduleAndResults/Overview/9053" value="/ScheduleAndResults/Overview/9053">2008-09</option>
|
|
<option id="/ScheduleAndResults/Overview/9078" value="/ScheduleAndResults/Overview/9078">2007-08</option>
|
|
<option id="/ScheduleAndResults/Overview/9142" value="/ScheduleAndResults/Overview/9142">2006-07</option>
|
|
<option id="/ScheduleAndResults/Overview/9147" value="/ScheduleAndResults/Overview/9147">2005-06</option>
|
|
<option id="/ScheduleAndResults/Overview/9150" value="/ScheduleAndResults/Overview/9150">2004-05</option>
|
|
<option id="/ScheduleAndResults/Overview/9153" value="/ScheduleAndResults/Overview/9153">2003-04</option>
|
|
<option id="/ScheduleAndResults/Overview/12153" value="/ScheduleAndResults/Overview/12153">2002-03</option>
|
|
<option id="/ScheduleAndResults/Overview/12158" value="/ScheduleAndResults/Overview/12158">2001-02</option>
|
|
<option id="/ScheduleAndResults/Overview/12173" value="/ScheduleAndResults/Overview/12173">2000-01</option>
|
|
<option class="disabled font-weight-bold text-black" style="font-size:16px" disabled value="-1"> Cups</option>
|
|
<hr />
|
|
</select>
|
|
</body>
|
|
</html>
|