Skip to content
This repository was archived by the owner on Jul 20, 2026. It is now read-only.
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 52 additions & 7 deletions ngm/ngscrape/spiders/district_case_enrichment.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,27 +102,51 @@ class DistrictCaseEnrichmentSpider(scrapy.Spider):
# "DOWNLOAD_DELAY": 2, # 2 second delay between requests
}

def __init__(self, *args, **kwargs):
def __init__(self, *args, backfill_case_type=False, **kwargs):
super().__init__(*args, **kwargs)
# Opt-in one-off mode (`-a backfill_case_type=true`) that also revisits
# already-enriched rows missing a case_type. Off by default so nightly
# runs never re-fetch permanently-typeless rows in a loop.
self.backfill_case_type = str(backfill_case_type).lower() in (
"1",
"true",
"yes",
)

def start_requests(self):
"""Generate requests for cases that need enrichment"""
self.engine = get_engine()
init_db(self.engine)
self.session = get_session(self.engine)

needs_enrichment = or_(
CourtCase.status == "pending",
CourtCase.status.is_(None),
)
if self.backfill_case_type:
# Revisit already-enriched rows whose case_type never got populated:
# the daily cause-list only carries the (often blank) "मुद्दा विषय"
# subject column, so these need the detail page's "मुद्दाको किसिम".
needs_enrichment = or_(
needs_enrichment,
and_(
CourtCase.status == "enriched",
or_(
CourtCase.case_type.is_(None),
CourtCase.case_type == "",
),
),
)

# Query all district court cases that need enrichment in one go
# Priority: newer registration dates first, status = pending or NULL
# Priority: newer registration dates first.
with self.session.begin():
cases_to_enrich = (
self.session.query(CourtCase.case_number, CourtCase.court_identifier)
.filter(
and_(
CourtCase.court_identifier.like("%dc"),
or_(
CourtCase.status == "pending",
CourtCase.status.is_(None),
),
needs_enrichment,
)
)
.order_by(CourtCase.registration_date_ad.desc().nullslast())
Expand Down Expand Up @@ -259,7 +283,23 @@ def parse_case_detail(self, response):
return

if case.status == "enriched":
self.logger.info(f"Case {case_number} already enriched, skipping")
if case.case_type:
self.logger.info(f"Case {case_number} already enriched, skipping")
return
# Already enriched but missing case_type: backfill just that field
# from the detail page without re-touching entities/hearings (whose
# rebuild deletes rows that may have downstream linkages).
case_type = self._extract_enrichment_data(soup).get("case_type")
if case_type:
case.case_type = case_type[:200]
case.updated_at = datetime.now(KATHMANDU_TZ).replace(tzinfo=None)
self.logger.info(
f"Backfilled case_type for {case_number} ({code_name}): {case_type}"
)
else:
self.logger.info(
f"Case {case_number} ({code_name}) has no case_type on detail page"
)
return

# Extract enrichment data
Expand Down Expand Up @@ -296,6 +336,11 @@ def _extract_enrichment_data(self, soup: BeautifulSoup) -> Dict:
# Map Nepali labels to database fields
if label == "रजिष्ट्रेशन नं" and value:
data["registration_number"] = value[:100]
elif label == "मुद्दाको किसिम" and value:
# True case type, only available on the detail page; the
# cause-list listing has no such column (it carries the
# subject), which is why district case_type is often blank.
data["case_type"] = value[:200]
elif label == "मुद्दाको बिषय" and value:
data["case_subject"] = value
elif label == "मुद्दाको स्थिति" and value:
Expand Down
Loading