Участник:BsivkoBot/UTM-метки

Описание

Мотивация

Тематическое обсуждение: Википедия:Запросы_к_ботоводам/Архив/2019/3#Очистить_UTM-метки_—_2
Тематическое обсуждение: Википедия:Форум/Архив/Технический/2017/06#UTM_parameters

UTM-метки являются служебной информацией и не влияют на попадание в целевую страницу. Соответственно, их содержимое избыточно. Более того, эти значения описывают маркетинговые элементы распространения информации.

Реализация

Бот ищет контекстно UTM-параметры, и удаляет их из текста вместе со значениями параметров URL.

Синтаксический разбор идёт от имени параметра до концовки - это один из символов '&', ' ', '\n', '\r', '<', ']'.

Список удаляемых параметров:

  • utm_source
  • utm_medium
  • utm_content
  • utm_referrer
  • utm_campaign
  • utm_term
  • utm
  • utm_cid
  • utm_hp_ref

Помимо классических UTM-меток, добавлены аналогичные других ресурсов (пример fbclid от Фейсбука):

  • fbclid
  • yclid
  • gclid
  • igshid

Исходный код

import mwparserfromhell

from processing.options.options_impl import get_options

TASK_UTM = "UTM-метки"


def process_utm_for_http_text(http_text):
    utms = ["utm_source", "utm_medium", "utm_content", "utm_referrer", "utm_campaign", "utm_term", "utm", "utm_cid",
            "utm_hp_ref", "yclid", "gclid", "fbclid", "igshid"]

    if "utm." in http_text:
        return http_text
    if not ("&utm" in http_text or "?utm" in http_text or "clid" in http_text or "shid" in http_text):
        return http_text

    text = http_text

    changed = False
    for one_utm in utms:
        while one_utm in text:
            pos = text.find(one_utm)
            end = pos + 1
            pos = pos - 1
            while True:
                if end >= len(text):
                    break
                if text[end] in ['&', '\n', '\r', '<', ']', ' ']:
                    break
                end += 1

            if end > len(text):
                continue

            if end == len(text):
                text = text[:pos]
                changed = True
                continue

            if text[end] in ['.']:
                break

            if text[pos] == '?' and text[end] == '&':
                pos += 1
                end += 1

            text = text[:pos] + text[end:]
            changed = True
    if changed:
        return text

    return http_text


def process_utm(text):
    # in templates

    parsed = mwparserfromhell.parse(text)

    for template in parsed.ifilter_templates():
        for param in template.params:
            value = template.get(param.name).value.strip()
            if "http:" not in value and "https:" not in value:
                continue
            utmed_text = process_utm_for_http_text(value)
            if utmed_text != value:
                template.get(param.name).value = utmed_text

    output = str(parsed)
    text = output

    # in text-ref's

    pairs = {
        'http://': [' ', '</ref>'],
        'https://': [' ', '</ref>']
    }

    for start, finish in pairs.items():
        pos = 0
        while True:
            pos = text.find(start, pos)
            if pos != -1:
                end = -1
                for f in finish:
                    i_end = text.find(f, pos)
                    if i_end != -1:
                        if end == -1:
                            end = i_end
                        else:
                            if i_end < end:
                                end = i_end
                if end != -1:
                    value = text[pos:end]
                    utmed_text = process_utm_for_http_text(value)
                    if utmed_text != value:
                        text = text[:pos] + utmed_text + text[end:]
                    else:
                        pos = end
                else:
                    break
            else:
                break

    return text


def utm_for_article(text, title="unknown"):
    options = get_options()
    exceptions = options.get("статьи")["исключить_если_есть_в_названии"]['utm']
    if title in exceptions:
        return text
    return process_utm(text)

Тестирование

from text_processing.utm import process_utm


