如何优化我的Web Scraping程序以提升运行效率?
爬虫性能优化方案
你的爬虫扫描43篇文章耗时26秒,核心瓶颈集中在串行网络请求、重复数据库IO和冗余的邮件连接操作上,以下是针对性的优化方案:
1. 并行处理网络请求
当前串行请求每篇文章的方式,会把大量时间浪费在等待网络响应上。改用多线程并行请求,能大幅压缩总耗时(网络IO场景下,多线程比多进程更高效):
from concurrent.futures import ThreadPoolExecutor def fetch_article(url): headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36' } try: response = requests.get(url, headers=headers, timeout=10) response.raise_for_status() return url, response.text except Exception as e: print(f"请求失败 {url}: {e}") return url, None # 并行请求所有文章,max_workers根据网站限制调整,建议5-10 with ThreadPoolExecutor(max_workers=8) as executor: results = executor.map(fetch_article, articles) # 批量处理返回结果 for url, html in results: if not html: continue Asoup = BeautifulSoup(html, 'lxml') # 后续解析逻辑...
2. 数据库操作优化
2.1 给URL字段添加索引
当前查询SELECT * FROM artikler WHERE url=?是全表扫描,给URL加索引能让查询速度提升数倍:
# 建表时同步加索引,若表已存在单独执行这条 try: c.execute("CREATE TABLE artikler (tittel text, dato text, url text, UNIQUE(url))") c.execute("CREATE INDEX IF NOT EXISTS idx_url ON artikler(url)") except: pass
2.2 减少数据库交互次数
- 预先查询所有已爬取的URL存入集合,避免循环中反复查库;
- 积累多条插入数据后批量提交,减少
commit()的IO开销:
# 预先获取所有已存在的URL c.execute("SELECT url FROM artikler") existing_urls = {row[0] for row in c.fetchall()} insert_data = [] # 循环中判断并积累数据 if url not in existing_urls and relevant: insert_data.append((title, date, url)) # 批量插入 if insert_data: c.executemany("INSERT INTO artikler VALUES (?, ?, ?)", insert_data) conn.commit()
3. 关键词匹配逻辑优化
原代码的循环逻辑存在错误(只要遇到不匹配的关键词就会覆盖relevant为False),同时可以用更高效的方式判断匹配:
# 转成集合加速in操作,合并标题和内容一次检查 keywords_set = set(keywords) text_to_check = title + " " + caption # 只要有一个关键词匹配就标记为相关 relevant = any(word in text_to_check for word in keywords_set) # 若关键词包含特殊字符,用正则一次匹配更可靠 import re pattern = re.compile('|'.join(re.escape(word) for word in keywords)) relevant = pattern.search(text_to_check) is not None
4. 复用SMTP连接
当前每次发邮件都重新建立SMTP连接,连接建立的开销远大于发送本身,改为只建立一次连接:
# 在所有循环外建立连接 with smtplib.SMTP_SSL('smtp.gmail.com', 465) as smtp: smtp.login("your_email@gmail.com", "your_app_password") # Gmail需用应用专用密码 # 循环处理文章,需要发邮件时直接复用连接 if url not in existing_urls and relevant: # ... 数据库插入逻辑 ... smtp.send_message(msg)
5. 其他辅助优化
- 页面缓存:用
requests-cache缓存已爬取页面,避免重复请求相同内容:import requests_cache requests_cache.install_cache('news_cache', expire_after=3600) # 缓存1小时 - 缩小解析范围:解析时只提取需要的HTML片段,减少BeautifulSoup的处理量:
# 比如只解析header部分 header_html = Asoup.find('header', class_='entry-header') if header_html: # 从header_html中提取标题等内容
内容的提问来源于stack exchange,提问作者PlainB4
相关产品推荐
相关产品推荐

