Last active
May 5, 2025 06:54
-
-
Save me-suzy/d176519ce36cfed5f9ed93fd6be48f32 to your computer and use it in GitHub Desktop.
categorii - verifica structura
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import os | |
import re | |
from bs4 import BeautifulSoup, Tag, NavigableString | |
# Directoarele care trebuie verificate (doar folderele principale, fără subfoldere) | |
directories = [ | |
r'e:\Carte\BB\17 - Site Leadership\Principal\ro', | |
r'e:\Carte\BB\17 - Site Leadership\Principal\en' | |
] | |
# Fișiere de ignorat | |
files_to_skip = [ | |
r'e:\Carte\BB\17 - Site Leadership\Principal\en\python-scripts-examples.html', | |
r'e:\Carte\BB\17 - Site Leadership\Principal\ro\python-scripts-examples.html' | |
] | |
def extract_sections(html_content): | |
"""Extrage secțiunile dintre marcajele specificate.""" | |
pattern = r'<!-- ARTICOL CATEGORIE START -->(.*?)<!-- ARTICOL CATEGORIE FINAL -->' | |
return re.findall(pattern, html_content, re.DOTALL) | |
def check_tag_attributes(tag): | |
"""Verifică dacă atributele unui tag HTML conțin caractere nevalide.""" | |
errors = [] | |
for attr_name, attr_value in tag.attrs.items(): | |
# Verifică atribute cu caractere nevalide (de ex. {}, [], etc.) | |
if isinstance(attr_value, str): | |
if re.search(r'[{}\[\]]', attr_value): | |
errors.append(f"Atributul '{attr_name}' conține caractere nevalide: '{attr_value}'") | |
# Verifică dacă numele atributului conține caractere nevalide | |
if re.search(r'[{}\[\]]', attr_name): | |
errors.append(f"Numele atributului conține caractere nevalide: '{attr_name}'") | |
# Verifică dacă există text în tag-ul HTML care conține "{" | |
if tag.string and '{' in tag.string: | |
errors.append(f"Textul tag-ului conține caractere nevalide: '{tag.string}'") | |
return errors | |
def check_invalid_html_tags(html_content): | |
"""Verifică taguri HTML nevalide în conținutul HTML.""" | |
# Lista de taguri HTML valide comune | |
valid_tags = ['html', 'head', 'body', 'div', 'span', 'p', 'a', 'img', 'table', 'tr', 'td', 'th', | |
'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'ul', 'ol', 'li', 'form', 'input', 'button', | |
'select', 'option', 'textarea', 'label', 'iframe', 'br', 'hr', 'em', 'strong', 'i', 'b', | |
'u', 'code', 'pre', 'blockquote', 'center', 'dl', 'dt', 'dd', 'fieldset', 'legend', | |
'font', 'style', 'script', 'meta', 'link', 'title', 'header', 'footer', 'nav', 'section', | |
'article', 'aside', 'main', 'figure', 'figcaption'] | |
errors = [] | |
# Găsește URL-ul primului articol pentru o identificare mai bună | |
soup = BeautifulSoup(html_content, 'html.parser') | |
article_url = None | |
first_table = soup.find('table') | |
if first_table: | |
den_articol = first_table.find('span', class_='den_articol') | |
if den_articol: | |
link = den_articol.find('a', class_='linkMare') | |
if link and link.get('href'): | |
article_url = link.get('href') | |
# Împărțim conținutul în linii pentru a putea raporta numărul liniei | |
lines = html_content.split('\n') | |
# Caută toate tagurile folosind expresii regulate pentru fiecare linie | |
for line_num, line in enumerate(lines, 1): | |
# Caută taguri deschise | |
tags = re.findall(r'<([a-zA-Z0-9]+)(?:\s+[^>]*)?>', line) | |
for tag in tags: | |
tag_lower = tag.lower() | |
if tag_lower not in valid_tags: | |
# Obținem contextul (text din jurul tag-ului) | |
pattern = r'(.{0,20})<' + re.escape(tag) + r'(?:\s+[^>]*)?>' + r'(.{0,20})' | |
context_match = re.search(pattern, line) | |
context = "" | |
if context_match: | |
before = context_match.group(1) | |
after = context_match.group(2) | |
context = f"{before}<{tag}>{after}" | |
error_msg = f"Tag HTML nevalid: <{tag}> la linia {line_num}, context: \"...{context}...\"" | |
if article_url: | |
error_msg += f", înainte de articolul {article_url}" | |
errors.append(error_msg) | |
return errors | |
def check_table_structure_with_location(table, table_path=""): | |
"""Verifică structura internă a unui tabel pentru a detecta elemente nevalide cu locație.""" | |
errors = [] | |
# Stabilim calea pentru tabel | |
table_path = table_path if table_path else "table" | |
# Verifică dacă există elemente nevalide în interiorul tabelului | |
for child in table.children: | |
if isinstance(child, NavigableString) and child.strip(): | |
# Am găsit text neașteptat direct în tabel | |
errors.append(f"Text neașteptat '{child.strip()}' găsit direct în elementul <{table_path}>") | |
elif isinstance(child, Tag) and child.name != 'tr': | |
# Am găsit un tag neașteptat direct în tabel | |
errors.append(f"Element neașteptat <{child.name}> găsit direct în elementul <{table_path}>") | |
# Verifică fiecare rând (tr) al tabelului | |
for tr_idx, tr in enumerate(table.find_all('tr', recursive=False), 1): | |
tr_path = f"{table_path}/tr[{tr_idx}]" | |
# Verifică dacă există elemente nevalide între rânduri | |
next_sibling = tr.next_sibling | |
while next_sibling and next_sibling.name != 'tr': | |
if isinstance(next_sibling, NavigableString) and next_sibling.strip(): | |
errors.append(f"Text neașteptat '{next_sibling.strip()}' găsit între tag-urile </tr> și <tr> în {table_path}") | |
elif isinstance(next_sibling, Tag): | |
errors.append(f"Element neașteptat <{next_sibling.name}> găsit între tag-urile </tr> și <tr> în {table_path}") | |
next_sibling = next_sibling.next_sibling | |
# Verifică conținutul rândului | |
for child in tr.children: | |
if isinstance(child, NavigableString) and child.strip(): | |
errors.append(f"Text neașteptat '{child.strip()}' găsit direct în tag-ul <{tr_path}>") | |
elif isinstance(child, Tag) and child.name != 'td' and child.name != 'th': | |
errors.append(f"Element neașteptat <{child.name}> găsit direct în tag-ul <{tr_path}>") | |
return errors | |
def check_element_problems(element, parent_path=""): | |
"""Verifică probleme de structură și tag-uri în elementele HTML.""" | |
errors = [] | |
current_path = parent_path | |
if isinstance(element, Tag): | |
current_path = f"{parent_path}/{element.name}" if parent_path else element.name | |
# Verifică dacă există atribute nevalide în elementul curent | |
for attr_name, attr_value in element.attrs.items(): | |
if re.search(r'[{}\[\]<>]', str(attr_value)): | |
errors.append(f"Atribut invalid '{attr_name}=\"{attr_value}\"' în elementul <{current_path}>") | |
# Verifică dacă există copii nevalizi în elementul curent | |
for child in element.children: | |
if isinstance(child, NavigableString) and child.strip(): | |
# Verifică text problematic | |
if "PROBLEMA" in child: | |
errors.append(f"Text problematic '{child.strip()}' găsit în <{current_path}>") | |
# Verifică dacă există text neașteptat în anumite elemente container | |
if element.name in ['table', 'tr', 'ul', 'ol'] and child.strip(): | |
errors.append(f"Text neașteptat '{child.strip()}' găsit direct în elementul <{current_path}>") | |
# Verifică recursiv copiii | |
if isinstance(child, Tag): | |
child_errors = check_element_problems(child, current_path) | |
errors.extend(child_errors) | |
return errors | |
def check_invalid_attributes_in_html(tag): | |
"""Verifică tag-ul și toate tag-urile copil pentru atribute nevalide.""" | |
errors = [] | |
# Verifică atributele tag-ului curent | |
tag_errors = check_tag_attributes(tag) | |
if tag_errors: | |
errors.append(f"Tag-ul <{tag.name}> conține atribute nevalide: {', '.join(tag_errors)}") | |
# Verifică recursiv toate tag-urile copil | |
for child in tag.find_all(True, recursive=True): | |
child_errors = check_tag_attributes(child) | |
if child_errors: | |
errors.append(f"Tag-ul <{child.name}> conține atribute nevalide: {', '.join(child_errors)}") | |
return errors | |
def check_table_structure(table): | |
"""Verifică structura internă a unui tabel pentru a detecta elemente nevalide.""" | |
errors = [] | |
# Verifică atribute nevalide în tabel și tag-uri copil | |
attr_errors = check_invalid_attributes_in_html(table) | |
errors.extend(attr_errors) | |
# Verifică dacă există elemente nevalide în interiorul tabelului | |
for child in table.children: | |
if isinstance(child, NavigableString) and child.strip(): | |
# Am găsit text neașteptat direct în tabel | |
errors.append(f"Text neașteptat '{child.strip()}' găsit direct în elementul <table>") | |
elif isinstance(child, Tag) and child.name != 'tr': | |
# Am găsit un tag neașteptat direct în tabel | |
errors.append(f"Element neașteptat <{child.name}> găsit direct în elementul <table>") | |
# Verifică fiecare rând (tr) al tabelului | |
for tr in table.find_all('tr', recursive=False): | |
# Verifică dacă există elemente nevalide între rânduri | |
next_sibling = tr.next_sibling | |
while next_sibling and next_sibling.name != 'tr': | |
if isinstance(next_sibling, NavigableString) and next_sibling.strip(): | |
errors.append(f"Text neașteptat '{next_sibling.strip()}' găsit între tag-urile </tr> și <tr>") | |
elif isinstance(next_sibling, Tag): | |
errors.append(f"Element neașteptat <{next_sibling.name}> găsit între tag-urile </tr> și <tr>") | |
next_sibling = next_sibling.next_sibling | |
# Verifică conținutul rândului | |
for child in tr.children: | |
if isinstance(child, NavigableString) and child.strip(): | |
errors.append(f"Text neașteptat '{child.strip()}' găsit direct în tag-ul <tr>") | |
elif isinstance(child, Tag) and child.name != 'td' and child.name != 'th': | |
errors.append(f"Element neașteptat <{child.name}> găsit direct în tag-ul <tr>") | |
# Verifică celulele (td/th) din rând | |
for cell in tr.find_all(['td', 'th'], recursive=False): | |
# Verifică atribute nevalide în celule | |
attr_errors = check_tag_attributes(cell) | |
if attr_errors: | |
errors.append(f"Tag-ul <{cell.name}> conține atribute nevalide: {', '.join(attr_errors)}") | |
# Verifică conținutul celulelor pentru probleme | |
for content in cell.contents: | |
if isinstance(content, NavigableString) and "PROBLEMA" in content: | |
errors.append(f"Text problematic '{content.strip()}' găsit în <{cell.name}>") | |
return errors | |
def identify_articles(soup): | |
"""Identifică articolele bazate pe șablonul corect.""" | |
articles = [] | |
current_article = [] | |
# Găsește toate tabelele potențiale de header | |
tables = soup.find_all('table') | |
for table in tables: | |
# Verifică dacă tabelul are span class="den_articol" | |
if table.find('span', class_='den_articol'): | |
# Dacă avem un articol în construcție, îl finalizăm | |
if current_article: | |
articles.append(current_article) | |
current_article = [] | |
# Începem un nou articol cu acest tabel | |
current_article.append(table) | |
# Găsește următoarele elemente ale articolului | |
current_element = table.find_next_sibling() | |
# Adaugă elementele până la următorul tabel cu den_articol sau sfârșitul secțiunii | |
while current_element: | |
# Dacă am găsit un nou tabel de header, oprim acest articol | |
if current_element.name == 'table' and current_element.find('span', class_='den_articol'): | |
break | |
current_article.append(current_element) | |
current_element = current_element.find_next_sibling() | |
# Adaugă ultimul articol dacă există | |
if current_article: | |
articles.append(current_article) | |
return articles | |
def get_article_title(article_elements): | |
"""Extrage titlul articolului din elementele articolului.""" | |
if not article_elements: | |
return "Articol fără elemente" | |
header_table = article_elements[0] | |
den_articol = header_table.find('span', class_='den_articol') | |
if not den_articol: | |
return "Articol fără titlu" | |
link = den_articol.find('a', class_='linkMare') | |
if link and link.string: | |
return link.string.strip() | |
elif link and link.get_text(): | |
return link.get_text().strip() | |
elif den_articol.get_text(): | |
return den_articol.get_text().strip() | |
return "Articol cu titlu nedetectabil" | |
def get_article_url(article_elements): | |
"""Extrage URL-ul articolului din elementele articolului.""" | |
if not article_elements: | |
return None | |
header_table = article_elements[0] | |
den_articol = header_table.find('span', class_='den_articol') | |
if not den_articol: | |
return None | |
link = den_articol.find('a', class_='linkMare') | |
if link and link.get('href'): | |
return link.get('href') | |
return None | |
def check_a_tag_problems(tag): | |
"""Verifică tag-urile <a> pentru probleme specifice.""" | |
errors = [] | |
# Verifică toate tag-urile <a> din elementul dat | |
for a_tag in tag.find_all('a'): | |
# Verifică dacă există un tag <a> fără închidere corectă | |
if a_tag.get('href') and not a_tag.get('href').startswith('http'): | |
# Verifică atributele href pentru a detecta probleme | |
href_attr = a_tag.attrs.get('href', '') | |
# Verifică dacă există spații între atribute | |
tag_str = str(a_tag) | |
if ' href=' not in tag_str and 'href=' in tag_str: | |
errors.append(f"Tag-ul <a> nu are spațiu înainte de atributul href: {tag_str}") | |
# Verifică dacă există ghilimele lipsă | |
if re.search(r'href=([^"\'])', tag_str): | |
errors.append(f"Atributul href nu are ghilimele: {tag_str}") | |
return errors | |
def check_between_articles(articles, idx): | |
"""Identifică și descrie elementele între articole.""" | |
if idx >= len(articles) - 1: | |
return [] # Nu există articol următor | |
current_article = articles[idx] | |
next_article = articles[idx+1] | |
# Obținem URL-urile pentru identificare | |
current_url = get_article_url(current_article) | |
next_url = get_article_url(next_article) | |
# Verificăm dacă primul element al articolului următor vine direct după ultimul element al articolului curent | |
last_elem = current_article[-1] | |
if last_elem and last_elem.name == 'p' and last_elem.get('class') and 'text_obisnuit' in last_elem.get('class'): | |
next_elem = last_elem.find_next_sibling() | |
if next_elem and next_elem != next_article[0]: | |
# Colectează toate elementele între articole | |
between_elements = [] | |
while next_elem and next_elem != next_article[0]: | |
between_elements.append(next_elem) | |
next_elem = next_elem.find_next_sibling() | |
if between_elements: | |
error_msg = [] | |
# Formatăm elementele găsite într-un mod mai clar | |
html_elements = [] | |
for elem in between_elements: | |
if isinstance(elem, Tag): | |
if elem.name == 'br': | |
html_elements.append("<br>") | |
elif elem.name == 'table': | |
html_elements.append("<table...>") | |
elif elem.name == 'div': | |
align = elem.get('align', '') | |
html_elements.append(f"<div align=\"{align}\">") | |
else: | |
html_elements.append(f"<{elem.name}>") | |
else: | |
# Element text | |
text = str(elem).strip() | |
if text: | |
html_elements.append(text[:30] + "..." if len(text) > 30 else text) | |
# Grupăm elementele identice consecutive | |
grouped_elements = [] | |
last_elem = None | |
count = 0 | |
for html_elem in html_elements: | |
if html_elem == last_elem: | |
count += 1 | |
else: | |
if count > 1: | |
grouped_elements.append(f"{last_elem} (repetat de {count} ori)") | |
elif count == 1: | |
grouped_elements.append(last_elem) | |
last_elem = html_elem | |
count = 1 | |
# Adăugăm ultimul grup | |
if count > 1: | |
grouped_elements.append(f"{last_elem} (repetat de {count} ori)") | |
elif count == 1: | |
grouped_elements.append(last_elem) | |
if grouped_elements: | |
elements_str = ", ".join(grouped_elements) | |
error_msg.append(f"S-au găsit elemente suplimentare între articolul cu URL {current_url} și articolul cu URL {next_url}: {elements_str}") | |
return error_msg | |
return [] | |
def get_element_html_string(element): | |
"""Returnează reprezentarea HTML ca string pentru un element.""" | |
if isinstance(element, Tag): | |
tag_name = element.name | |
attrs = [] | |
for attr, value in element.attrs.items(): | |
if isinstance(value, list): | |
value = " ".join(value) | |
attrs.append(f'{attr}="{value}"') | |
attrs_str = " ".join(attrs) | |
if attrs_str: | |
return f"<{tag_name} {attrs_str}>" | |
return f"<{tag_name}>" | |
else: | |
return str(element) | |
def check_article_structure(article_elements, all_articles, article_index): | |
"""Verifică structura unui articol.""" | |
errors = [] | |
# Verifică tabelul header (primul element) | |
if not article_elements or article_elements[0].name != 'table': | |
return ["Articolul nu începe cu un tabel header"] | |
header_table = article_elements[0] | |
# Obține titlul și URL-ul articolului pentru referință | |
title = get_article_title(article_elements) | |
url = get_article_url(article_elements) | |
# Verifică fiecare element din articol pentru text neașteptat | |
for i, element in enumerate(article_elements): | |
if isinstance(element, Tag): | |
# Verifică textul direct în element (inclusiv între tag-uri) | |
for j, content in enumerate(element.contents): | |
if isinstance(content, NavigableString) and content.strip(): | |
errors.append(f"Text neașteptat '{content.strip()}' găsit în elementul <{element.name}> din articolul \"{title}\"") | |
# Verifică atribute nevalide și alte probleme | |
attr_errors = check_invalid_attributes_in_html(element) | |
if attr_errors: | |
errors.extend(attr_errors) | |
# Verifică tag-urile <a> pentru probleme | |
a_tag_errors = check_a_tag_problems(element) | |
if a_tag_errors: | |
errors.extend(a_tag_errors) | |
# Verifică tag-uri neașteptate între elemente consecutive | |
if i < len(article_elements) - 1: | |
# Găsim elementul următor | |
next_elem = article_elements[i+1] | |
# Verificăm dacă există text între elementul curent și cel următor | |
current_next_sibling = element.next_sibling | |
while current_next_sibling and current_next_sibling != next_elem: | |
if isinstance(current_next_sibling, NavigableString) and current_next_sibling.strip(): | |
errors.append(f"Text neașteptat '{current_next_sibling.strip()}' găsit între <{element.name}> și <{next_elem.name}> în articolul \"{title}\"") | |
current_next_sibling = current_next_sibling.next_sibling | |
# Verifică text problematic în interiorul elementelor | |
for element in article_elements: | |
if isinstance(element, Tag): | |
for text in element.find_all(text=True): | |
if "PROBLEMA" in text: | |
errors.append(f"Text problematic '{text.strip()}' găsit în <{element.name}>") | |
# Verifică structura internă a tabelului header | |
table_structure_errors = check_table_structure(header_table) | |
if table_structure_errors: | |
errors.extend(table_structure_errors) | |
# Verifică span class="den_articol" | |
den_articol = header_table.find('span', class_='den_articol') | |
if not den_articol: | |
errors.append("Tabelul header nu conține span class='den_articol'") | |
else: | |
# Verifică link cu class="linkMare" | |
link_mare = den_articol.find('a', class_='linkMare') | |
if not link_mare: | |
errors.append("Span-ul den_articol nu conține link cu class='linkMare'") | |
else: | |
# Verifică atribute nevalide în link-ul mare | |
link_attr_errors = check_tag_attributes(link_mare) | |
if link_attr_errors: | |
errors.append(f"Link-ul cu class='linkMare' conține atribute nevalide: {', '.join(link_attr_errors)}") | |
# Verifică td class="text_dreapta" | |
text_dreapta = header_table.find('td', class_='text_dreapta') | |
if not text_dreapta: | |
errors.append("Tabelul header nu conține td class='text_dreapta' pentru dată și categorie") | |
# Verifică paragraful descriptiv | |
if len(article_elements) < 2 or article_elements[1].name != 'p' or not article_elements[1].get('class') or 'text_obisnuit2' not in article_elements[1].get('class'): | |
errors.append("Lipsește paragraful descriptiv <p class='text_obisnuit2'>") | |
else: | |
# Verifică text italic | |
em_tag = article_elements[1].find('em') | |
if not em_tag: | |
errors.append("Paragraful descriptiv nu conține text italic <em>") | |
# Verifică tabelul de "read more"/"citește mai departe" | |
read_more_table_index = -1 | |
for i, elem in enumerate(article_elements): | |
if i >= 2 and elem.name == 'table' and elem.find('div', id='external2'): | |
read_more_table_index = i | |
break | |
if read_more_table_index == -1: | |
errors.append("Lipsește tabelul cu div id='external2' pentru 'citește mai departe'") | |
else: | |
read_more_table = article_elements[read_more_table_index] | |
# Verifică structura internă a tabelului read_more | |
table_structure_errors = check_table_structure(read_more_table) | |
if table_structure_errors: | |
errors.extend(table_structure_errors) | |
external2_div = read_more_table.find('div', id='external2') | |
if external2_div.get('align') != 'right': | |
errors.append("Div-ul external2 nu are align='right'") | |
# Verifică atribute invalide în div-ul external2 | |
div_attr_errors = check_tag_attributes(external2_div) | |
if div_attr_errors: | |
errors.append(f"Div-ul external2 conține atribute nevalide: {', '.join(div_attr_errors)}") | |
# Verifică specific pentru text după tabelul "citește mai departe" și înainte de paragraful final | |
if read_more_table_index != -1 and read_more_table_index + 1 < len(article_elements): | |
read_more_table = article_elements[read_more_table_index] | |
next_elem = article_elements[read_more_table_index + 1] | |
# Verifică text între tabelul "citește mai departe" și elementul următor | |
current = read_more_table.next_sibling | |
while current and current != next_elem: | |
if isinstance(current, NavigableString) and current.strip(): | |
errors.append(f"Text neașteptat '{current.strip()}' găsit după tabelul 'citește mai departe' în articolul \"{title}\"") | |
current = current.next_sibling | |
# Verifică paragraful gol final | |
has_final_p = False | |
has_wrong_final_p = False | |
final_p_issues = [] | |
unexpected_elements = [] | |
# Căutăm elementele după tabelul de "citește mai departe" | |
if read_more_table_index != -1 and read_more_table_index + 1 < len(article_elements): | |
# Verificăm toate elementele după tabelul de "citește mai departe" | |
for i in range(read_more_table_index + 1, len(article_elements)): | |
elem = article_elements[i] | |
# Verifică dacă este paragraf final corect | |
if elem.name == 'p' and elem.get('class') and 'text_obisnuit' in elem.get('class'): | |
if len(elem.get('class')) == 1 and not elem.get('align') and not elem.string: | |
# Paragraf corect | |
has_final_p = True | |
else: | |
# Paragraf incorect (atribute suplimentare sau text) | |
has_wrong_final_p = True | |
attrs = [] | |
for attr, value in elem.attrs.items(): | |
if isinstance(value, list): | |
value = " ".join(value) | |
attrs.append(f'{attr}="{value}"') | |
attrs_str = " ".join(attrs) | |
final_p_issues.append(f"Există un paragraf final incorect: <p {attrs_str}> în loc de <p class=\"text_obisnuit\"></p>") | |
# Verifică dacă sunt paragrafe finale repetate | |
elif has_final_p and elem.name == 'p' and elem.get('class') and 'text_obisnuit' in elem.get('class'): | |
final_p_issues.append("Paragrafele <p class=\"text_obisnuit\"></p> se repetă unul după altul") | |
# Detectează alte elemente neașteptate | |
elif not has_final_p: | |
unexpected_elements.append(elem) | |
# Procesează elementele neașteptate | |
if unexpected_elements: | |
# Grupează elementele consecutive de același tip | |
element_groups = [] | |
current_group = [] | |
current_type = None | |
for elem in unexpected_elements: | |
elem_type = elem.name if isinstance(elem, Tag) else type(elem).__name__ | |
if elem_type == current_type: | |
current_group.append(elem) | |
else: | |
if current_group: | |
element_groups.append((current_type, current_group)) | |
current_type = elem_type | |
current_group = [elem] | |
# Adaugă ultimul grup | |
if current_group: | |
element_groups.append((current_type, current_group)) | |
# Raportează elementele grupate | |
for elem_type, group in element_groups: | |
if elem_type == 'br' and len(group) > 1: | |
# Grupează tag-urile <br> multiple | |
br_html = "<br>" * len(group) | |
final_p_issues.append(f"Elementul {br_html} este în plus între tagul </table> și <p class=\"text_obisnuit\"></p>") | |
elif len(group) > 1: | |
# Alte elemente repetate | |
elem_html = get_element_html_string(group[0]) | |
final_p_issues.append(f"Elementul {elem_html} se repetă de {len(group)} ori între tagul </table> și <p class=\"text_obisnuit\"></p>") | |
else: | |
# Elemente individuale | |
elem_html = get_element_html_string(group[0]) | |
final_p_issues.append(f"Elementul {elem_html} este în plus între tagul </table> și <p class=\"text_obisnuit\"></p>") | |
# Verifică dacă lipsește paragraful final | |
if not has_final_p and not has_wrong_final_p: | |
final_p_issues.append("Lipsește <p class=\"text_obisnuit\"></p> la sfârșitul articolului") | |
# Adaugă erorile de paragraf final la lista de erori | |
errors.extend(final_p_issues) | |
# Verifică dacă link-urile se repetă de mai mult de 2 ori | |
if den_articol and read_more_table_index != -1 and 'external2_div' in locals() and external2_div: | |
title_links = [a.get('href') for a in den_articol.find_all('a', href=True)] | |
read_more_links = [a.get('href') for a in external2_div.find_all('a', href=True) if not a.find('img')] | |
all_links = title_links + read_more_links | |
link_counts = {} | |
for link in all_links: | |
link_counts[link] = link_counts.get(link, 0) + 1 | |
for link, count in link_counts.items(): | |
if count > 2: | |
errors.append(f"Link-ul '{link}' apare de {count} ori (în loc de maxim 2)") | |
# Verifică elementele între articole | |
between_errors = check_between_articles(all_articles, article_index) | |
errors.extend(between_errors) | |
# Verifică text după ultimul element al articolului | |
if article_elements: | |
last_elem = article_elements[-1] | |
next_sibling = last_elem.next_sibling | |
while next_sibling: | |
if isinstance(next_sibling, NavigableString) and next_sibling.strip(): | |
errors.append(f"Text neașteptat '{next_sibling.strip()}' găsit după ultimul element al articolului \"{title}\"") | |
elif isinstance(next_sibling, Tag): | |
# Dacă următorul element este un nou tabel header, am trecut la alt articol | |
if next_sibling.name == 'table' and next_sibling.find('span', class_='den_articol'): | |
break | |
next_sibling = next_sibling.next_sibling | |
return errors | |
def check_section_structure(section): | |
"""Verifică structura secțiunii pentru articolele corecte.""" | |
soup = BeautifulSoup(section, 'html.parser') | |
errors = [] | |
# Verifică taguri HTML nevalide în întreaga secțiune | |
invalid_tag_errors = check_invalid_html_tags(section) | |
if invalid_tag_errors: | |
errors.extend(invalid_tag_errors) | |
# Verifică dacă există text/elemente nevalide direct în secțiune (în afara articolelor) | |
for child in soup.children: | |
if isinstance(child, NavigableString) and child.strip() and not child.strip().startswith("<!--") and not child.strip().endswith("-->"): | |
# Text neașteptat în afara articolelor și care nu este comentariu HTML | |
errors.append(f"Text neașteptat găsit direct în secțiune: '{child.strip()}'") | |
elif isinstance(child, Tag): | |
# Verifică textul direct în elementele de nivel superior | |
for direct_text in child.contents: | |
if isinstance(direct_text, NavigableString) and direct_text.strip() and not direct_text.strip().startswith("<!--") and not direct_text.strip().endswith("-->"): | |
errors.append(f"Text neașteptat găsit în <{child.name}>: '{direct_text.strip()}'") | |
# Verifică dacă există text problematic în elementele de nivel superior | |
for text in child.find_all(text=True): | |
if "PROBLEMA" in text: | |
errors.append(f"Text problematic '{text.strip()}' găsit în <{child.name}>") | |
# Verifică text neașteptat oriunde în secțiune, nu doar la nivel superior | |
# Caută text în afara tag-urilor HTML în întregul document | |
for text in soup.find_all(text=True): | |
if text.strip() and not text.strip().startswith("<!--") and not text.strip().endswith("-->"): | |
# Verifică dacă textul este în interiorul unui element valid | |
parent = text.parent | |
# Dacă textul este direct în body, div align="justify", sau în alte locuri neașteptate | |
if (parent.name == 'body' or | |
(parent.name == 'div' and parent.get('align') == 'justify') or | |
parent.name in ['table', 'tr']): | |
# Evită raportarea textului din celule td/th, span, a, p - acestea sunt locuri valide pentru text | |
if not (parent.name in ['td', 'th', 'span', 'a', 'em', 'p']): | |
errors.append(f"Text neașteptat '{text.strip()}' găsit în <{parent.name}>") | |
# Specifică verificare pentru text după ultimul div al secțiunii | |
main_div = soup.find('div', attrs={'align': 'justify'}) | |
if main_div: | |
next_sibling = main_div.next_sibling | |
while next_sibling: | |
if isinstance(next_sibling, NavigableString) and next_sibling.strip(): | |
errors.append(f"Text neașteptat '{next_sibling.strip()}' găsit după tag-ul </div> în secțiune") | |
next_sibling = next_sibling.next_sibling | |
# Identifică articolele | |
articles = identify_articles(soup) | |
if not articles: | |
errors.append("Nu s-au găsit articole în secțiune") | |
return False, "\n".join(errors) | |
# Verifică fiecare articol | |
articles_with_errors = [] | |
for idx, article_elements in enumerate(articles): | |
article_errors = check_article_structure(article_elements, articles, idx) | |
if article_errors: | |
title = get_article_title(article_elements) | |
url = get_article_url(article_elements) | |
articles_with_errors.append((idx+1, title, url, article_errors)) | |
if articles_with_errors: | |
for article_idx, title, url, article_errors in articles_with_errors: | |
errors.append(f"Articolul {article_idx} - \"{title}\" (URL: {url}):") | |
for error in article_errors: | |
errors.append(f" - {error}") | |
if errors: | |
return False, "\n".join(errors) | |
return True, None | |
def read_file_with_multiple_encodings(file_path): | |
"""Încearcă să citească fișierul cu diferite codificări.""" | |
encodings = ['utf-8', 'latin-1', 'cp1252', 'iso-8859-1'] | |
for encoding in encodings: | |
try: | |
with open(file_path, 'r', encoding=encoding) as file: | |
return file.read() | |
except UnicodeDecodeError: | |
continue | |
raise UnicodeDecodeError(f"Nu s-a putut citi fișierul {file_path} cu niciuna din codificările: {encodings}") | |
def check_file_structure(file_path): | |
"""Verifică structura unui fișier HTML.""" | |
# Verifică dacă fișierul este în lista celor de ignorat | |
if file_path in files_to_skip: | |
print(f"[Ignorat] {file_path}") | |
return None | |
try: | |
content = read_file_with_multiple_encodings(file_path) | |
sections = extract_sections(content) | |
if not sections: | |
return None | |
# Colectează toate erorile brute | |
all_errors = [] | |
for idx, section in enumerate(sections): | |
is_valid, error_msg = check_section_structure(section) | |
if not is_valid: | |
all_errors.append(f"Secțiunea {idx+1} conține erori de structură:") | |
# Împarte mesajul de eroare în linii și le adaugă cu formatare | |
for line in error_msg.split('\n'): | |
if line.strip(): | |
# Filtrează erorile care se repetă | |
if not any(similar_error in all_errors for similar_error in get_similar_errors(line)): | |
# Îmbunătățește mesajele cu localizări clare | |
enhanced_line = enhance_error_location(line) | |
all_errors.append(f" {enhanced_line}") | |
if all_errors: | |
# Procesează lista finală pentru a elimina duplicatele | |
clean_errors = remove_duplicates(all_errors) | |
return (file_path, clean_errors) | |
return None | |
except Exception as e: | |
return (file_path, [f"Eroare la procesarea fișierului: {e}"]) | |
def get_similar_errors(error): | |
"""Generează variante de erori similare pentru a detecta duplicatele.""" | |
variants = [] | |
# Creează variante pentru a detecta duplicatele | |
if "Text neașteptat" in error: | |
# Extrage textul problematic | |
text_match = re.search(r"Text neașteptat '([^']+)'", error) | |
if text_match: | |
text = text_match.group(1) | |
variants.append(f"Text neașteptat '{text}' găsit în") | |
variants.append(f"Text neașteptat '{text}' găsit direct în") | |
return variants | |
def enhance_error_location(error): | |
"""Îmbunătățește mesajul de eroare cu localizare clară.""" | |
# Pentru text după div | |
if "găsit după tag-ul </div>" in error: | |
return error.replace("găsit după tag-ul </div> în secțiune", | |
"găsit între </div> și <!-- ARTICOL CATEGORIE FINAL -->") | |
# Pentru text în secțiune | |
if "găsit direct în secțiune" in error: | |
return error.replace("găsit direct în secțiune", | |
"găsit înainte de <div align=\"justify\">") | |
# Pentru text în tabele/rânduri fără context | |
if re.search(r"găsit (?:direct )?în (?:elementul )?<(table|tr|p)>", error) and "articolul" not in error: | |
# Identifică articolul din context pentru a adăuga la localizare | |
url_match = re.search(r"URL: (https://[^\s]+)", error) | |
if url_match: | |
url = url_match.group(1) | |
return error + f" (în articolul cu URL {url})" | |
return error | |
def remove_duplicates(errors): | |
"""Elimină duplicatele din lista de erori.""" | |
unique_errors = [] | |
seen = set() | |
for error in errors: | |
# Creează o cheie simplificată pentru a detecta duplicatele | |
key = re.sub(r"în articolul .*?$", "", error) | |
key = re.sub(r"la linia \d+", "", key) | |
key = re.sub(r"context: .*?$", "", key) | |
key = key.strip() | |
if key not in seen: | |
seen.add(key) | |
unique_errors.append(error) | |
return unique_errors | |
def check_html_string(html_content): | |
"""Verifică structura unui string HTML.""" | |
sections = extract_sections(html_content) | |
if not sections: | |
return ["Nu s-au găsit secțiuni între marcajele <!-- ARTICOL CATEGORIE START --> și <!-- ARTICOL CATEGORIE FINAL -->"] | |
errors = [] | |
for idx, section in enumerate(sections): | |
is_valid, error_msg = check_section_structure(section) | |
if not is_valid: | |
errors.append(f"Secțiunea {idx+1} conține erori de structură:\n{error_msg}") | |
return errors | |
def main(): | |
files_with_issues = [] | |
total_files = 0 | |
processed_files = 0 | |
skipped_files = 0 | |
# Calculează numărul total de fișiere HTML din folderele principale (fără subfoldere) | |
for directory in directories: | |
files = [f for f in os.listdir(directory) if os.path.isfile(os.path.join(directory, f)) | |
and (f.lower().endswith('.html') or f.lower().endswith('.htm'))] | |
total_files += len(files) | |
print(f"Începe verificarea structurii pentru {total_files} fișiere HTML...") | |
# Procesează fișierele din folderele principale (fără subfoldere) | |
for directory in directories: | |
print(f"Scanez directorul: {directory}") | |
# Listează doar fișierele din directorul principal, fără subfoldere | |
files = [f for f in os.listdir(directory) if os.path.isfile(os.path.join(directory, f)) | |
and (f.lower().endswith('.html') or f.lower().endswith('.htm'))] | |
for file in files: | |
file_path = os.path.join(directory, file) | |
# Verifică dacă fișierul este în lista celor de ignorat | |
if file_path in files_to_skip: | |
skipped_files += 1 | |
print(f"[{processed_files+skipped_files}/{total_files}] [Ignorat] {file}") | |
continue | |
processed_files += 1 | |
print(f"[{processed_files+skipped_files}/{total_files}] {file}") | |
result = check_file_structure(file_path) | |
if result: | |
files_with_issues.append(result) | |
print("\n---- Rezultate finale ----") | |
if files_with_issues: | |
print(f"S-au găsit {len(files_with_issues)} fișiere cu structuri HTML neconforme:\n") | |
for i, (file_path, errors) in enumerate(files_with_issues): | |
print(f"{file_path}:") | |
for error in errors: | |
print(f" {error}") | |
# Adaugă linia de separare după fiecare fișier, exceptând ultimul | |
if i < len(files_with_issues) - 1: | |
print("-------") | |
else: | |
print("Nu s-au găsit fișiere cu structuri HTML neconforme.") | |
print(f"\nProcesare completă: {processed_files} fișiere verificate, {skipped_files} fișiere ignorate.") | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment