各位老铁,晚上好!今天咱们聊点刺激的,说说怎么跟那些神烦的 Anti-Bot 机制斗智斗勇。记住,咱们的目标不是教唆大家干坏事,而是为了更好地理解这些机制,保护自己的爬虫,也保护自己的数据。
开场白:别把爬虫当小强,要当绅士!
很多网站都装了 Anti-Bot 机制,目的很简单:防止恶意爬虫薅羊毛,影响正常用户体验。咱们写爬虫,不能像个愣头青,横冲直撞,搞得人家服务器瘫痪。要像个绅士,礼貌地请求,合理地抓取。当然,必要的伪装也是必不可少的。
第一节:浏览器指纹识别——你是谁?从哪来?要到哪去?
想象一下,你走进一家酒吧,老板一眼就能看出你是新来的。为什么?因为你的穿着、谈吐、行为都跟老顾客不一样。浏览器指纹识别就是这个道理。网站通过各种信息,给你的浏览器打上一个独特的“指纹”,用来判断你是不是一个正常的浏览器。
-
常见的指纹信息:
信息 说明 User-Agent 声明浏览器及操作系统信息,容易伪造,但很重要。 Platform 操作系统平台,比如 Win32
、Linux x86_64
。Plugins 安装的浏览器插件列表,比如 Flash、Java。 Fonts 系统安装的字体列表,不同的操作系统、浏览器,字体列表可能不一样。 WebGL WebGL 渲染器信息,包括渲染器名称、厂商、版本等。 AudioContext AudioContext 的指纹,通过 Web Audio API 生成,不同的硬件和软件环境,生成的指纹可能不一样。 Canvas Canvas 指纹,通过 Canvas API 绘制文本或图形,然后获取图像数据的哈希值。不同的操作系统、浏览器、字体,绘制出来的图像可能不一样。 Timezone 时区信息。 Screen Size 屏幕分辨率。 -
检测方式:
网站通常会用 JavaScript 代码来收集这些信息,然后进行分析和判断。
-
绕过策略:
-
User-Agent 伪造: 这是最基本的,但也是最有效的。
import requests import random user_agents = [ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.3 Safari/605.1.15', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:89.0) Gecko/20100101 Firefox/89.0', ] def get_random_user_agent(): return random.choice(user_agents) headers = { 'User-Agent': get_random_user_agent() } response = requests.get('https://www.example.com', headers=headers) # 替换成目标网址 print(response.status_code)
-
Headless Chrome 模拟: 使用 Puppeteer 或 Selenium 这样的工具,可以模拟真实的浏览器环境,包括各种指纹信息。
const puppeteer = require('puppeteer'); (async () => { const browser = await puppeteer.launch({ headless: false, // 是否以无头模式运行 args: [ '--disable-web-security', // 禁用 web 安全策略,避免跨域问题 '--disable-features=IsolateOrigins', // 禁用隔离源,避免一些指纹检测 '--lang=zh-CN,zh;q=0.9,en;q=0.8', // 设置语言 ], }); const page = await browser.newPage(); // 设置 User-Agent await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'); // 模拟视窗大小 await page.setViewport({ width: 1920, height: 1080 }); await page.goto('https://www.example.com'); // 替换成目标网址 // 模拟鼠标移动 await page.mouse.move(100, 100); // 模拟点击 await page.click('a'); await page.waitForTimeout(5000); // 等待 5 秒 await browser.close(); })();
-
指纹随机化: 可以修改 Headless Chrome 的启动参数,或者使用一些第三方库,来随机化一些指纹信息,比如 WebGL、Canvas。
// 使用 puppeteer-extra 和 puppeteer-extra-plugin-stealth 来隐藏指纹 const puppeteer = require('puppeteer-extra'); const StealthPlugin = require('puppeteer-extra-plugin-stealth'); puppeteer.use(StealthPlugin()); (async () => { const browser = await puppeteer.launch({ headless: false }); const page = await browser.newPage(); await page.goto('https://www.example.com'); // 替换成目标网址 await page.waitForTimeout(5000); await browser.close(); })();
-
使用真实浏览器: 这是最靠谱的方法,但成本也最高。可以使用一些云服务,比如 Browserless、HeadlessChrome.dev,它们提供了真实的浏览器环境,可以有效避免指纹识别。
-
第二节:行为分析——你的小动作,我都知道!
光有好的皮囊还不够,还要有像人一样的行为。网站可以通过分析你的鼠标移动、点击、键盘输入等行为,来判断你是不是一个机器人。
-
常见的行为分析:
行为 说明 鼠标移动轨迹 真实的用户的鼠标移动轨迹通常是不规则的,而机器人的鼠标移动轨迹往往是直线或者规则的曲线。 点击行为 真实的用户的点击行为通常是有目的性的,而机器人的点击行为可能是随机的或者有规律的。 键盘输入 真实的用户的键盘输入通常是有意义的,而机器人的键盘输入可能是随机的或者无意义的。 页面停留时间 真实的用户的页面停留时间通常是根据内容决定的,而机器人的页面停留时间可能是固定的。 页面滚动 真实的用户的页面滚动通常是根据内容决定的,而机器人的页面滚动可能是固定的或者无规律的。 -
检测方式:
网站通常会用 JavaScript 代码来监听用户的行为,然后进行分析和判断。
-
绕过策略:
-
模拟鼠标移动: 使用 Puppeteer 或 Selenium,可以模拟真实的鼠标移动轨迹。
const puppeteer = require('puppeteer'); // 模拟鼠标移动轨迹 async function simulateMouseMove(page, startX, startY, endX, endY, steps = 20) { const deltaX = (endX - startX) / steps; const deltaY = (endY - startY) / steps; for (let i = 0; i < steps; i++) { const currentX = startX + deltaX * i; const currentY = startY + deltaY * i; await page.mouse.move(currentX, currentY); await page.waitForTimeout(Math.random() * 20 + 10); // 增加随机延迟 } await page.mouse.move(endX, endY); } (async () => { const browser = await puppeteer.launch({ headless: false }); const page = await browser.newPage(); await page.setViewport({ width: 1920, height: 1080 }); await page.goto('https://www.example.com'); // 替换成目标网址 // 获取元素的位置 const element = await page.$('a'); // 替换成目标元素的选择器 const boundingBox = await element.boundingBox(); const centerX = boundingBox.x + boundingBox.width / 2; const centerY = boundingBox.y + boundingBox.height / 2; // 模拟鼠标移动到元素中心 await simulateMouseMove(page, 100, 100, centerX, centerY); // 模拟点击 await page.click('a'); await page.waitForTimeout(5000); await browser.close(); })();
-
模拟点击行为: 模拟点击不同的元素,增加随机延迟。
// 模拟随机点击 async function simulateRandomClicks(page, clicks = 5) { for (let i = 0; i < clicks; i++) { // 随机选择一个元素 const elements = await page.$$('body *'); const randomIndex = Math.floor(Math.random() * elements.length); const element = elements[randomIndex]; // 获取元素的位置 const boundingBox = await element.boundingBox(); if (boundingBox) { const centerX = boundingBox.x + boundingBox.width / 2; const centerY = boundingBox.y + boundingBox.height / 2; // 模拟鼠标移动到元素中心 await page.mouse.move(centerX, centerY); // 模拟点击 await page.click('body'); // 点击body,可以触发更多事件 await page.waitForTimeout(Math.random() * 500 + 200); // 增加随机延迟 } } }
-
模拟键盘输入: 模拟键盘输入,增加随机延迟。
// 模拟键盘输入 async function simulateKeyboardInput(page, text) { for (let i = 0; i < text.length; i++) { await page.keyboard.type(text[i]); await page.waitForTimeout(Math.random() * 100 + 50); // 增加随机延迟 } }
-
随机页面停留时间: 每次访问页面后,随机停留一段时间。
import time import random def random_sleep(min_seconds=1, max_seconds=5): sleep_time = random.uniform(min_seconds, max_seconds) time.sleep(sleep_time) # 使用示例 random_sleep()
-
模拟页面滚动: 模拟页面滚动,增加随机延迟。
// 模拟随机滚动 async function simulateRandomScroll(page, scrollHeight = 500) { await page.evaluate((scrollHeight) => { window.scrollBy(0, Math.random() * scrollHeight); }, scrollHeight); await page.waitForTimeout(Math.random() * 500 + 200); // 增加随机延迟 }
-
第三节:JS 环境检测——你是不是在装模作样?
网站可以通过检测 JavaScript 的运行环境,来判断你是不是一个真实的浏览器。比如,检测是否存在 window
对象、navigator
对象,或者检测一些特定的 JavaScript 函数。
-
常见的 JS 环境检测:
检测项 说明 window
对象window
对象是浏览器环境的全局对象,如果不存在,说明不是浏览器环境。navigator
对象navigator
对象包含了浏览器的信息,比如 User-Agent、Platform 等,如果不存在,说明不是浏览器环境。document
对象document
对象代表了 HTML 文档,如果不存在,说明不是浏览器环境。特定函数 网站可能会检测一些特定的 JavaScript 函数,比如 eval
、Function
,如果不存在或者被修改,说明可能是一个模拟环境。 -
检测方式:
网站通常会用 JavaScript 代码来检测这些信息,然后进行分析和判断。
-
绕过策略:
-
使用 Headless Chrome: Headless Chrome 提供了完整的 JavaScript 运行环境,可以有效避免 JS 环境检测。
-
修改 JavaScript 环境: 可以修改 JavaScript 的运行环境,模拟真实的浏览器环境。
// 修改 navigator 对象 Object.defineProperty(navigator, 'webdriver', { get: () => false, }); // 修改 window 对象 window.navigator.chrome = { runtime: {}, }; // 删除一些属性 delete navigator.plugins; delete navigator.mimeTypes;
-
使用 Proxy: 使用 Proxy 可以拦截 JavaScript 代码的执行,修改返回值,从而绕过 JS 环境检测。
// 使用 Proxy 拦截 navigator 对象 const originalNavigator = navigator; const proxyNavigator = new Proxy(originalNavigator, { get: function(target, prop) { if (prop === 'webdriver') { return false; } return target[prop]; }, }); // 将 navigator 对象替换为 Proxy 对象 window.navigator = proxyNavigator;
-
第四节:蜜罐——小心有诈!
蜜罐是一种诱饵技术,网站会在页面上放置一些隐藏的链接或表单,只有机器人才能发现并点击。一旦机器人点击了这些链接或表单,就会被识别出来。
-
常见的蜜罐:
类型 说明 隐藏链接 在页面上放置一些隐藏的链接,比如用 CSS 将链接隐藏起来,或者将链接的颜色设置为和背景色一样。 隐藏表单 在页面上放置一些隐藏的表单,比如用 CSS 将表单隐藏起来,或者将表单的 name
属性设置为一些奇怪的值。JavaScript 生成的链接 通过JavaScript动态生成链接,正常用户不会这么快就抓取到这些链接,而爬虫可能会抓取到。 -
检测方式:
网站通常会用 CSS 或 JavaScript 代码来隐藏这些链接或表单。
-
绕过策略:
-
不要抓取隐藏的链接或表单: 在抓取页面时,忽略那些用 CSS 隐藏起来的链接或表单。
from bs4 import BeautifulSoup import requests response = requests.get('https://www.example.com') # 替换成目标网址 soup = BeautifulSoup(response.content, 'html.parser') # 找到所有可见的链接 visible_links = [a['href'] for a in soup.find_all('a') if a.get('href') and a.get('style') != 'display: none;'] print(visible_links)
-
不要填写隐藏的表单: 在填写表单时,检查表单的
name
属性,避免填写那些name
属性奇怪的表单。 -
使用真实用户行为: 模拟真实用户的行为,不要盲目地抓取所有的链接或填写所有的表单。
-
总结:道高一尺,魔高一丈!
Anti-Bot 机制和绕过策略是一个永恒的猫鼠游戏。网站会不断地更新 Anti-Bot 机制,我们也要不断地学习和改进绕过策略。记住,咱们的目标不是战胜所有的 Anti-Bot 机制,而是要找到一个平衡点,既能抓取到我们需要的数据,又能避免被网站封禁。
最后,送给大家一句至理名言:
爬虫有风险,入行需谨慎! (手动狗头)
希望今天的分享对大家有所帮助! 谢谢大家!