This repository has been archived on 2026-08-07. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
trz-univer-diplom/linker.py
T

224 lines
4.8 KiB
Python
Executable File

#!/usr/bin/env python3
import re
import tempfile
import xml.etree.ElementTree as ET
from pathlib import Path
from zipfile import ZipFile
from urllib.parse import urlsplit, urlunsplit
import requests
from bs4 import BeautifulSoup
INPUT_DOCX = "Отчет.docx"
OUTPUT_DOCX = "Отчет_fixed.docx"
FIRST_NEW_SOURCE = 8
ACCESS_DATE = "30.05.2026"
NS = {
"w": "http://schemas.openxmlformats.org/wordprocessingml/2006/main"
}
def normalize_url(url):
url = url.strip()
if "#:~:text=" in url:
url = url.split("#:~:text=", 1)[0]
parts = urlsplit(url)
return urlunsplit((
parts.scheme.lower(),
parts.netloc.lower(),
parts.path.rstrip("/"),
"",
""
))
def get_title(url):
try:
response = requests.get(
url,
timeout=15,
headers={
"User-Agent": "Mozilla/5.0"
}
)
response.raise_for_status()
soup = BeautifulSoup(response.text, "html.parser")
og = soup.find("meta", property="og:title")
if og and og.get("content"):
return " ".join(og["content"].split())
meta = soup.find("meta", attrs={"name": "title"})
if meta and meta.get("content"):
return " ".join(meta["content"].split())
if soup.title and soup.title.string:
return " ".join(soup.title.string.split())
except Exception as e:
print(f"WARNING: {url}: {e}")
return url
def main():
with tempfile.TemporaryDirectory() as tmpdir:
tmpdir = Path(tmpdir)
with ZipFile(INPUT_DOCX) as archive:
archive.extractall(tmpdir)
document_xml = tmpdir / "word" / "document.xml"
tree = ET.parse(document_xml)
root = tree.getroot()
url_to_index = {}
index_to_url = {}
next_index = FIRST_NEW_SOURCE
#
# Первый проход:
# собираем все URL и выдаем номера
#
for node in root.findall(".//w:instrText", NS):
text = "".join(node.itertext())
match = re.search(r'HYPERLINK\s+"([^"]+)"', text)
if not match:
continue
url = normalize_url(match.group(1))
if url in url_to_index:
continue
url_to_index[url] = next_index
index_to_url[next_index] = url
next_index += 1
print("\n=== URL -> INDEX ===\n")
for index in sorted(index_to_url):
print(f"[{index}] {index_to_url[index]}")
print()
#
# Второй проход:
# меняем номера ссылок
#
current_url = None
waiting_for_text = False
replaced_count = 0
for elem in root.iter():
tag = elem.tag
if tag.endswith("instrText"):
text = "".join(elem.itertext())
match = re.search(
r'HYPERLINK\s+"([^"]+)"',
text
)
if match:
current_url = normalize_url(match.group(1))
waiting_for_text = True
continue
if not waiting_for_text:
continue
if not tag.endswith("t"):
continue
if elem.text is None:
continue
if not re.match(r"\[\d+\]", elem.text.strip()):
continue
new_index = url_to_index[current_url]
old_text = elem.text
elem.text = f"[{new_index}]"
print(
f"{old_text} -> {elem.text} : {current_url}"
)
replaced_count += 1
waiting_for_text = False
current_url = None
print()
print(f"Replaced links: {replaced_count}")
print()
tree.write(
document_xml,
encoding="utf-8",
xml_declaration=True
)
with ZipFile(OUTPUT_DOCX, "w") as out_zip:
for file in tmpdir.rglob("*"):
if file.is_dir():
continue
out_zip.write(
file,
file.relative_to(tmpdir)
)
print(f"Saved: {OUTPUT_DOCX}")
#
# Формируем список литературы
#
print("\n=== SOURCES ===\n")
for index in sorted(index_to_url):
url = index_to_url[index]
title = get_title(url)
print(
f"{index}. "
f"{title} "
f"(дата обращения: {ACCESS_DATE}). "
f"Режим доступа - {url}"
)
if __name__ == "__main__":
main()