You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用request_html爬取天气数据时程序随机终止的原因咨询

问题:使用request_html爬取Weather Underground时程序随机终止

问题描述

我尝试用request_html爬取Weather Underground的天气数据,编写了如下代码,但运行时程序会随机终止——有时在获取2016-1-20的数据后停止,有时在2016-3-20时停止。不清楚是否是r.html.render中的timeout或sleep参数导致的问题?

session = HTMLSession()
flag = 0
leap_year =[2016,2020]
month_30 = [4,6,9,11]
for year in range(2015,2020):
    date =[]
    times = []
    temp = []
    dew = []
    hum =[]
    wind=[]
    wind_s =[]
    wind_g =[]
    press = []
    precip = []
    cond = []
    for month in range(1,13):
        for day in range(1,32):
            if(year in leap_year):
                if(month == 2 and day >29):
                    break
            else:
                if (month == 2 and day >28):
                    break
            if(month in month_30 and day >30):
                break
            d = "{}-{}-{}".format(year,month,day)
            start2 = time.time()
            url = "https://www.wunderground.com/history/daily/ca/richmond/CYVR/date/{}".format(d)
            r = session.get(url)
            r.html.render(sleep =5)
            soup = BeautifulSoup(r.html.html,'html.parser')
            table = soup.find("tbody",{'role':'rowgroup'})
            row = table.find_all('tr')
            for r in row :
                n = 0
                date.append(d)
                for cell in r.find_all('td'):
                    if(n == 0):
                        times.append(cell.text)
                    elif(n == 1):
                        temp.append(cell.text)
                    elif(n == 2):
                        dew.append(cell.text)
                    elif(n == 3):
                        hum.append(cell.text)
                    elif(n == 4):
                        wind.append(cell.text)
                    elif(n == 5):
                        wind_s.append(cell.text)
                    elif(n == 6):
                        wind_g.append(cell.text)
                    elif(n == 7):
                        press.append(cell.text)
                    elif(n == 8):
                        precip.append(cell.text)
                    elif(n == 9):
                        cond.append(cell.text)
                    n+=1
            end2 = time.time()
            print("it took : {} for one day ".format(end2-start2))
            print(d)
end = time.time()
print(end-start)

可能的原因分析

程序随机终止大概率不是单纯的sleep参数问题,而是以下几个因素共同导致的:

  1. 缺少异常处理机制
    你的代码没有任何错误捕获:如果某天的请求失败(比如网络波动)、页面结构变化(找不到<tbody role="rowgroup">),或者渲染过程中Chrome进程崩溃,程序会直接抛出AttributeError、ConnectionError等异常并终止运行。这是最常见的终止原因。

  2. render参数配置不足
    r.html.render()默认的timeout是30秒,但如果页面加载缓慢(比如反爬机制导致加载延迟),可能会超时;另外,频繁渲染页面可能导致Chrome子进程崩溃,没有设置重启机制的话,后续渲染会直接失败。

  3. 反爬机制触发
    Weather Underground会检测频繁的自动化请求,当你的请求频率过高时,可能会返回空白页面、验证码页面或者直接拒绝连接,导致后续解析失败触发异常。


解决方案

针对这些问题,我给你调整了代码,加入了关键改进:

from requests_html import HTMLSession
from bs4 import BeautifulSoup
import time
import random

session = HTMLSession()
leap_year = [2016, 2020]
month_30 = [4, 6, 9, 11]
# 初始化所有数据列表在循环外,避免每次年份重置(如果需要按年份拆分可以调整)
all_data = {
    "date": [],
    "times": [],
    "temp": [],
    "dew": [],
    "hum": [],
    "wind": [],
    "wind_s": [],
    "wind_g": [],
    "press": [],
    "precip": [],
    "cond": []
}

start = time.time()

for year in range(2015, 2020):
    for month in range(1, 13):
        for day in range(1, 32):
            # 日期合法性判断
            if year in leap_year:
                if month == 2 and day > 29:
                    break
            else:
                if month == 2 and day > 28:
                    break
            if month in month_30 and day > 30:
                break
            
            d = f"{year}-{month}-{day}"
            url = f"https://www.wunderground.com/history/daily/ca/richmond/CYVR/date/{d}"
            start2 = time.time()
            
            try:
                # 发送请求,设置超时并检查状态码
                r = session.get(url, timeout=15)
                r.raise_for_status()  # 触发HTTP错误(如403/500)
                
                # 渲染页面:增加超时时间,添加--no-sandbox避免进程崩溃,用随机sleep降低反爬风险
                r.html.render(
                    sleep=random.uniform(4, 6), 
                    timeout=40, 
                    options={"args": ["--no-sandbox", "--disable-dev-shm-usage"]}
                )
                
                # 解析页面
                soup = BeautifulSoup(r.html.html, 'html.parser')
                table = soup.find("tbody", {'role': 'rowgroup'})
                
                if not table:
                    print(f"警告:日期{d}未找到目标表格,跳过")
                    continue
                
                rows = table.find_all('tr')
                for row in rows:
                    cells = row.find_all('td')
                    if len(cells) < 10:
                        print(f"警告:日期{d}的行数据不完整,跳过该行")
                        continue
                    
                    all_data["date"].append(d)
                    all_data["times"].append(cells[0].text.strip())
                    all_data["temp"].append(cells[1].text.strip())
                    all_data["dew"].append(cells[2].text.strip())
                    all_data["hum"].append(cells[3].text.strip())
                    all_data["wind"].append(cells[4].text.strip())
                    all_data["wind_s"].append(cells[5].text.strip())
                    all_data["wind_g"].append(cells[6].text.strip())
                    all_data["press"].append(cells[7].text.strip())
                    all_data["precip"].append(cells[8].text.strip())
                    all_data["cond"].append(cells[9].text.strip())
                
                end2 = time.time()
                print(f"完成日期{d},耗时: {end2-start2:.2f}秒")
                
                # 增加随机延迟,避免被反爬识别
                time.sleep(random.uniform(2, 4))
                
            except Exception as e:
                print(f"日期{d}处理失败,错误信息: {str(e)}")
                # 出错后延长延迟,降低被拉黑风险
                time.sleep(random.uniform(5, 8))
                continue

end = time.time()
print(f"总耗时: {end-start:.2f}秒")

关键改进点说明

  • 全流程异常捕获:用try-except包裹请求、渲染、解析的核心逻辑,出错时仅打印信息并继续执行,不会终止整个程序。
  • 优化渲染配置:延长timeout到40秒,添加--no-sandbox和--disable-dev-shm-usage参数避免Chrome进程崩溃(尤其在Linux服务器环境),同时用随机sleep代替固定值,更难被反爬检测。
  • 请求合法性校验:用r.raise_for_status()提前捕获HTTP错误状态码,避免无效页面进入解析环节。
  • 数据完整性检查:验证表格和行数据是否存在,避免因页面结构变化导致的AttributeError。
  • 动态延迟策略:正常请求后用短随机延迟,出错后用长延迟,降低被反爬机制拉黑的概率。

内容的提问来源于stack exchange,提问作者Lucian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 11:32:40