gendesign/backend/output/geojson/66_41_0204016_10.geojson
lekss361 54dbc77348 feat(geo): NSPD bulk-fetcher без Playwright + resume-friendly UI
ОТКРЫТИЕ: stdlib urllib проходит WAF nspd.gov.ru (TLS-fingerprint stdlib
отличается от mainstream HTTP-clients). Это позволяет полностью убрать
Playwright + Chromium для NSPD-задач.

* nspd_lite.py: urllib + ssl._create_unverified_context(). 4 публичных
  fetcher'а (geoportal/quarter/parcel/building) + fetch_via_rosreestr2coord
  fallback на community-lib

* schema 77: nspd_geo_jobs (журнал) + nspd_geo_targets (cad-номера со
  статусом pending/done/failed). Resume-state в БД.

* tasks/nspd_geo.py: Celery task process_nspd_geo_job(job_id). Heartbeat
  каждые 5 items, WAF backoff 30s × 2^N (max 8 → paused). UPSERT в
  cad_quarters_geom / cad_buildings → идемпотентно.

* worker_ready hook: stale jobs (>10min без heartbeat) автоматически
  re-enqueue после redeploy. Никаких потерь прогресса.

* 4 admin endpoint + UI /admin/scrape/geo с формой запуска (manual_list /
  rosreestr_pending для авто-наполнения из ДДУ-кварталов), progress-bars
  и cancel/resume кнопками per job.

* settings: use_nspd_lite=True, nspd_lite_rate_ms=600.
* dep: rosreestr2coord>=4.0.0 (community lib для fallback).

TODO следующих шагов:
- smoke-test на проде через SSH (validation RU-IP не банит urllib)
- feature toggle USE_NSPD_LITE в scrape_nspd.py для переключения с старого
  Playwright-пути
- docker lean image (-300 MB после убирания Chromium)
- расширение SCRAPE_NSPD_DEFAULT_REGIONS на 66,74,72,59 (Челябинск/Тюмень/Пермь)
2026-05-11 08:53:28 +03:00

1 line
4.4 KiB
JSON

{"id": 103660478, "type": "Feature", "geometry": {"type": "Polygon", "coordinates": [[[60.5222936642305, 56.87886819649157], [60.52228588780081, 56.87886283773699], [60.52224469481928, 56.878834885257085], [60.522052973741495, 56.87869300342362], [60.52253110197689, 56.878512041850186], [60.52259101161419, 56.87848945465678], [60.522737599100324, 56.87843394151893], [60.52278893631658, 56.878433926994376], [60.522832402213155, 56.878434032020515], [60.522886453650436, 56.87846714420006], [60.52289738223943, 56.878462343346754], [60.523191155978175, 56.87868465965369], [60.52329525075883, 56.878758083028075], [60.52313452537541, 56.87882406737451], [60.52263537237766, 56.879028728703595], [60.52257662924073, 56.87905283814238], [60.5222936642305, 56.87886819649157]]], "crs": {"type": "name", "properties": {"name": "EPSG:3857"}}}, "properties": {"cadastralDistrictsCode": 66, "category": 36368, "categoryName": "\u0417\u0435\u043c\u0435\u043b\u044c\u043d\u044b\u0435 \u0443\u0447\u0430\u0441\u0442\u043a\u0438 \u0415\u0413\u0420\u041d", "descr": "66:41:0204016:10", "externalKey": "66:41:0204016:10", "interactionId": 103594786, "label": "66:41:0204016:10", "options": {"area": null, "cad_num": "66:41:0204016:10", "cost_application_date": "2023-01-01", "cost_approvement_date": "", "cost_determination_date": "2022-01-01", "cost_index": 8497.03, "cost_registration_date": "2023-01-03", "cost_value": 23706713.7, "declared_area": null, "determination_couse": "\u0410\u043a\u0442 \u043e\u0431 \u0443\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u0438 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u043a\u0430\u0434\u0430\u0441\u0442\u0440\u043e\u0432\u043e\u0439 \u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u0438, \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0445 \u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0438 \u0441 \u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u043c\u0438 \u0417\u0430\u043a\u043e\u043d\u0430 237-\u0424\u0417\n\n\n\n", "land_record_area": 2790, "land_record_category_type": "\u0417\u0435\u043c\u043b\u0438 \u043d\u0430\u0441\u0435\u043b\u0435\u043d\u043d\u044b\u0445 \u043f\u0443\u043d\u043a\u0442\u043e\u0432", "land_record_reg_date": "2006-03-06", "land_record_subtype": "\u0417\u0435\u043c\u043b\u0435\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435", "land_record_type": "\u0417\u0435\u043c\u0435\u043b\u044c\u043d\u044b\u0439 \u0443\u0447\u0430\u0441\u0442\u043e\u043a", "ownership_type": "\u0427\u0430\u0441\u0442\u043d\u0430\u044f", "permitted_use_established_by_document": "\u043c\u0430\u0433\u0430\u0437\u0438\u043d\u044b (\u043e\u0431\u0449\u0435\u0439 \u043f\u043b\u043e\u0449\u0430\u0434\u044c\u044e \u0434\u043e 5000 \u043a\u0432.\u043c), \u043e\u0431\u0449\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0435 \u043f\u0438\u0442\u0430\u043d\u0438\u0435, \u0431\u044b\u0442\u043e\u0432\u043e\u0435 \u043e\u0431\u0441\u043b\u0443\u0436\u0438\u0432\u0430\u043d\u0438\u0435, \u0434\u0435\u043b\u043e\u0432\u043e\u0435 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435", "previously_posted": "\u0420\u0430\u043d\u0435\u0435 \u0443\u0447\u0442\u0435\u043d\u043d\u044b\u0439", "quarter_cad_number": "66:41:0204016", "readable_address": "\u0420\u043e\u0441\u0441\u0438\u0439\u0441\u043a\u0430\u044f \u0424\u0435\u0434\u0435\u0440\u0430\u0446\u0438\u044f, \u0421\u0432\u0435\u0440\u0434\u043b\u043e\u0432\u0441\u043a\u0430\u044f \u043e\u0431\u043b\u0430\u0441\u0442\u044c, \u043c\u0443\u043d\u0438\u0446\u0438\u043f\u0430\u043b\u044c\u043d\u043e\u0435 \u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \"\u0433\u043e\u0440\u043e\u0434 \u0415\u043a\u0430\u0442\u0435\u0440\u0438\u043d\u0431\u0443\u0440\u0433\", \u0433\u043e\u0440\u043e\u0434 \u0415\u043a\u0430\u0442\u0435\u0440\u0438\u043d\u0431\u0443\u0440\u0433, \u0443\u043b\u0438\u0446\u0430 \u0411\u0438\u043b\u0438\u043c\u0431\u0430\u0435\u0432\u0441\u043a\u0430\u044f, 3", "right_type": "\u0421\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0441\u0442\u044c", "specified_area": 2790, "status": "\u0420\u0430\u043d\u0435\u0435 \u0443\u0447\u0442\u0435\u043d\u043d\u044b\u0439"}, "subcategory": 5, "systemInfo": {"inserted": "2023-11-07T18:40:05.722318", "insertedBy": "7EF5CD0B-AC08-4097-AF2B-07CD85992A79", "updated": "2026-02-03T04:59:16.064005", "updatedBy": "7EF5CD0B-AC08-4097-AF2B-07CD85992A79"}}}