прогнал через скрипт список ссылок и источников, часть уже оформил правильно

This commit is contained in:
2026-05-31 22:53:56 +03:00
parent 8508150b07
commit 56d8bce9c3
2 changed files with 160 additions and 129 deletions
Regular → Executable
+122 -91
View File
@@ -1,15 +1,22 @@
#!/usr/bin/env python3
import re
import shutil
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"
@@ -22,30 +29,75 @@ def normalize_url(url):
if "#:~:text=" in url:
url = url.split("#:~:text=", 1)[0]
url = url.rstrip("/")
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 build_url_mapping(root):
"""
Первый проход.
def main():
with tempfile.TemporaryDirectory() as tmpdir:
Собираем все уникальные URL и
присваиваем им номера.
"""
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
)
match = re.search(r'HYPERLINK\s+"([^"]+)"', text)
if not match:
continue
@@ -56,26 +108,24 @@ def build_url_mapping(root):
continue
url_to_index[url] = next_index
index_to_url[next_index] = url
next_index += 1
return url_to_index
print("\n=== URL -> INDEX ===\n")
for index in sorted(index_to_url):
print(f"[{index}] {index_to_url[index]}")
def patch_document(root, url_to_index):
"""
Второй проход.
Находим:
HYPERLINK "..."
Затем ближайший следующий
<w:t>[старый номер]</w:t>
И меняем его на новый.
"""
print()
#
# Второй проход:
# меняем номера ссылок
#
current_url = None
waiting_for_visible_text = False
waiting_for_text = False
replaced_count = 0
for elem in root.iter():
@@ -91,74 +141,41 @@ def patch_document(root, url_to_index):
)
if match:
current_url = normalize_url(
match.group(1)
)
waiting_for_visible_text = True
current_url = normalize_url(match.group(1))
waiting_for_text = True
continue
if (
waiting_for_visible_text
and tag.endswith("t")
and elem.text
and re.match(r"\[\d+\]", elem.text.strip())
):
index = url_to_index[current_url]
if not waiting_for_text:
continue
old = elem.text
elem.text = f"[{index}]"
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} -> {elem.text} : {current_url}"
f"{old_text} -> {elem.text} : {current_url}"
)
waiting_for_visible_text = False
replaced_count += 1
waiting_for_text = False
current_url = None
def main():
input_docx = Path("Отчет.docx")
output_docx = Path(
input_docx.stem + "_fixed.docx"
)
with tempfile.TemporaryDirectory() as tmp:
tmp = Path(tmp)
with ZipFile(input_docx) as archive:
archive.extractall(tmp)
document_xml = (
tmp /
"word" /
"document.xml"
)
tree = ET.parse(document_xml)
root = tree.getroot()
url_to_index = build_url_mapping(root)
print("\nURL -> INDEX\n")
for url, index in url_to_index.items():
print(
f"[{index}] {url}"
)
print(
f"\nFound {len(url_to_index)} unique sources\n"
)
patch_document(
root,
url_to_index
)
print()
print(f"Replaced links: {replaced_count}")
print()
tree.write(
document_xml,
@@ -166,23 +183,36 @@ def main():
xml_declaration=True
)
with ZipFile(
output_docx,
"w"
) as out_zip:
with ZipFile(OUTPUT_DOCX, "w") as out_zip:
for file in tmp.rglob("*"):
for file in tmpdir.rglob("*"):
if file.is_dir():
continue
out_zip.write(
file,
file.relative_to(tmp)
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"\nSaved: {output_docx}"
f"{index}. "
f"{title} "
f"(дата обращения: {ACCESS_DATE}). "
f"Режим доступа - {url}"
)
@@ -190,3 +220,4 @@ if __name__ == "__main__":
main()
BIN
View File
Binary file not shown.