aiohttp请求URL报403 Forbidden但浏览器可正常访问如何解决
问题原因
返回403 Forbidden是站点反爬机制拦截请求导致的:
aiohttp默认发起请求时携带的User-Agent字段带有明显的爬虫标识(格式为Python/<版本号> aiohttp/<版本号>),站点识别到请求不是来自普通用户浏览器,就会直接拒绝响应。浏览器访问时会携带合规的普通用户请求标识,不会触发拦截规则,所以可以正常打开。
解决方法
核心是修改请求头,模拟真实浏览器的请求特征,修改后的可运行代码如下:
from datetime import datetime from urllib.parse import urlparse from pathlib import Path import asyncio import aiohttp import os async def fetch_url(url, save_to_file=False): timeout = aiohttp.ClientTimeout(total=30) # 模拟Chrome浏览器的常规请求头 headers = { "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8", "Connection": "keep-alive" } # 把headers传入ClientSession,所有该会话的请求都会自动携带这些头 async with aiohttp.ClientSession(timeout=timeout, headers=headers, trust_env=True) as session: async with session.get(url, raise_for_status=True) as response: text = await response.text() if save_to_file: current_timestamp = datetime.now().strftime('%m_%d_%Y_%H_%M_%S') name_part = urlparse(url).netloc file_name = Path(os.path.join(os.getcwd(), 'feeds', name_part + '_' + current_timestamp + '.rss')) file_name.parent.mkdir(exist_ok=True, parents=True) # 补充utf-8编码避免写入乱码 with open(file_name, 'w+', encoding='utf-8') as f: f.write(text) url = 'https://coinfomania.com/feed/' # Jupyter环境可直接用await调用 await fetch_url(url, save_to_file=True) # 普通.py文件运行请注释上面的await,改用下面的调用方式 # asyncio.run(fetch_url(url, save_to_file=True))
补充说明
- 如果后续再次出现403,可以直接打开浏览器的开发者工具,在网络面板里复制任意一个到该站点的请求的User-Agent值替换即可,不要长期使用同一个固定UA。
- 原代码里的
ssl=False参数没有必要,关闭SSL校验反而会带来安全风险,正常HTTPS站点不需要加这个参数,上面的代码已经移除。 - 请求时控制频率,不要短时间内发起大量请求,否则即使UA正常也可能被站点封禁IP。
内容的提问来源于stack exchange,提问作者PirateApp
相关产品推荐
相关产品推荐

