Python 如何将其包装为递归调用
我正在用python写一只小蜘蛛。它点击一个页面,根据一个模式获取页面上的所有链接,转到每个页面,然后重复 我需要以某种方式使它递归。以下是url模式:Python 如何将其包装为递归调用,python,Python,我正在用python写一只小蜘蛛。它点击一个页面,根据一个模式获取页面上的所有链接,转到每个页面,然后重复 我需要以某种方式使它递归。以下是url模式: www.example.com 然后我得到基于正则表达式的所有链接,然后我访问每个页面 递归部分: 假设我正在访问一个url如下的页面: www.example.com/category/1 www.example.com/category/1_234_4232 现在,如果此页面包含以下链接: www.example.com/catego
www.example.com
然后我得到基于正则表达式的所有链接,然后我访问每个页面
递归部分:
假设我正在访问一个url如下的页面:
www.example.com/category/1
www.example.com/category/1_234_4232
现在,如果此页面包含以下链接:
www.example.com/category/1_234
(基本上相同的url,只是它有一个额外的“_234234”)
我访问该页面,然后检查url,如:
www.example.com/category/1
www.example.com/category/1_234_4232
(同样,相同的url加上下划线和数字)
我一直这样做,直到没有更多的链接适合这个模式
1. visit a category page
2. does it contain links with the same url + "_dddd" if yes, visit that page
3. back to #2 unless no links
我不需要正则表达式,我只需要构造递归调用的帮助。按照您要求的方式,仅仅递归可能不是最好的方法 首先,如果要索引的页面超过1000页,则可能会“从最底层”调用堆栈并崩溃。另一方面,如果在递归过程中不小心释放变量,它可能会消耗相当多的内存 我想推荐一些更像:
visit_next = set(['www.example.com'])
visited = set()
while len(visit_next):
next_link = visit_next.pop()
if next_link not in visited:
visited.add(next_link)
for link in find_all_links_from(next_link):
if link not in visited:
visit_next.add(link)
编辑:
正如我所建议的,我已经用集合重写了这个;这应该使用更少的内存(在长时间的遍历中,几乎可以肯定访问下一个列表会收集许多重复的链接)。按照您要求的方式,仅仅递归可能不是最好的方法 首先,如果要索引的页面超过1000页,则可能会“从最底层”调用堆栈并崩溃。另一方面,如果在递归过程中不小心释放变量,它可能会消耗相当多的内存 我想推荐一些更像:
visit_next = set(['www.example.com'])
visited = set()
while len(visit_next):
next_link = visit_next.pop()
if next_link not in visited:
visited.add(next_link)
for link in find_all_links_from(next_link):
if link not in visited:
visit_next.add(link)
编辑:
正如我所建议的,我已经用集合重写了这个;这应该使用更少的内存(在长时间的遍历中,下一次访问列表几乎肯定会收集到许多重复的链接)。基本上,您会像其他人一样进行此操作(有缺陷): 然而(正如也指出的那样),你必须跟踪你已经访问过的网站。一种简单(但有点有效)的方法是存储它们(可能是在“规范化”它们之后,以捕获写得不同的几乎相同的链接-例如,strip
/.*$/
)。例如:
visited = set()
def visit(url):
content = get_content(url)
links = extract_and_normalize_links(content)
for link in links:
if link not in visited:
visited.add(link)
visit(link)
堆栈溢出可能会成为一个问题,这取决于有多少链接(另一方面,如果达到1000次调用,脚本将运行很长时间)。如果您确实有那么多间接操作,那么应该删除递归,如另一个答案所示。或者使用堆栈(一个列表),如果您希望按照递归的顺序进行刮取:
while link_stack:
current_page = link_stack.pop()
# get links
link_stack.extend(links_from_current_page)
基本上,你会像其他人那样做(有缺陷): 然而(正如也指出的那样),你必须跟踪你已经访问过的网站。一种简单(但有点有效)的方法是存储它们(可能是在“规范化”它们之后,以捕获写得不同的几乎相同的链接-例如,strip
/.*$/
)。例如:
visited = set()
def visit(url):
content = get_content(url)
links = extract_and_normalize_links(content)
for link in links:
if link not in visited:
visited.add(link)
visit(link)
堆栈溢出可能会成为一个问题,这取决于有多少链接(另一方面,如果达到1000次调用,脚本将运行很长时间)。如果您确实有那么多间接操作,那么应该删除递归,如另一个答案所示。或者使用堆栈(一个列表),如果您希望按照递归的顺序进行刮取:
while link_stack:
current_page = link_stack.pop()
# get links
link_stack.extend(links_from_current_page)
已访问
可以是一个简单存在的集合,表示链接已被访问。最后一行中的列表visit_next
需要append
,而不是add
。递归与线程一样,在适合作业的时候使用非常好,但并不总是适合作业的工具。这是一个很好的解决方案。@eumiro是对的,您应该使用一个集合,而不是带有虚假值的dict。如果你打算使用visit_next
作为堆栈,请弹出最后一个元素,而不是第一个元素(简单的.pop
,这是默认值)。@delnan:我认为它更像是一个队列;无论如何,集合可能是一个更好的解决方案(自动处理多次插入的值)。如果集合是重复的,则不会插入?已访问的
可能是一个简单存在的集合,表示链接已访问。最后一行中的列表visit_next
需要append
,而不是add
。递归与线程一样,在适合作业的时候使用非常好,但并不总是适合作业的工具。这是一个很好的解决方案。@eumiro是对的,您应该使用一个集合,而不是带有虚假值的dict。如果你打算使用visit_next
作为堆栈,请弹出最后一个元素,而不是第一个元素(简单的.pop
,这是默认值)。@delnan:我认为它更像是一个队列;无论如何,集合可能是更好的解决方案(自动处理多重插入值)。如果集合是重复的,它不会插入?