#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'
.