在Python中使用re.findall()进行Web爬网

时间:2014-04-18 14:21:19

标签: python regex web-crawler findall

我正在尝试通过编写一个非常简单的网络爬虫来教自己。

它的代码在这里:

#!/usr/bin/python

import sys, getopt, time, urllib, re

LINK_INDEX = 1
links = [sys.argv[len(sys.argv) - 1]]
visited = []
politeness = 10
maxpages = 20

def print_usage():
    print "USAGE:\n./crawl [-politeness <seconds>] [-maxpages <pages>] seed_url"

def parse_args():
    #code for parsing arguments (works fine so didnt need to be included here)

def crawl():
    global links, visited
    url = links.pop()    
    visited.append(url)

    print "\ncurrent url: %s" % url

    response = urllib.urlopen(url)
    html = response.read()

    html = html.lower()

    raw_links = re.findall(r'<a href="[\w\.-]+"', html)

    print "found: %d" % len(raw_links)

    for raw_link in raw_links:
        temp = raw_link.split('"')
        if temp[LINK_INDEX] not in visited and temp[LINK_INDEX] not in links:
            links.append(temp[LINK_INDEX])

    print "\nunvisited:"
    for link in links:
        print link

    print "\nvisited:"
    for link in visited:
        print link

parse_args()

while len(visited) < maxpages and len(links) > 0:
    crawl()
    time.sleep(politeness)

print "politeness = %d, maxpages = %d" % (politeness, maxpages)

我在大约10页的同一个工作目录中创建了一个小型测试网络,它们以各种方式链接在一起,它似乎工作正常,但是当我将它自己发送到实际的互联网上时,它无法从它获取的文件中解析链接。

它能够很好地获取html代码,因为我可以打印出来,但似乎re.findall()部分没有按预期执行,因为链接列表永远不会被填充。我可能写错了我的正则表达式吗?它可以很好地找到像<a href="test02.html"这样的字符串,然后从中解析链接,但由于某种原因,它不适用于实际的网页。可能是http部分可能会把它扔掉?

我以前从未使用过Python的正则表达式,所以我很确定这就是问题所在。任何人都可以告诉我如何更好地表达我寻找的模式?谢谢!

3 个答案:

答案 0 :(得分:1)

您的正则表达式与href属性的所有有效值都不匹配,例如带斜杠的路径,等等。使用[^"]+(与结束双引号不同)而不是[\w\.-]+会有所帮助,但这并不重要,因为...... you should not parse HTML with regexps开头。

列夫已经提到过BeautifulSoup,你也可以看一下lxml。你可以写的任何手工制作的正则表达式都会更好。

答案 1 :(得分:1)

你可能想要这个:

raw_links = re.findall(r'<a href="(.+?)"', html)

使用括号表示您想要返回的内容,否则您将获得包括<a href=...位在内的整个匹配项。现在你得到一切,直到结束引号,因为使用了非贪婪的+?操作

更具辨别力的过滤器可能是:

raw_links = re.findall(r'<a href="([^">]+?)"', html)

这匹配除了引号和终止括号之外的任何内容。

这些简单的RE将与已注释的URL匹配,javascript中的URL类文字字符串等。所以请小心使用结果!

答案 2 :(得分:1)

问题 与你的正则表达式。我可以用很多方法编写一个有效的HTML锚点,你的正则表达式不会匹配。例如,可能存在额外的空格或换行符,并且还有其他可能存在的属性,您尚未将其考虑在内。此外,你不考虑不同的情况。例如:

<a  href="foo">foo</a>

<A HREF="foo">foo</a>

<a class="bar" href="foo">foo</a>

这些都不会与你的正则表达式匹配。

你可能想要更像这样的东西:

<a[^>]*href="(.*?)"

这将匹配锚标记start,后跟除&gt;之外的任何字符。 (这样我们仍然可以在标签内匹配)。这可能是classid属性。然后,在捕获组中捕获href属性的值,您可以通过

提取该值
match.group(1)

href值的匹配也非贪婪。这意味着它将匹配可能的最小匹配。这是因为如果你在同一行上有其他标签,那么你将超出你想要的范围。

最后,您需要以不区分大小写的方式添加re.I标志以进行匹配。