
很多开发小伙伴都遇到过这种崩溃的场景:明明写好了Playwright自动化爬虫,指纹伪装、延时等待全都加了,刚开始还能正常爬取,跑十几条数据就突然限流、403拦截、页面空白,严重时直接IP永久封禁。
排查半天会发现,问题根本不是代码逻辑 bug,核心瓶颈在于:常规爬虫固定IP极易被网站风控标记、网段批量封禁,一旦触发规则就直接限流拦截。
更头疼的是,现在绝大多数网站都搭载了JS动态反爬体系,不仅检测IP风险,还会校验浏览器指纹、用户浏览行为、JS环境完整性,单纯换IP、加延时,已经完全无法躲过进阶风控检测。
读完这篇教程,你将彻底解决以上所有问题:无需手动管理IP池、全自动轮换纯净住宅IP、完美模拟真人浏览行为、抹平所有爬虫专属JS指纹,稳定绕过99%网页JS反爬与行为风控,实现长期、高频、稳定的自动化爬取任务。
本次方案直接采用住宅隧道代理架构,实现零运维全自动IP轮换。全程自动切换高纯净住宅IP、无需人工干预、无需校验IP有效性,每一轮访问都会自动分配全新外网IP,从根源降低IP封禁概率,风控容错率直接拉满。
搭配Playwright无痕浏览器环境、全套真人随机行为模拟、JS指纹深度伪装三大核心能力,全方位规避IP风控、设备指纹锁定、人机行为检测、JS环境识别四大反爬维度,完美适配电商、资讯、短视频、搜索引擎等高反爬、高频爬取场景,稳定性远超常规爬虫方案。
核心优势:真实家庭住宅IP池、全自动轮询换IP、连接稳定不掉线、零IP运维成本、开箱即用。
环境配置简单无门槛,全平台兼容Windows、Mac、Linux,直接执行命令安装即可:
# 安装playwright核心依赖
pip install playwright
# 自动下载适配你系统的浏览器内核
playwright install开通高纯净住宅隧道代理,获取专属隧道地址、账号密码即可使用,无需批量提取IP、无需手动轮换、无需检测有效性。
隧道通用标准格式:http://用户名:密码@隧道地址:端口
隧道服务端会全自动分配全新真实住宅IP,全程无需人工干预,彻底告别IP池运维难题。
代码深度适配住宅隧道代理机制,集成全套真人行为仿真、JS指纹修复、失败自动重试、资源自动释放逻辑,仅需替换隧道账号密码即可直接部署运行。
import random
import time
from playwright.sync_api import sync_playwright, Page, BrowserContext
from typing import Optional
# ====================== 【仅需修改这里】隧道代理核心配置 ======================
# 隧道代理账号密码(自行替换为自己的)
TUNNEL_USERNAME = "你的隧道代理用户名"
TUNNEL_PASSWORD = "你的隧道代理密码"
# 隧道代理官方地址端口(根据服务商提供填写:tunnel.zdaye.com:8080)
TUNNEL_SERVER = "tunnel.zdaye.com:8080"
# 目标爬取网址
TARGET_URL = "https://需要反爬的目标网址.com"
# ====================== 通用仿真配置(无需改动) ======================
# 随机浏览器窗口大小(模拟不同设备)
WINDOW_SIZE_LIST = [(1280, 720), (1366, 768), (1440, 900), (1920, 1080)]
# 随机UA池,伪装不同浏览器设备
UA_LIST = [
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
]
# ====================== 工具小函数(真人行为仿真) ======================
def get_random_window_size() -> tuple:
"""随机浏览器分辨率"""
return random.choice(WINDOW_SIZE_LIST)
def human_delay(min_s: float = 0.5, max_s: float = 2.0):
"""真人随机停顿,杜绝机械固定间隔"""
time.sleep(random.uniform(min_s, max_s))
def random_scroll(page: Page):
"""模拟人类随意滚动页面"""
scroll_times = random.randint(2, 6)
for _ in range(scroll_times):
scroll_height = random.randint(200, 800)
page.evaluate(f"window.scrollBy(0, {scroll_height})")
human_delay(0.3, 1.0)
if random.random() > 0.5:
page.evaluate("window.scrollTo(0, 0)")
human_delay(0.5, 1.2)
def human_click(page: Page, selector: str) -> bool:
"""带随机偏移的真人点击,规避定点点击检测"""
element = page.query_selector(selector)
if not element:
return False
box = element.bounding_box()
if not box:
return False
x = box["x"] + random.uniform(5, box["width"] - 5)
y = box["y"] + random.uniform(5, box["height"] - 5)
page.mouse.move(x, y, steps=random.randint(20, 50))
human_delay(0.2, 0.6)
page.mouse.click(x, y)
return True
def inject_anti_crawl_js(page: Page):
"""注入JS抹平爬虫指纹,绕过JS反爬检测"""
anti_js = """
Object.defineProperty(navigator, 'webdriver', {
get: () => undefined
});
delete window.__pwTest__;
delete window.playwright;
Object.defineProperty(navigator, 'plugins', {
get: () => [1, 2, 3, 4, 5]
});
Object.defineProperty(navigator, 'languages', {
get: () => ['zh-CN', 'zh', 'en-US', 'en']
});
"""
page.add_init_script(anti_js)
# ====================== 核心爬虫函数(隧道代理专属) ======================
def crawl_target_url(url: str) -> Optional[dict]:
with sync_playwright() as p:
# 随机设备参数
window_width, window_height = get_random_window_size()
random_ua = random.choice(UA_LIST)
# 组装隧道代理配置
proxy_config = {
"server": f"http://{TUNNEL_SERVER}",
"username": TUNNEL_USERNAME,
"password": TUNNEL_PASSWORD
}
# 浏览器启动,关闭自动化特征
browser = p.chromium.launch(
headless=True,
args=[
"--no-sandbox",
"--disable-blink-features=AutomationControlled",
"--disable-dev-shm-usage",
"--disable-http2", # 规避部分隧道代理兼容问题
f"--window-size={window_width},{window_height}"
],
timeout=30000
)
# 新建独立上下文,每次自动换新IP、清空指纹
context: BrowserContext = browser.new_context(
proxy=proxy_config,
user_agent=random_ua,
viewport={"width": window_width, "height": window_height},
no_cache=True,
locale="zh-CN",
timezone_id="Asia/Shanghai"
)
page: Page = context.new_page()
inject_anti_crawl_js(page)
try:
# 访问目标页面,等待网络稳定
page.goto(url, timeout=60000, wait_until="networkidle")
human_delay(1.5, 3.0)
# 模拟真人浏览行为
random_scroll(page)
human_delay(1.0, 2.0)
# 可自行添加点击、输入等操作
# human_click(page, "按钮选择器")
page_title = page.title()
page_html = page.content()
print(f"✅ 访问成功!当前隧道IP已自动轮换,页面标题:{page_title}")
return {
"title": page_title,
"html": page_html
}
except Exception as e:
print(f"❌ 访问失败:{str(e)},下次自动换新住宅IP重试")
return None
finally:
# 强制释放资源,断开连接,保证下一轮必换IP
page.close()
context.close()
browser.close()
# ====================== 程序入口:自动重试 + 自动换IP ======================
if __name__ == "__main__":
retry_times = 3
for i in range(retry_times):
result = crawl_target_url(TARGET_URL)
if result:
break
human_delay(2.0, 4.0)
print("🎉 隧道代理爬虫任务执行完毕,全程自动换IP无残留")
住宅隧道代理最大的核心优势就是全局全自动轮转IP,无需任何人工操作,只要重新创建浏览器上下文、建立新连接,服务端就会自动分配全新的纯净住宅IP,彻底杜绝固定IP反复访问被风控的问题。
代码内置完整资源销毁机制,每一次爬取任务结束后,都会彻底关闭页面、销毁浏览器上下文、清空所有缓存和会话,完全断开隧道代理连接,从机制上保证下一轮任务必然切换新IP,杜绝IP复用导致的风控封禁。同时关闭HTTP2协议,完美适配隧道代理传输规则,大幅降低连接报错概率。
普通机房IP特征明显、全网复用率高,很容易被网站批量标记封禁;而住宅IP是真实家庭宽带IP,IP独立、分散、纯净度高,无批量风控特征、相似度极低,不管是低频测试还是高频长期爬取,封禁概率都远低于机房IP,适配绝大多数高强度反爬网站。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。