为何Python爬虫递归重试需用return fetch_data(link)而非直接调用?
return fetch_data(link)而非直接调用? 先给你点个赞,能自己调试找到解决方法已经超棒了!咱们来唠唠你这个核心疑问——为啥这里必须用return fetch_data(link),不能直接调用函数就行?
先快速回顾下你的场景:你需要遍历多个链接,每个链接如果提取的指定title为空,就重试4次,失败就切换到下一个链接。最后你通过两处修改搞定了问题:一是把直接调用改成带return的递归,二是在if语句内、while循环外重置counter。
先贴出你修正后的完整代码:
import time import requests from bs4 import BeautifulSoup links = [ "https://stackoverflow.com/questions/tagged/web-scraping?sort=newest&page=2", "https://stackoverflow.com/questions/tagged/web-scraping?sort=newest&page=3", "https://stackoverflow.com/questions/tagged/web-scraping?sort=newest&page=4" ] counter = 0 def fetch_data(link): global counter res = requests.get(link) soup = BeautifulSoup(res.text,"lxml") try: title = soup.select_one("p.tcode").text except AttributeError: title = "" if not title: while counter<=3: time.sleep(1) print("trying {} times".format(counter)) counter += 1 return fetch_data(link) #First fix counter=0 #Second fix print("tried with this link:",link) if __name__ == '__main__': for link in links: fetch_data(link)
现在拆解核心问题:直接调用fetch_data(link)和用return fetch_data(link)到底差在哪?
1. 直接调用会让函数执行流程彻底混乱
如果把return fetch_data(link)改成fetch_data(link),会发生什么?
假设第一次调用fetch_data(link)发现title为空,进入if块和while循环,打印trying 0 times,counter变成1,然后直接调用fetch_data(link)——这时候确实会发起新的递归调用,但原来的函数实例根本没终止!
当新的递归调用完成(不管重试成功还是失败),程序会回到原来的函数实例,继续执行while循环的下一次迭代(因为counter已经是1,依然满足<=3),这会导致:
- 重试次数远远超过4次,甚至陷入无限递归
- 同一个链接会被多次打印
tried with this link - 全局的
counter会被多个函数实例互相干扰,重置逻辑完全失效
简单说,直接调用就像你开了一个新窗口干活,但原来的窗口还在继续跑流程,整个逻辑直接乱套。
2. return fetch_data(link)会终止当前函数,把执行权完全交给递归调用
用return的话,当你发起递归调用时,当前的函数实例会立即停止执行,不会继续跑后面的while循环迭代和print语句。每次重试都是一个全新的函数实例,从res = requests.get(link)开始重新执行,这样:
- 每次重试都是独立的检查流程,不会有残留的执行逻辑干扰
- 当重试到第4次后,
counter会被重置为0,当前函数实例正常结束,回到for循环处理下一个链接 - 最终输出会严格按照你预期的那样,每个链接重试4次后只打印一次
tried with this link
举个直观的例子:第一次重试(counter=0)没拿到title,return fetch_data(link)会让当前函数“退场”,进入新的fetch_data(link)调用;新调用再次检查title,为空就继续重试,直到counter到3,重置后函数结束,顺利切换到下一个链接。
总结
递归调用时,return的核心作用是终止当前函数的执行,并把递归调用的流程完全接管过来。如果不用return,当前函数会继续执行后续代码,导致重试次数失控、流程混乱,根本达不到你想要的“重试4次就换下一个链接”的效果。
内容的提问来源于stack exchange,提问作者robots.txt

