Промежуточное ПО Django для добавления relnofollow для всех внешних ссылок

Я пытаюсь закрыть все внешние URL с параметром rel="nofollow":

Я пишу это простое промежуточное ПО:

import re

NOFOLLOW_RE = re.compile(u'<a (?![^>]*rel=["\']nofollow[\'"])'\
                         u'(?![^>]*href=["\']mysite\.com[\'"])',
                         re.UNICODE|re.IGNORECASE)

class NofollowLinkMiddleware(object):

    def process_response(self, request, response):
        if ("text" in response['Content-Type']):

            response.content = re.sub(NOFOLLOW_RE, u'<a rel="nofollow" ', response.content.decode('UTF8') )
            return response
        else:
            return response

это работает, но закрывает все ссылки внутренние и внешние. И я не знаю, как еще добавить тег для ссылки.

2 ответа

Решение

Сначала вы забыли "http://" и URL-путь. Итак, вы regexp должны быть:

NOFOLLOW_RE = re.compile(u'<a (?![^>]*rel=["\']nofollow[\'"])'\
                         u'(?![^>]*href=["\']http://mysite\.com(/[^\'"]*)?[\'"])',
                         re.U|re.I)

Затем вы также должны рассматривать hrefs, начинающиеся с "/" и "#", как внутренние ссылки:

NOFOLLOW_RE = re.compile(u'<a (?![^>]*rel=["\']nofollow[\'"])'\
                         u'(?![^>]*href=["\'](?:https?://mysite\.com(?:/[^\'"]*)|/[^\'"]*|#[^\'"]*)[\'"])',
                         re.U|re.I)

Также вы, возможно, захотите принять во внимание домен 3-го уровня и протокол "https://".

Для тега вы можете использовать группы, посмотрите на re.sub() в документации по Python:

NOFOLLOW_RE = re.compile(u'<a (?P<link>(?![^>]*rel=["\']nofollow[\'"])'\
                         u'(?![^>]*href=["\'](?:https?://mysite\.com(?:/[^\'"]*)|/[^\'"]*|#[^\'"]*)[\'"]).*?</a>)',
                         re.U|re.I)
...
response.content = NOFOLLOW_RE.sub(u'<noindex><a rel="nofollow" \g<link></noindex>', your_html)

Это регулярное выражение является странным. Я настоятельно рекомендую вам написать тест со всеми возможными комбинациями тегов и их атрибутов, которые вы можете себе представить. Если после этого вы обнаружите какую-то проблему в этом коде, тест поможет вам не все сломать.

Я знаю, что я очень поздно, но я оставляю ответ за других. @HighCat дал правильный ответ на все случаи, кроме одного. Выше регулярное выражение также добавит nofollow к ссылке http://example.com/

Так что регулярное выражение в этом случае должно быть =>

import re

NOFOLLOW_RE = re.compile(u'<a (?P<link>(?![^>]*rel=["\']nofollow[\'"])'\
                         u'(?![^>]*href=["\'](?:https?://example\.com/?(?:[^\'"]*)|/[^\'"]*|#[^\'"]*)[\'"]).*?</a>)',
                         re.U|re.I)

class NofollowLinkMiddleware(object):

    def process_response(self, request, response):
        if ("text" in response['Content-Type']):

            response.content = NOFOLLOW_RE.sub(u'<a rel="nofollow" target="_blank" \g<link>', response.content.decode('UTF8') )
            return response
        else:
            return response

Это незначительное изменение. Я должен комментировать или редактировать, но у меня недостаточно репутации (для комментариев), и редактирование также требует изменения 6+ символов.

Другие вопросы по тегам