如何在re.findall中排除字符串?
这可能是个傻问题,但我只是想学习!
我正在尝试制作一个简单的电子邮件搜索工具,以便更好地了解Python。我正在修改一些开源代码来解析电子邮件地址:
emails = re.findall(r'([A-Za-z0-9\.\+_-]+@[A-Za-z0-9\._-]+\.[a-zA-Z]*)', html)
然后我使用CSV模块将结果写入电子表格。
因为我想让域名后缀可以是几乎任何类型,所以我的结果中输出了一些带有电子邮件格式的图像文件:
例如:forbes@2x-302019213j32.png
我该如何添加代码来排除“png”这个字符串呢?
代码:
def scrape(self, page): try: request = urllib2.Request(page.url.encode("utf8")) html = urllib2.urlopen(request).read() except Exception, e: return emails = re.findall(r'([A-Za-z0-9\.\+_-]+@[A-Za-z0-9\._-]+\.[a-zA-Z]*)', html) for email in emails: if email not in self.emails: # if not a duplicate self.csvwriter.writerow([page.title.encode('utf8'), page.url.encode("utf8"), email]) self.emails.append(email)
3 个回答
我知道Joran已经给你回复了,但我想分享另一种用Python正则表达式的方法,我觉得很有意思。
这里有一个 (?!...)
的匹配模式,它的意思是:“无论你把这个匹配模式放在哪里,如果在字符串的那个点检查这个模式并且找到了匹配,那么这个匹配就失败。”
如果这个解释不太好,Python的文档解释得更清楚:https://docs.python.org/2/howto/regex.html#lookahead-assertions
另外,这里有一个实际的例子:
y = r'([A-Za-z0-9\.\+_-]+@[A-Za-z0-9\._-]+\.(?!png)[a-zA-z]*)'
s = 'forbes@2x-302019213j32.png'
re.findall(y, s) # Will return an empty list
s2 = 'myname@email2018529391230.net'
re.findall(y, s2) # Will return a list with s2 string
s3 = s + ' ' + s2 # Concatenates the two e-mail-formatted strings
re.findall(y, s3) # Will only return s2 string in list
有很多方法可以做到这一点,但我最喜欢的是:
pat = re.compile(r'''
[A-Za-z0-9\.\+_-]+ # 1+ \w\n.+-_
@[A-Za-z0-9\._-]+ # literal @ followed by same
\.png # if png, DON'T CAPTURE
|([A-Za-z0-9\.\+_-]+@[A-Za-z0-9\._-]+\.[a-zA-Z]*)
# if not png, CAPTURE''', flags=re.X)
因为正则表达式是从左到右进行匹配的,所以如果一个字符串开始匹配,它会先匹配到|
左边的部分。如果这个字符串以.png
结尾,它会匹配这个字符串,但不会把它捕获下来。如果它不是以.png
结尾,那么|
右边的部分就会开始匹配,并且会把它捕获下来。想要更深入了解这个技巧,可以点击这里。使用这些方法时,你可以这样做:
matches = filter(None,pat.findall(html))
所有被左边部分匹配到的字符串(比如所有匹配到的png
文件,但不在捕获组内的)在你的findall结果中会显示为空字符串。filter(None, iterable
)会把你的可迭代对象中的所有空字符串去掉,留下你想要的数据。
另外,你也可以在抓取到所有数据后再进行过滤。
pat = re.compile(r'''[A-Za-z0-9\.\+_-]+@[A-Za-z0-9\._-]+\.[a-zA-Z]*''')
# same regex you have currently
matches = filter(lambda x: not x.endswith('png'), pat.findall(html))
需要注意的是,接下来你应该把self.emails
改成一个集合。它似乎不需要保持顺序,而集合的查找速度比列表快得多。不过,记得使用set.add
而不是list.append
。
你现在已经在用一个if语句了,只需要把其中的一部分放到if的检查里就行了……这样做会比试图从正则表达式中排除它简单得多。
if email not in self.emails and not email.endswith("png"): # if not a duplicate
self.csvwriter.writerow([page.title.encode('utf8'), page.url.encode("utf8"), email])
self.emails.append(email)