Python爬虫遇403 Forbidden错误的绕过方案及脚本优化求助
Python爬虫遇403 Forbidden错误的绕过方案及脚本优化求助
看起来你在爬取目标网站时碰到了挺头疼的403权限限制问题,而且即便用cfscrape能拿到首页内容,也存在深层页面无法访问、图片模糊的情况,我来分享一些实用的解决思路和脚本优化方向:
一、绕过403 Forbidden的常见方案
1. 补全更真实的请求头
你之前试过调整headers,但可能没覆盖足够多的关键字段。网站通常会通过请求头识别是否为真实浏览器访问,建议你照搬Chrome/Firefox等主流浏览器的完整请求头,至少包含这些核心字段:
User-Agent:用最新的浏览器UA字符串,比如Chrome的Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8Accept-Language:根据目标网站地区设置,比如en-US,en;q=0.5Referer:如果是从某个页面跳转过来的,设置对应页面的URLCookie:可以手动访问网站,从浏览器开发者工具的Network面板里复制真实Cookie
把这些headers加到你的请求里,示例:
headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8", "Accept-Language": "en-US,en;q=0.5", "Referer": "https://目标网站域名/" } response = scraper.get("website_url", headers=headers)
2. 会话保持与Cookie处理
很多网站会通过Cookie验证用户会话,cfscrape虽然能绕过Cloudflare,但如果网站还有额外的Cookie验证,你可以:
- 先用浏览器手动访问网站,获取有效Cookie,然后加到scraper的会话中
- 或者用Selenium/Playwright模拟浏览器打开页面,获取Cookie后传给cfscrape的scraper对象,实现会话复用
3. 高匿代理的合理使用
如果单纯改headers没用,试试高匿代理(避免用透明代理,容易被识别),注意代理的IP地区尽量和目标网站的受众地区一致。在cfscrape中配置代理的方式:
proxies = { "http": "http://username:password@proxy_ip:port", "https": "https://username:password@proxy_ip:port" } scraper.proxies = proxies
4. 控制请求频率
频繁的请求很容易触发反爬机制,建议在每次请求之间加入随机延迟,模拟人类访问节奏:
import time import random # 在请求页面或图片后添加 time.sleep(random.uniform(1, 3)) # 随机延迟1-3秒
二、你的Python脚本优化建议
1. 解决深层页面无法访问的问题
当前脚本只爬取了首页,要获取深层页面,需要遍历页面内的链接并递归/循环爬取:
- 提取页面中所有
<a>标签的href属性 - 过滤掉非目标域名的链接、重复链接
- 逐个请求这些链接,重复解析、保存的流程
示例代码片段:
from urllib.parse import urljoin, urlparse visited_urls = set() # 记录已爬取的URL,避免重复 def crawl_page(url): if url in visited_urls: return visited_urls.add(url) response = scraper.get(url, headers=headers) soup = BeautifulSoup(response.content, 'lxml') # 保存当前页面 page_filename = urlparse(url).path.split('/')[-1] or 'index.html' with open(page_filename, 'w') as f: f.write(str(soup)) # 爬取当前页面的图片(复用你原来的图片处理逻辑) # ... # 提取并爬取深层链接 for a_tag in soup.findAll('a', href=True): link = urljoin(url, a_tag['href']) # 只爬取目标域名下的链接 if urlparse(link).netloc == urlparse("website_url").netloc: crawl_page(link) time.sleep(random.uniform(1, 2)) # 启动爬取 crawl_page("website_url")
2. 解决图片模糊的问题
图片模糊大概率是因为你获取的是缩略图地址,很多网站会把原图地址放在data-src、data-original、srcset这类属性里,而不是src。修改你的图片处理逻辑:
for img in soup.findAll('img'): # 优先尝试获取原图地址,按优先级检查属性 img_url = None if img.get('data-src'): img_url = img['data-src'] elif img.get('data-original'): img_url = img['data-original'] elif img.get('srcset'): # srcset通常包含多个分辨率的地址,取最后一个(最高清) img_url = img['srcset'].split(',')[-1].strip().split(' ')[0] else: img_url = img.get('src') if img_url: # 处理相对路径,拼接成绝对URL if not img_url.startswith('http'): img_url = urljoin("website_url", img_url) name = img_url.split('/')[-1] name = urllib.parse.unquote(name) # 请求图片时加上Referer头,避免防盗链拦截 img_response = scraper.get(img_url, headers={**headers, "Referer": url}) with open(name, "wb") as file: file.write(img_response.content) time.sleep(random.uniform(0.5, 1.5))
如果这样还是拿到模糊图,可能网站需要登录才能获取原图,或者有更严格的防盗链机制,这时候可以考虑用Selenium直接模拟浏览器截图或者获取图片的真实地址。
额外提醒
爬取网站前一定要查看目标网站的robots.txt文件和使用条款,确保你的爬取行为符合规定,避免法律风险。
备注:内容来源于stack exchange,提问作者Bruno Barros




