CodeRigor

FREE LESSON

Capstone: audit a local site’s link graph

Analyze supplied local HTML pages, resolve declared bases, find missing targets and unreachable pages, and serialize an honest audit.

A site is a collection of documents connected by references. This capstone supplies that collection as a Python mapping from absolute URL strings to HTML strings. The URLs are identifiers for local fixtures; no file, DNS lookup or network request is needed. A known page is present in the mapping. A broken internal target is absent from that mapping. An external target belongs to another syntactic origin and has unknown availability.

Known pages form a local graph
start / 2
Home reaches guide and example through a cycle; orphan is supplied but unreachable; missing is reported and never traversed.
Known pages form a local graph
Home reaches guide and example through a cycle; orphan is supplied but unreachable; missing is reported and never traversed.

Validate the collection before reporting it. Convert the entry and every supplied page key with document_key. Require the entry to be present, all pages to share its canonical origin, and every normalized page key to be distinct. Reject collisions rather than silently letting dictionary order select one source. Two keys differing only by a default port or fragment can collide under the declared policy. Different queries remain separate pages.

The supplied page scanner gathers anchor hrefs and the first base element with a string href, including an empty string. Fixtures have a static, well-formed base declaration in the head before links, unique attributes and no dynamic DOM behavior. A later base must not replace the first. Resolve a relative declared base against the page’s canonical document URL, then resolve its hrefs against that base. The scanner includes anchor start events even without a closing tag because destination analysis needs no label.

Python
from urllib.parse import urljoin

page = "https://example.test/docs/start.html"
base = urljoin(page, "../assets/")
print(urljoin(base, "guide.html#install"))
print(urljoin(base, "/contact"))

For each accepted target, classify its origin. Known internal targets become graph edges. Missing internal targets become broken rows. External targets become external rows. Rejected or unresolvable extracted references increase an ignored counter. A declared base that makes urljoin raise is a configuration error and propagates ValueError. Count repeated broken or external occurrences separately for each (source, target) pair. A set is enough for graph adjacency because multiple identical edges do not change reachability, but it would lose report occurrence counts.

Inventory and reachability answer different questions
start / 3
Every supplied page contributes report evidence. Only known internal edges feed entry-based reachability.
Inventory and reachability answer different questions
Every supplied page contributes report evidence. Only known internal edges feed entry-based reachability.

Inspect all supplied pages, including unreachable ones. An orphan page can still contain a broken reference worth reporting. Then traverse known internal edges from the entry using a work list and a seen set. Add discovered neighbors until the work list is empty. A self-link or cycle must terminate, and a three-hop chain must reach its last page. Missing and external targets never enter this traversal.

Python
graph = {"home": {"guide"}, "guide": {"example"}, "example": {"home"}, "orphan": set()}
seen, pending = set(), ["home"]
while pending:
    current = pending.pop()
    if current in seen:
        continue
    seen.add(current)
    pending.extend(graph[current] - seen)
print(sorted(seen))
print(sorted(set(graph) - seen))

Return sorted reachable and unreachable page keys, sorted broken/external rows and the ignored count. audit_json applies the earlier standalone JSON formatting policy. Preserve input mappings and strings; output ordering must not depend on input insertion order or set traversal order.

Build failure cases as carefully as the happy path: empty maps, absent entries, alias collisions, cross-origin page keys, first-base precedence, query variants, cycles and repeated missing targets. The report is an audit of the supplied snapshot. It does not prove a server returns 200, a fragment exists, a browser can render the page, or a request destination is authorized. Live crawling adds HTTP preparation, bounded work, robots conventions, remote failure handling and request-security decisions beyond this free local course.

Watch & read

Free lectures, talks and readings that cover this skill from another angle. All resources →

Revisit 03:30–10:30 for document/DOM structure and 21:20–23:50 for links. They motivate the static fixture model; local graph analysis, error policies and deterministic reports are taught in the capstone.