vacancy detail SEO fix

This commit is contained in:
2026-03-20 19:49:22 +03:00
parent b623bc7456
commit a5ee736987
2 changed files with 51 additions and 124 deletions

View File

@@ -177,144 +177,71 @@ def generate_vacancy_seo_tags(vacancy_data: Dict[str, Any], vacancy_id: int) ->
def inject_seo_tags(html_template: str, seo_tags: Dict[str, str]) -> str: def inject_seo_tags(html_template: str, seo_tags: Dict[str, str]) -> str:
""" """
Внедрение SEO-тегов в HTML шаблон Внедрение SEO-тегов в HTML шаблон
Args:
html_template: исходный HTML
seo_tags: словарь с SEO-тегами
Returns:
HTML с замененными SEO-тегами
""" """
replacements = {
'<title id="pageTitle">Резюме | Rabota.Today</title>': f'<title>{seo_tags.get("title", "Rabota.Today")}</title>',
'<title id="pageTitle">Вакансия | Rabota.Today</title>': f'<title>{seo_tags.get("title", "Rabota.Today")}</title>',
'<meta name="description" id="metaDescription"': f'<meta name="description"',
'<meta name="keywords"': f'<meta name="keywords"',
'<meta property="og:title" id="ogTitle"': f'<meta property="og:title"',
'<meta property="og:description" id="ogDescription"': f'<meta property="og:description"',
'<meta property="og:url" id="ogUrl"': f'<meta property="og:url"',
'<meta property="profile:first_name" id="profileFirstName"': f'<meta property="profile:first_name"',
'<meta property="profile:last_name" id="profileLastName"': f'<meta property="profile:last_name"',
'<meta name="twitter:title" id="twitterTitle"': f'<meta name="twitter:title"',
'<meta name="twitter:description" id="twitterDescription"': f'<meta name="twitter:description"',
'<link rel="canonical" id="canonicalUrl"': f'<link rel="canonical"'
}
result = html_template result = html_template
# Заменяем общие теги # Заменяем title
for old, new in replacements.items(): title_pattern = '<title id="pageTitle">.*?</title>'
if old in result: result = re.sub(title_pattern, f'<title>{seo_tags.get("title", "Rabota.Today")}</title>', result)
result = result.replace(old, new)
# Вставляем конкретные значения # Заменяем description
if 'description' in seo_tags: desc_pattern = '<meta name="description" id="metaDescription" content=".*?">'
desc_pattern = '<meta name="description" content="' result = re.sub(desc_pattern, f'<meta name="description" content="{seo_tags.get("description", "")}">', result)
desc_start = result.find(desc_pattern)
if desc_start != -1:
desc_end = result.find('">', desc_start)
if desc_end != -1:
result = result[
:desc_start] + f'<meta name="description" content="{seo_tags["description"]}">' + result[
desc_end + 2:]
if 'keywords' in seo_tags: # Заменяем keywords
keywords_pattern = '<meta name="keywords" content="' keywords_pattern = '<meta name="keywords" id="metaKeywords" content=".*?">'
keywords_start = result.find(keywords_pattern) result = re.sub(keywords_pattern, f'<meta name="keywords" content="{seo_tags.get("keywords", "")}">', result)
if keywords_start != -1:
keywords_end = result.find('">', keywords_start)
if keywords_end != -1:
result = result[:keywords_start] + f'<meta name="keywords" content="{seo_tags["keywords"]}">' + result[
keywords_end + 2:]
if 'og_title' in seo_tags: # Заменяем og:title
og_title_pattern = '<meta property="og:title" content="' og_title_pattern = '<meta property="og:title" id="ogTitle" content=".*?">'
og_title_start = result.find(og_title_pattern) result = re.sub(og_title_pattern, f'<meta property="og:title" content="{seo_tags.get("og_title", "")}">', result)
if og_title_start != -1:
og_title_end = result.find('">', og_title_start)
if og_title_end != -1:
result = result[
:og_title_start] + f'<meta property="og:title" content="{seo_tags["og_title"]}">' + result[
og_title_end + 2:]
if 'og_description' in seo_tags: # Заменяем og:description
og_desc_pattern = '<meta property="og:description" content="' og_desc_pattern = '<meta property="og:description" id="ogDescription" content=".*?">'
og_desc_start = result.find(og_desc_pattern) result = re.sub(og_desc_pattern, f'<meta property="og:description" content="{seo_tags.get("og_description", "")}">',
if og_desc_start != -1: result)
og_desc_end = result.find('">', og_desc_start)
if og_desc_end != -1:
result = result[
:og_desc_start] + f'<meta property="og:description" content="{seo_tags["og_description"]}">' + result[
og_desc_end + 2:]
if 'og_url' in seo_tags: # Заменяем og:url
og_url_pattern = '<meta property="og:url" content="' og_url_pattern = '<meta property="og:url" id="ogUrl" content=".*?">'
og_url_start = result.find(og_url_pattern) result = re.sub(og_url_pattern, f'<meta property="og:url" content="{seo_tags.get("og_url", "")}">', result)
if og_url_start != -1:
og_url_end = result.find('">', og_url_start)
if og_url_end != -1:
result = result[:og_url_start] + f'<meta property="og:url" content="{seo_tags["og_url"]}">' + result[
og_url_end + 2:]
# Заменяем profile:first_name
first_name_pattern = '<meta property="profile:first_name" id="profileFirstName" content=".*?">'
if 'profile_first_name' in seo_tags: if 'profile_first_name' in seo_tags:
first_name_pattern = '<meta property="profile:first_name" content="' result = re.sub(first_name_pattern,
first_name_start = result.find(first_name_pattern) f'<meta property="profile:first_name" content="{seo_tags.get("profile_first_name", "")}">',
if first_name_start != -1: result)
first_name_end = result.find('">', first_name_start)
if first_name_end != -1:
result = result[
:first_name_start] + f'<meta property="profile:first_name" content="{seo_tags["profile_first_name"]}">' + result[
first_name_end + 2:]
# Заменяем profile:last_name
last_name_pattern = '<meta property="profile:last_name" id="profileLastName" content=".*?">'
if 'profile_last_name' in seo_tags: if 'profile_last_name' in seo_tags:
last_name_pattern = '<meta property="profile:last_name" content="' result = re.sub(last_name_pattern,
last_name_start = result.find(last_name_pattern) f'<meta property="profile:last_name" content="{seo_tags.get("profile_last_name", "")}">',
if last_name_start != -1: result)
last_name_end = result.find('">', last_name_start)
if last_name_end != -1:
result = result[
:last_name_start] + f'<meta property="profile:last_name" content="{seo_tags["profile_last_name"]}">' + result[
last_name_end + 2:]
if 'twitter_title' in seo_tags: # Заменяем twitter:title
twitter_title_pattern = '<meta name="twitter:title" content="' twitter_title_pattern = '<meta name="twitter:title" id="twitterTitle" content=".*?">'
twitter_title_start = result.find(twitter_title_pattern) result = re.sub(twitter_title_pattern, f'<meta name="twitter:title" content="{seo_tags.get("twitter_title", "")}">',
if twitter_title_start != -1: result)
twitter_title_end = result.find('">', twitter_title_start)
if twitter_title_end != -1:
result = result[
:twitter_title_start] + f'<meta name="twitter:title" content="{seo_tags["twitter_title"]}">' + result[
twitter_title_end + 2:]
if 'twitter_description' in seo_tags: # Заменяем twitter:description
twitter_desc_pattern = '<meta name="twitter:description" content="' twitter_desc_pattern = '<meta name="twitter:description" id="twitterDescription" content=".*?">'
twitter_desc_start = result.find(twitter_desc_pattern) result = re.sub(twitter_desc_pattern,
if twitter_desc_start != -1: f'<meta name="twitter:description" content="{seo_tags.get("twitter_description", "")}">', result)
twitter_desc_end = result.find('">', twitter_desc_start)
if twitter_desc_end != -1:
result = result[
:twitter_desc_start] + f'<meta name="twitter:description" content="{seo_tags["twitter_description"]}">' + result[
twitter_desc_end + 2:]
if 'canonical_url' in seo_tags: # Заменяем canonical
canonical_pattern = '<link rel="canonical" href="' canonical_pattern = '<link rel="canonical" id="canonicalUrl" href=".*?">'
canonical_start = result.find(canonical_pattern) result = re.sub(canonical_pattern, f'<link rel="canonical" href="{seo_tags.get("canonical_url", "")}">', result)
if canonical_start != -1:
canonical_end = result.find('">', canonical_start)
if canonical_end != -1:
result = result[
:canonical_start] + f'<link rel="canonical" href="{seo_tags["canonical_url"]}">' + result[
canonical_end + 2:]
# Вставляем структурированные данные # Заменяем структурированные данные - заменяем весь блок от <script type="application/ld+json"> до </script>
if 'structured_data' in seo_tags: structured_pattern = r'<script type="application/ld+json">.*?</script>'
structured_pattern = '<script type="application/ld+json" id="structuredData">' # Находим и заменяем первый блок структурированных данных
structured_start = result.find(structured_pattern) result = re.sub(structured_pattern,
if structured_start != -1: f'<script type="application/ld+json">\n{seo_tags.get("structured_data", "{}")}\n</script>', result,
structured_end = result.find('</script>', structured_start) count=1)
if structured_end != -1:
result = result[ # Удаляем второй пустой блок, если он есть
:structured_start] + f'<script type="application/ld+json">\n{seo_tags["structured_data"]}\n</script>\n<script type="application/ld+json" id="structuredData" style="display:none;">' + result[ empty_structured_pattern = r'<script type="application/ld\+json" id="structuredData" style="display:none;">\s*</script>'
structured_end + 9:] result = re.sub(empty_structured_pattern, '', result)
return result return result

View File

@@ -34,7 +34,7 @@
<meta name="theme-color" content="#0b1c34"> <meta name="theme-color" content="#0b1c34">
<!-- Структурированные данные (JSON-LD) будут заменены сервером --> <!-- Структурированные данные (JSON-LD) будут заменены сервером -->
<script type="application/ld+json" id="structuredData"> <script type="application/ld+json">
{ {
"@context": "https://schema.org", "@context": "https://schema.org",
"@type": "JobPosting", "@type": "JobPosting",