如何从re.findall中排除字符串?

时间:2014-07-14 16:18:33

标签: python regex scrape

这可能是一个愚蠢的问题,但我只是想学习!

我正在尝试构建一个简单的电子邮件搜索工具,以了解有关python的更多信息。我正在修改一些开源代码来解析电子邮件地址:

emails = re.findall(r'([A-Za-z0-9\.\+_-]+@[A-Za-z0-9\._-]+\.[a-zA-Z]*)', html)

然后我使用CSV模块将结果写入电子表格。

由于我想保持域扩展几乎任何一个,我的结果是输出电子邮件类型格式的图像文件:

示例:forbes@2x-302019213j32.png

如何添加以从re.findall

中排除“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 个答案:

答案 0 :(得分:2)

你已经只对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)

答案 1 :(得分:2)

有很多方法可以做到这一点,但我最喜欢的是:

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结尾,|的右侧将开始消耗它并将捕获它。有关此技巧的更深入的对话,see here。要使用它们:

matches = filter(None,pat.findall(html))

左侧匹配的任何字符串(例如,匹配但不属于捕获组的所有png文件)将在您的findall中显示为空字符串。 filter(None, iterable)从您的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

答案 2 :(得分:2)

我知道Joran已经给了你一个回应,但是这是用Python正则表达式做的另一种方法,我觉得很酷。

有一个(?!...)匹配模式,基本上说:“无论你在哪里放置这种匹配模式,如果在字符串中的那个点检查这个模式并找到匹配,那么该匹配发生失败。”< / p>

如果这是一个糟糕的解释,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