Лучший способ отфильтровать электронные письма и домены в python

#python #regex #email #filtering #email-validation

#python #регулярное выражение #Адрес электронной почты #фильтрация #проверка электронной почты

Вопрос:

У меня есть список электронных писем и доменов, которые я пытаюсь отфильтровать как черный список

Для электронной почты это легко, так как я могу просто сравнить электронные письма напрямую, но для доменов электронные письма с поддоменами и т.д. Также должны быть сопоставлены.

итак, для foo.com домен, мне нужно было бы отфильтровать

 x@foo.com
x@subdomain.foo.com
  

Как это обычно делается? Через регулярное выражение? Разделение электронного письма на соответствующие строки?

Комментарии:

1. это длинный список доменов?

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

3. если список длинный, как это лучше сделать?

Ответ №1:

Я думаю, что самый простой способ добиться этого — использовать строковый метод ends_with . Этот метод работает следующим образом:

 >>> blacklisted = 'foo.com'
>>> email = 'x@foo.com'
>>> email.endswith('foo.com')
True
>>> email = 'x@subdomain.foo.com'
>>> email.endswith('foo.com')
True
  

Итак, это вернет true, если домен, или электронная почта, или что-то еще заканчивается на 'foo.com' . Как вы можете видеть, это будет включать все поддомены 'foo.com' . Удобно, что вы также можете передать кортеж в endswith , поэтому, если вы создадите кортеж из своих доменов, занесенных в черный список, вы могли бы сделать что-то вроде этого:

 >>> blacklisted = ('foo.com', 'bar.com')
>>> email = 'x@bar.com'
>>> email.endswith(blacklisted)
True
  

Преимущество этого даже будет заключаться в том, что некоторые поддомены будут занесены в черный список, но не другие.

 >>> blacklisted = ('foo.com', 'bar.com', 'sub.baz.net')
>>> email_bad = 'x@sub.baz.net'
>>> email_bad.endswith(blacklisted)
True
>>> email_good = 'x@good.baz.net'
>>> email_good.endswith(blacklisted)
False
  

Редактировать: В ответ на комментарий Авариса:

Чтобы убедиться, что вы не столкнетесь с такой ситуацией:

 >>> blacklisted = ('bar.com', 'baz.com')
>>> email = 'x@foobar.com'
>>> email.endswith(blacklisted)
True
  

Вы можете включить в свой черный список как '.bar.com' , так и '@bar.com' . Результатом чего является

 >>> blacklisted = ('.bar.com', '@bar.com', '.baz.com', '@baz.com')
>>> email = 'x@foobar.com'
>>> email.endswith(blacklisted)
False
  

Очевидно, что это требует больше работы. На данный момент я бы сказал, что этот метод по сравнению с регулярным выражением является вопросом предпочтения. Хотя я стараюсь избегать регулярных выражений любой ценой, это может быть правильным решением для вас.

Комментарии:

1. x@foobar.com будет выведен в черный список, если у вас есть bar.com как нежелательный.

2. Блин, я об этом не подумал. Можете ли вы увидеть простое исправление, или эта идея бесполезна?

3. Возможно, вы могли бы поместить оба @bar.com и .bar.com в список нежелательных вместо просто bar.com .

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

5. станет ли это неэффективным, если у меня будет большое количество электронных писем, занесенных в черный список?

Ответ №2:

Это был бы самый простой способ, который я могу придумать:

 >>> f = 'foo@subdomain.bar.com'
>>> '.'.join(f.split('.')[-2:])
'bar.com'
  

В нем не используется регулярное выражение, это всего лишь одна строка, очень читаемая, она выводит имя домена и имеет дополнительное преимущество в том, что не заботится о том, является ли домен .com, .net или каким-либо другим.

Затем вы бы просто сверили извлеченный домен с таблицей, занесенной в черный список.

РЕДАКТИРОВАТЬ: Ок, для .co.uk домены и др.

 >>> import re
>>> def get_addr(email_addr):
        parts = re.split(r'[@.]', email_addr)
        return '.'.join(parts[(-3 if parts[-2] == 'co' else -2):])
>>> get_addr('foo@subdomain.bar.com')
'bar.com'
>>> get_addr('foo@subdomain.bar.co.uk')
'bar.co.uk'
>>> get_addr('foo@bar.com')
'bar.com'
  

Редактировать:
@Wilduck указал, что могут быть варианты использования, когда вы хотите отфильтровать определенные вложенные файлы, но не другие (т. Е. ‘community.ebay.co.uk ‘). Я подумал, что вы, возможно, захотите внести в черный список и определенные адреса электронной почты, не создавая отдельную таблицу (ie exgirlfriend@gmail.com ). Вот мое решение:

 >>> def is_in_blacklist(addr):
...     #check if addr is in your list or db table
...     return True or False

>>> def addr_is_blacklisted(addr):
...     if not addr: return False
...     if is_in_blacklist(addr):
...         return True
...     sliced = '.'.join(addr.split('@' if '@' in addr else '.')[1:])
...     return addr_is_blacklisted(sliced)
  

Итак, это деконструкция адреса электронной почты от начала до конца и проверка каждой части по вашему черному списку. Очевидно, что вы не можете получить ответ с помощью одного запроса, но вы можете фильтровать по отдельным адресам электронной почты, по поддоменам, по доменам и вплоть до доменов верхнего уровня, если вам так хочется. В среднем у вас будет 3-4 запроса на электронное письмо, и вы не убьете себя, если у вас будет огромный черный список.

Комментарии:

1. foo@subdomain.bar.co.uk ? Кроме того, почему вы хотите обязательно занести в черный список оба whitehouse.com и whitehouse.gov ?

2. да, электронные письма должны быть международными

3. И это также приведет к сбою для foo@bar.com .

4. Ах, об этом не подумал. Хорошо, новая правка обработает ‘foo@bar.com ‘, ‘foo@subdomain.bar.com ‘, и ‘foo@subdomain.bar.co.uk ‘

5. @Wilduck, это не привело бы к обоим whitehouse.com и whitehouse.gov быть занесенным в черный список. Функция извлекает доменное имя электронной почты, которое вы бы сравнили с таблицей. Если whitehouse.com был внесен в черный список, whitehouse.gov электронные письма не будут затронуты.

Ответ №3:

как насчет

 .*foo.com$
  

работает ли это?

Комментарии:

1. является ли регулярное выражение разумным способом?

2. должен ли я хранить регулярное выражение вместо домена?

3. Следует отметить, что это связано с той же проблемой, на которую указал Аварис str.endswith . А именно, что оно будет соответствовать 'x@barfoo.com' .