爬虫程序无报错却运行耗时过长,疑似循环问题求排查
爬虫性能优化方案
你的爬虫耗时过长主要集中在DataFrame操作效率低下、串行请求等待、冗余代码这几个方面,以下是具体优化点和修改后的代码:
核心问题分析与优化
- 频繁调用
DataFrame.append()是性能杀手:每次append都会生成新的DataFrame对象,循环中多次执行会产生大量内存拷贝,随着数据量增大,耗时呈指数级上升。建议用列表存储数据字典,最后一次性转换为DataFrame。 html.parser解析速度慢:BeautifulSoup默认的html.parser比lxml解析器慢很多,换成lxml能大幅提升页面解析速度(需先安装lxml库:pip install lxml)。- 冗余的网络请求:代码开头的
requests.get(request_url)和BeautifulSoup解析完全没有被使用,属于无效请求,直接删除。 - 低效的终止判断逻辑:
if '<div class = "noCar">' in str(page_info)这种把DataFrame转成字符串搜索的方式效率极低,应该在页面解析阶段直接判断是否存在无数据的标识元素。 - 串行请求等待时间长:每次请求都要等待响应后才能发起下一次,改用
requests.Session复用TCP连接,能减少握手开销,降低等待时间。
修改后的代码
import requests from bs4 import BeautifulSoup import pandas as pd from requests.adapters import HTTPAdapter # 复用TCP连接,减少握手开销 session = requests.Session() session.mount('http://', HTTPAdapter(max_retries=3)) session.mount('https://', HTTPAdapter(max_retries=3)) headers = { 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36' } def get_info(page_url): try: html = session.get(page_url, headers=headers, timeout=10) html.raise_for_status() # 捕获HTTP错误 soup = BeautifulSoup(html.text, 'lxml') # 改用lxml解析器 # 先判断是否存在无数据标识 if soup.find('div', class_='noCar'): return [] temp = soup.find('div', class_='tslb_b') if not temp: return [] tr_list = temp.find_all('tr') data_list = [] for tr in tr_list: td_list = tr.find_all('td') if len(td_list) == 8: # 确保字段数量正确 data_dict = { 'id': td_list[0].text.strip(), 'brand': td_list[1].text.strip(), 'car_model': td_list[2].text.strip(), 'type': td_list[3].text.strip(), 'desc': td_list[4].text.strip(), 'problem': td_list[5].text.strip(), 'datetime': td_list[6].text.strip(), 'status': td_list[7].text.strip() } data_list.append(data_dict) return data_list except Exception as e: print(f"获取页面{page_url}失败: {str(e)}") return [] request_url = input("请输入目标URL: ") result_data = [] current_page = 1 while True: # 构造分页URL(注意:原代码的[:48]拼接逻辑需根据实际URL确认是否正确) page_url = request_url[:48] + str(current_page) + "d&cb=0&csb=0&cs=0&cm=0&ba=0&qt=0&z=0&zs=0&f=0&nt=0&fu=0&qts=0&wd=%e5%a4%87%e8%83%8e" page_data = get_info(page_url) if not page_data: break result_data.extend(page_data) current_page += 1 if current_page > 100: # 限制最多爬100页 break # 最后一次性转换为DataFrame result = pd.DataFrame(result_data, columns=['id', 'brand', 'car_model', 'type', 'desc', 'problem', 'datetime', 'status']) result.to_csv('result.csv', index=False, encoding='utf-8-sig')
额外优化建议
- 如果爬取页数较多,可引入异步请求库
aiohttp,同时发起多个请求,将总耗时压缩到接近单页请求时间。 - 给请求添加随机延迟(如
time.sleep(random.uniform(0.5, 1.5))),避免触发网站反爬机制,同时减少服务器压力。
内容的提问来源于stack exchange,提问作者Yount Shi
相关产品推荐
相关产品推荐