def test_utm():
    assert process_utm(
        '<ref>{{cite web|url=http://www.bashinform.ru/news/?yn&utm_source=yxnews&utm_medium=desktop&utm_referrer=https%3A%2F%2Fyandex.ru%2Fnews Информация ИА «Башинформ»}}</ref>') == \
           '<ref>{{cite web|url=http://www.bashinform.ru/news/?yn& Информация ИА «Башинформ»}}</ref>'
    assert process_utm(
        '<ref>{{cite web|url=https://auto.rambler.ru/roadaccidents/ Далее: https://auto.rambler.ru/roadaccidents/42930390/?utm_content=rauto&utm_medium=read_more&utm_source=copylink}}</ref>') == \
           '<ref>{{cite web|url=https://auto.rambler.ru/roadaccidents/ Далее: https://auto.rambler.ru/roadaccidents/42930390/?}}</ref>'
    assert process_utm(
        '<ref>{{cite web|url=https://tass.ru/mezhdunarodnaya-panorama/6992630?utm_referrer=https%3A%2F%2Fzen.yandex.com%2F%3Ffrom%3Dspecial&utm_source=YandexZenSpecial Турция и сирийская оппозиция захватили город Рас-эль-Айн в Сирии}}</ref>') == \
           '<ref>{{cite web|url=https://tass.ru/mezhdunarodnaya-panorama/6992630? Турция и сирийская оппозиция захватили город Рас-эль-Айн в Сирии}}</ref>'
    assert process_utm(
        '<ref>{{cite web|url=https://tass.ru/opinions/7118243?utm_source=yxnews&utm_medium=desktop&utm_referrer=https%3A%2F%2Fyandex.ru%2Fnews |title= Боливия без Моралеса. Почему никто пока не смог успокоить волнения в этой стране |author= Юрьева Дарья|date=|work=|publisher= ТАСС |accessdate= 2019-11-14|lang= |archiveurl=https://web.archive.org/web/20191116085511/https://tass.ru/opinions/7118243?utm_source=yxnews&utm_medium=desktop&utm_referrer=https://yandex.ru/news|archivedate=2019-11-16|deadlink=no}}</ref>') == \
           '<ref>{{cite web|url=https://tass.ru/opinions/7118243?|title= Боливия без Моралеса. Почему никто пока не смог успокоить волнения в этой стране |author= Юрьева Дарья|date=|work=|publisher= ТАСС |accessdate= 2019-11-14|lang= |archiveurl=https://web.archive.org/web/20191116085511/https://tass.ru/opinions/7118243?|archivedate=2019-11-16|deadlink=no}}</ref>'
    assert process_utm(
        'http://www.bashinform.ru/news/?yn&utm_source=yxnews&utm_medium=desktop&utm_referrer=https%3A%2F%2Fyandex.ru%2Fnews Информация ИА «Башинформ»') == \
           'http://www.bashinform.ru/news/?yn& Информация ИА «Башинформ»'
    assert process_utm(
        '<ref>http://www.bashinform.ru/news/?yn&utm_source=yxnews&utm_medium=desktop&utm_referrer=https%3A%2F%2Fyandex.ru%2Fnews</ref>') == \
           '<ref>http://www.bashinform.ru/news/?yn&</ref>'

Состояние и развитие

  • Тестирование. Bsivko (обс.) 09:51, 1 ноября 2019 (UTC)
  • Что есть обработано и поставлено в боевой режим. Bsivko (обс.) 14:37, 1 ноября 2019 (UTC)
  • В последние пару недель были найдены случаи ложного срабатывания. В связи с этим изменилась форма поиска — на поля шаблонов, содержащих ссылки (URL) и <ref>'ы. Помимо этого, добавлены на удаление параметры utm_cid и utm_hp_ref. Bsivko (обс.) 14:02, 28 декабря 2019 (UTC)
  • Добавлены метки других ресурсов: fbclid, yclid, gclid. Bsivko (обс.) 19:22, 30 января 2020 (UTC)
  • Добавлена метка инстаграмма (igshid). Bsivko (обс.) 10:09, 8 июля 2020 (UTC)

Обсуждение