在Python正则表达式搜索中使用通配符匹配字符串

14

我想写一些快速代码来下载Facebook页面的“粉丝”数量。

尽管我已经尝试了相当多的迭代,但出于某种原因,我无法让以下代码挑选出HTML中的粉丝数量。其他我在网络上找到的解决方案也没有正确匹配这种情况下的正则表达式。肯定有可能在两个匹配位之间添加通配符吧?

我想要匹配的文本是“6 of X fans”,其中X是页面拥有的任意数量的粉丝 - 我想获取这个数字。

我正在考虑间断轮询这些数据并将其写入文件,但我还没有开始。我也在思考这是否是正确的方向,因为代码看起来相当笨重。 :)

import urllib
import re

fbhandle = urllib.urlopen('http://www.facebook.com/Microsoft')
pattern = "6 of(.*)fans" #this wild card doesnt appear to work?
compiled = re.compile(pattern)

for lines in fbhandle.readlines():
        ms = compiled.match(lines)
        print ms #debugging
        if ms: break
#ms.group()
print ms
fbhandle.close()

1
“不起作用”并不是一个问题描述。 - Jochen Ritzel
注意:您应该将“lines”命名为“line”。 - miku
1
请发布您要匹配的文本(如果可能的话),并期望的结果。 - Mike
3
非贪婪匹配 .*? 在这种情况下很有帮助。 - Roger Pate
3个回答

17

Evan Fosmark已经给出了一个很好的答案,这只是更多的信息。

你有此行:

pattern = "6 of(.*)fans"

一般来说,这不是一个好的正则表达式。如果输入文本是:
"6 of 99 fans in the whole galaxy of fans"
那么匹配组(括号内的内容)将是:
" 99 fans in the whole galaxy of "
因此,我们需要一个模式,即使像上面那样愚蠢的输入文本,也能抓取你想要的内容。
在这种情况下,匹配空格并不重要,因为当你将字符串转换为整数时,空格会被忽略。但让我们编写一个忽略空格的模式。
使用通配符*,可以匹配长度为零的字符串。在这种情况下,我认为你总是想要一个非空匹配,所以你需要使用+来匹配一个或多个字符。
Python提供了非贪婪匹配,因此你可以用它来重新编写。旧的带有正则表达式的程序可能没有非贪婪匹配,因此我还将提供一个不需要非贪婪匹配的模式。
因此,非贪婪模式:
pattern = "6 of\s+(.+?)\s+fans"

另一个:
pattern = "6 of\s+(\S+)\s+fans"

\s 表示 "任何空格",会匹配空格、制表符和一些其他字符(例如 "换页符")。\S 表示 "任何非空格",会匹配任何 \s 不匹配的内容。

第一个模式比你的第一个模式做得更好,即使输入文本很奇怪:

"6 of 99 fans in the whole galaxy of fans"

它将返回一个匹配组,只包含 99

但试试这个奇怪的输入文本:

"6 of 99 crazed fans"

它将返回一个匹配组,包含 99 crazed

第二个模式将完全不匹配,因为单词 "crazed" 不是单词 "fans"。

嗯。这里有一个最后的模式,即使在奇怪的输入文本中也应该总是正确的:

pattern = "6 of\D*?(\d+)\D*?fans"

\d 匹配任何数字('0''9')。\D 匹配任何非数字字符。

这将成功匹配任何稍微不太模糊的内容:

"6 of 99 fans in the whole galaxy of fans"

匹配组将是 99

"6 of 99 crazed fans"

匹配组将是 99

"6 of 99 41 fans"

它将无法匹配,因为里面有第二个数字。

要了解更多关于 Python 正则表达式的内容,您可以阅读 各种 网页 页面。为了快速提醒,在 Python 解释器中执行:

>>> import re
>>> help(re)

当你从网页中"scraping"文本时,有时可能会遇到HTML代码的问题。一般来说,正则表达式不是忽略HTML或XML标记的好工具(参见此处);最好使用Beautiful Soup解析HTML并提取文本,然后使用正则表达式获取您真正想要的文本。
我希望这很有趣和/或教育性。

14
import urllib
import re

fbhandle = urllib.urlopen('http://www.facebook.com/Microsoft')
pattern = "6 of(.*)fans" #this wild card doesnt appear to work?
compiled = re.compile(pattern)

ms = compiled.search(fbhandle.read())
print ms.group(1).strip()
fbhandle.close()

你需要使用re.search()。使用re.match()会尝试将模式与整个文档匹配,但实际上你只是想匹配文档中的某个部分。上面的代码打印出:79,110。当然,在别人运行它时,这个数字可能会不同。


1
非常感谢 - 运行得很好。虽然我不确定我完全理解区别,但match()将用于在小型字符串上执行某种布尔评估的情况下使用? - oneAday
2
@oneAday:在这里有一个很好的解释,讲述了“match”和“search”的区别:http://www.amk.ca/python/howto/regex/regex.html#SECTION000720000000000000000 - mechanical_meat
评论中的链接无法使用,我想知道搜索和匹配之间有何区别。 - Timo

0
不需要使用正则表达式。
import urllib
fbhandle = urllib.urlopen('http://www.facebook.com/Microsoft')
for line in fbhandle.readlines():
    line=line.rstrip().split("</span>")
    for item in line:
        if ">Fans<" in item:
            rind=item.rindex("<span>")
            print "-->",item[rind:].split()[2]

输出

$ ./python.py
--> 79,133

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接