网页爬虫中while True try except循环输出不稳定,迭代时元素重复或遗漏
代码问题排查与修复方案
核心问题点
- 重试逻辑设计错误:你将整个最终层链接的for循环包裹在
try代码块内,当任意一个链接请求触发异常时,会终止当前for循环,回到while True入口重新遍历each_bill全量列表。例如前20个链接请求成功、第21个触发异常时,x已经计数到20,重试后for循环会再次从第1个链接开始遍历,再次写入前20条的结果,等x累加到q时直接跳出循环,剩下的q-20个链接完全没有被处理,这就是你遇到重复+遗漏的根因。 - 变量命名冲突:外层遍历AllGPs的循环变量名为
each,内层遍历最终链接的循环变量也命名为each,极端情况下会出现变量覆盖的异常问题。 - 异常捕获粒度过粗:全链路捕获请求异常没有区分具体出错的链接,也没有设置单链接最大重试次数,可能出现单链接一直失败导致程序死循环的情况。
- 资源写入没有即时flush:批量写入csv时如果程序异常终止,可能丢失已经爬取的结果。
修复方案
将重试逻辑从全量遍历级别下沉到单链接请求级别,只针对出错的单个链接做重试,不需要每次重新遍历所有已处理的链接,修正后的核心代码片段如下:
# 前面的代码保持不变,从最终层链接遍历开始修改 gp=0 # 单链接最大重试次数,避免死循环 MAX_RETRY = 3 for gp_url in AllGPs: # 修改变量名避免冲突 res=requests.get(gp_url) soup=bs(res.text,'html.parser') urls=[] for link in soup.find_all('a'): urls.append(link.get('href')) inte=urls[1:-1] each_bill=[base_url+e[6:] for e in inte] q=len(each_bill) print("no of bills is: ",q) gp+=1 for idx, bill_url in enumerate(each_bill): # 用下标记录处理进度 # 单链接单独重试 retry_cnt = 0 success = False while retry_cnt < MAX_RETRY: try: r=requests.get(bill_url, timeout=30) # 加超时避免无限等待 r.raise_for_status() # 主动抛出4xx/5xx异常 y=r.text.count('Display Board') print(y) soup=bs(r.text,'html.parser') table_soup=soup.findAll('table') trow=[] for tr in table_soup[3]: trow.append(tr) text=trow[1].text b=text[13:] print(b) writer.writerow((y,b)) d.flush() # 即时写入磁盘避免数据丢失 print("Now Wyd ",idx+1,"th bill in",gp," th GP") success = True break except requests.exceptions.RequestException as e: print(f"bill {idx+1} 第{retry_cnt+1}次请求失败: ",e) retry_cnt +=1 time.sleep(5) if not success: # 超过重试次数可以记录失败链接,按需处理 print(f"bill {idx+1} 超过最大重试次数,跳过: {bill_url}") d.close()
额外优化建议
- 所有请求都统一添加超时参数,避免因服务器无响应导致程序长时间卡死
- 可以先把所有层级的链接全部收集完成存储到本地,再统一做最终页的爬取,避免前面层级的请求重复执行
- 增加请求头模拟浏览器行为,降低被网站反爬拦截的概率
内容的提问来源于stack exchange,提问作者adc admin
相关产品推荐
相关产品推荐

