vacancy detail SEO fix
This commit is contained in:
173
seo_helpers.py
173
seo_helpers.py
@@ -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
|
||||||
@@ -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",
|
||||||
|
|||||||
Reference in New Issue
Block a user