在Python中过滤电子邮件和域名的最佳方法
我有一份电子邮件和域名的列表,我想把它们作为黑名单来过滤掉。
对于电子邮件来说,这很简单,因为我可以直接比较电子邮件。但对于域名来说,像带有子域名的电子邮件也需要一起匹配。
比如说,对于foo.com这个域名,我需要过滤掉:
x@foo.com
x@subdomain.foo.com
通常是怎么做的呢?是用正则表达式吗?还是把电子邮件拆分成合适的字符串来处理?
3 个回答
那这个怎么样呢
.*foo\.com$
这样可以吗?
这是我能想到的最简单的方法:
>>> 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')。我想,你可能也想要把特定的邮箱地址加入黑名单,而不需要单独建立一个表(比如 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 次查询,如果你的黑名单很大,也不会让你崩溃。
我觉得最简单的方法是用 字符串方法 ends_with
。这个方法的工作原理是这样的:
>>> blacklisted = 'foo.com'
>>> email = 'x@foo.com'
>>> email.endswith('foo.com')
True
>>> email = 'x@subdomain.foo.com'
>>> email.endswith('foo.com')
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
编辑: 针对 Avaris 的评论:
为了确保你不会遇到这种情况:
>>> 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
显然,这样会多花一些功夫。到这里我觉得用这种方法和正则表达式相比,主要是个人喜好。虽然我尽量避免使用正则表达式,但对你来说,可能正则表达式更合适。