#!/usr/bin/env python3 """End-of-page bibliography scan โ€” the known blind spot of block-unit measurement. The instrument judges each block on its own. A page that collects its sources in a list at the BOTTOM scores low here even though it does cite them. This scan looks for that: a sources heading in the last third of the page, followed by external links. Every hit must still be read by hand โ€” the heading alone proves nothing. Run: SNAPSHOTS= python3 code/bibliography-scan.py """ import re, io, os, glob, json, csv, sys, importlib.util spec=importlib.util.spec_from_file_location("ins","code/measure.py") ins=importlib.util.module_from_spec(spec); spec.loader.exec_module(ins) SNAPS=os.environ.get("SNAPSHOTS") HEADING = re.compile(r'^\s*(sources?|references?|bibliography|citations?|works cited|' r'further reading|sources? (?:&|and) references?|cited (?:works|sources))\s*:?\s*$', re.I) def host_of(u): m=re.match(r'https?://([^/]+)', u or '') return m.group(1).replace('www.','').lower() if m else '' scored={r['page_id']:r for r in csv.DictReader(open('data/results.csv'))} log={r['page_id']:r for r in csv.DictReader(open('data/retrieval-log.csv'))} result=[] for path in sorted(glob.glob(os.path.join(SNAPS,'v2-*.html'))): name=os.path.basename(path)[3:-5] if name not in log: continue h=io.open(path,encoding='utf-8',errors='ignore').read() bls=ins.blocks(h) if not bls: continue own=host_of(log[name]['url']) # look for a sources heading in the last 35% of the page cutoff=int(len(bls)*0.65) found=None for i,(kind,txt,raw) in enumerate(bls): if i]*href="([^"]+)"', raw): u=m.group(1) if not u.startswith('http'): internal+=1; continue if host_of(u)==own: internal+=1 else: external+=1 if len(examples)<3: examples.append(u[:70]) result.append({"page_id":name,"bibliography":True,"heading":bls[found][1].strip()[:40], "external_links":external,"own_links":internal,"examples":examples}) print(f"{'page':<26}{'scored':>7} biblio ext-links") for r in sorted(result,key=lambda x:(not x['bibliography'],x['page_id'])): p=f"{float(scored[r['page_id']]['percent_sourced']):.0f}%" if r['page_id'] in scored else " โ€”" if r['bibliography']: print(f" {r['page_id']:<24}{p:>7} YES {r['external_links']:>3} ext ยท {r['own_links']} own [{r['heading']}]") for u in r['examples']: print(f" {u}") else: print(f" {r['page_id']:<24}{p:>7} no") json.dump(result, io.open('/tmp/bibliography-scan.json','w',encoding='utf-8'), ensure_ascii=False, indent=1)