Python requests+bs4爬取Reddit数据偶发无返回无报错问题
问题核心原因
- 反爬机制拦截是90%问题的根源:你当前的请求没有携带任何自定义请求头,使用的是requests库默认的
python-requests/版本号标识,Reddit的WAF会直接把这类特征的请求归类为脚本流量,大概率返回空壳拦截页而非正常搜索结果页。这也是为什么会出现“5次请求只有1次成功”的偶发现象:当你的请求刚好没触发短时间高频访问的风控阈值时,才会被放行拿到正常页面,其余时候都会被拦。
- 无报错无输出的核心逻辑漏洞:Reddit返回拦截页时同样会给出200的HTTP状态码,requests只会在网络错误、超时、4xx/5xx状态码时抛出异常,这种“响应合法但内容不对”的场景本身不会触发任何报错;你拿到拦截页的HTML后,用
find_all去找带data-click-id:body属性的标签,自然会拿到空列表,循环跑完没有任何打印,程序就直接结束了。 - 附带的代码逻辑问题:你代码里漏导入了
BeautifulSoup库,还设置了timeout=None无超时限制,遇到被限流挂起的场景会直接卡死,不会主动抛出异常。
可直接落地的修复方案
- 替换默认请求头:把requests自带的python标识换成普通桌面/移动端浏览器的User-Agent,补全基础的
Accept-Language、Accept请求头,让请求的特征和普通用户的浏览器访问保持一致。 - 加前置内容校验:每次拿到响应后,先判断状态码是否为200,再检查返回文本里是否包含目标页特有的字段,确认拿到的是正常内容后再做解析,不要无差别把所有响应都拿去解析。
- 控制请求频率:每次请求之间加2-4秒的随机等待间隔,不要用固定间隔发规律请求,树莓派本身网络链路长,慢一点的访问节奏反而更不容易触发风控。
- 放弃硬解析HTML的方案:直接在原来的请求URL后面加
.json后缀,调用Reddit公开的结构化接口,不需要解析前端元素,既降低树莓派的性能消耗,也不会因为Reddit前端改元素属性导致抓取失效。
适配树莓派运行的极简代码示例:
import requests from time import sleep import random # 模拟树莓派端常用的浏览器请求特征 headers = { "User-Agent": "Mozilla/5.0 (X11; Linux armv7l) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", "Accept-Language": "en-US,en;q=0.9" } target_url = "https://www.reddit.com/r/hardwareswap/search?q=Vive&restrict_sr=1.json" # 随机间隔2-4秒,避免规律性请求被识别 sleep(random.uniform(2, 4)) r = requests.get(target_url, headers=headers, timeout=10) if r.status_code != 200: print(f"请求被拦截,返回状态码:{r.status_code}") else: post_list = r.json()["data"]["children"] for post in post_list: title = post["data"]["title"] full_link = "https://reddit.com" + post["data"]["permalink"] print(title) print(full_link)
注意点:纯requests+JSON接口的方案资源占用极低,树莓派哪怕是Zero系列都能流畅跑,不需要额外装Chrome这类重型浏览器;只要控制好请求频率,不会触发IP封禁。
内容的提问来源于stack exchange,提问作者fleegz2007
相关产品推荐
相关产品推荐

