88 lines
3.7 KiB
Python
88 lines
3.7 KiB
Python
# -*- coding: utf-8 -*-
|
||
"""
|
||
Заполняет doctor_bio_entries из свойств врача в дампе Bitrix, которые
|
||
export_seed.py по ошибке не читал: EDUCATION(331), AWARDS(330), CONFERENCES(332).
|
||
|
||
Значения хранятся либо простым текстом, либо сериализованным PHP-массивом вида
|
||
a:2:{s:4:"TEXT";s:N:"...";s:4:"TYPE";s:4:"HTML";} — сначала извлекаем текст,
|
||
затем режем на отдельные пункты (по <li> или по <br>/переводу строки),
|
||
из каждого пытаемся достать год.
|
||
"""
|
||
import sqlread, io, re, html
|
||
|
||
P = 'D:/medkor-local/tmp/dana/db.sql'
|
||
OUT = io.open('seed_doctor_bio.sql', 'w', encoding='utf-8')
|
||
|
||
def esc(s):
|
||
if s is None:
|
||
return "NULL"
|
||
return "'" + str(s).replace("\\", "\\\\").replace("'", "''") + "'"
|
||
|
||
def extract_text(raw):
|
||
"""Достаёт TEXT из сериализованного PHP-массива Bitrix, если он там есть."""
|
||
m = re.search(r's:4:"TEXT";s:\d+:"(.*)";s:4:"TYPE"', raw, re.S)
|
||
return m.group(1) if m else raw
|
||
|
||
def split_entries(raw):
|
||
text = extract_text(raw)
|
||
text = text.replace('\\r\\n', '\n').replace('rn', '\n') # артефакты дампа
|
||
# снимаем HTML-экранирование ДО поиска тегов — в паре карточек теги были
|
||
# вставлены как текст (<ul> вместо <ul>), и без этого шага <li>
|
||
# не находился, а обрывки "<ul>"/"</ul>" оседали как отдельные записи
|
||
text = html.unescape(text)
|
||
items = re.findall(r'(?is)<li[^>]*>(.*?)</li>', text)
|
||
if not items:
|
||
parts = re.split(r'(?i)<br\s*/?>|\n', text)
|
||
items = [p for p in parts if p.strip()]
|
||
out = []
|
||
for it in items:
|
||
t = html.unescape(re.sub(r'(?s)<[^>]+>', ' ', it)).strip()
|
||
t = re.sub(r'\s+', ' ', t)
|
||
# чистые обрывки разметки без текста (<ul>, </ul>, пустой <p></p> и т.п.)
|
||
if t and re.search(r'[А-Яа-яA-Za-z0-9]', t):
|
||
out.append(t)
|
||
return out
|
||
|
||
YEAR_RE = re.compile(r'(19|20)\d{2}')
|
||
|
||
def parse_year(text):
|
||
m = YEAR_RE.search(text)
|
||
return int(m.group(0)) if m else None
|
||
|
||
PROPS = {'331': 'education', '330': 'award', '332': 'conference'}
|
||
|
||
values = {} # (elem_id, prop_id) -> value
|
||
for r in sqlread.rows(P, 'b_iblock_element_property'):
|
||
if r.get('IBLOCK_PROPERTY_ID') in PROPS and r.get('VALUE'):
|
||
values[(r['IBLOCK_ELEMENT_ID'], r['IBLOCK_PROPERTY_ID'])] = r['VALUE']
|
||
|
||
doctors = [r for r in sqlread.rows(P, 'b_iblock_element')
|
||
if r['IBLOCK_ID'] == '29' and r.get('ACTIVE') == 'Y']
|
||
|
||
OUT.write('BEGIN;\n')
|
||
total = 0
|
||
per_doctor_any = 0
|
||
for d in doctors:
|
||
eid = d['ID']
|
||
had_any = False
|
||
for prop_id, kind in PROPS.items():
|
||
raw = values.get((eid, prop_id))
|
||
if not raw:
|
||
continue
|
||
entries = split_entries(raw)
|
||
for i, text in enumerate(entries):
|
||
year = parse_year(text)
|
||
title = text if len(text) <= 300 else text[:297] + '...'
|
||
OUT.write(
|
||
"INSERT INTO doctor_bio_entries (doctor_id, kind, year_from, title, sort) "
|
||
"SELECT id, %s, %s, %s, %s FROM doctors WHERE legacy_id=%s;\n" % (
|
||
esc(kind), year if year else 'NULL', esc(title), i + 1, eid))
|
||
total += 1
|
||
had_any = True
|
||
if had_any:
|
||
per_doctor_any += 1
|
||
OUT.write('COMMIT;\n')
|
||
OUT.close()
|
||
print('врачей с хотя бы одной записью:', per_doctor_any, 'из', len(doctors))
|
||
print('всего записей doctor_bio_entries:', total)
|