026.爬虫专用浏览器-绕过常见无头检测(二)
一、无头检测简介:
- 无头检测(
Headless Detection
)就是检测用户是否在无头浏览器。只要检测到,那百分百是爬虫。 - 无头检测我们多数使用这个站:https://bot.sannysoft.com/
- 之前写过一篇文章:插眼传送,绕过了部分检测,但是不全,这里我们继续追加。
二、WebGL Render
- 无头模式下,不会使用gpu,所以检测webGL render是否有关键字"
SwiftShader
",如果有那就是无头。
- 打开文件
\third_party\blink\renderer\modules\webgl\webgl_rendering_context_base.cc
case WebGLDebugRendererInfo::kUnmaskedRendererWebgl:if (ExtensionEnabled(kWebGLDebugRendererInfoName)) {if (IdentifiabilityStudySettings::Get()->ShouldSampleType(blink::IdentifiableSurface::Type::kWebGLParameter)) {RecordIdentifiableGLParameterDigest(pname, IdentifiabilityBenignStringToken(String(ContextGL()->GetString(GL_RENDERER))));}//return WebGLAny(script_state,// String(ContextGL()->GetString(GL_RENDERER)));// 追加 ==========================================base::CommandLine* base_command_line = base::CommandLine::ForCurrentProcess();int seed;if (base_command_line->HasSwitch("fingerprints")) {std::istringstream(base_command_line->GetSwitchValueASCII("fingerprints")) >> seed;}else{auto now = std::chrono::system_clock::now();std::time_t now_time_t = std::chrono::system_clock::to_time_t(now);seed = static_cast<int>(now_time_t);}String tmp = " (NV/" + String(std::to_string(seed)) + ")";String render = (String(ContextGL()->GetString(GL_RENDERER)) + tmp);std::string renderer = render.Utf8();// 将全部SwiftShader替换成NVDIAstd::string searchString = "SwiftShader";std::string replaceString = "NVDIA";size_t start_pos = 0;while ((start_pos = renderer.find(searchString, start_pos)) != std::string::npos) {renderer.replace(start_pos, searchString.length(), replaceString);start_pos += replaceString.length(); }return WebGLAny(script_state, String(renderer));// 结束追加 ==========================================}SynthesizeGLError(GL_INVALID_ENUM, "getParameter","invalid parameter name, WEBGL_debug_renderer_info not enabled");return ScriptValue::CreateNull(script_state->GetIsolate());
这里的逻辑是将
SwiftShader
关键字全部改成NVDIA
了。
三、window.chrome
- 正常有头的chromium内核浏览器打开F12都是有
window.chrome
的,但无头浏览器会返回undefined
。
- 打开文件
\content\renderer\render_frame_impl.cc
void RenderFrameImpl::DidClearWindowObject() {TRACE_EVENT_WITH_FLOW0("navigation", "RenderFrameImpl::DidClearWindowObject",TRACE_ID_LOCAL(this),TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);if (enabled_bindings_ & BINDINGS_POLICY_WEB_UI)WebUIExtension::Install(frame_);
- 替换为:
void RenderFrameImpl::DidClearWindowObject() {TRACE_EVENT_WITH_FLOW0("navigation", "RenderFrameImpl::DidClearWindowObject",TRACE_ID_LOCAL(this),TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);//if (enabled_bindings_ & BINDINGS_POLICY_WEB_UI)// WebUIExtension::Install(frame_);WebUIExtension::Install(frame_);
这里就是把if条件注释掉。
四、plugins插件
有头浏览器都会装5个默认插件,但无头会变成0个。
这个上篇无头博客改了,但是改的有点乱,会被cloudflare检测到,所以上篇这里作废,我们重改。
- 打开:
\third_party\blink\renderer\modules\plugins\dom_plugin_array.cc
bool DOMPluginArray::IsPdfViewerAvailable() {auto* data = GetPluginData();if (!data)return false;for (const Member<MimeClassInfo>& mime_info : data->Mimes()) {if (mime_info->Type() == "application/pdf")return true;}return false;
}
- 替换为:
bool DOMPluginArray::IsPdfViewerAvailable() {//auto* data = GetPluginData();//if (!data)// return false;//for (const Member<MimeClassInfo>& mime_info : data->Mimes()) {// if (mime_info->Type() == "application/pdf")// return true;//}//return false;return true;
}
让这个函数一直返回
true
即可。
五、无头userAgent
-
上篇博客给userAgent去掉了
HeadlessChrome
特征,但是发现他一直不变,因为无头的UA和有头的UA是两套逻辑。这里我们给无头UA加些随机数。 -
打开:
\headless\lib\browser\headless_browser_impl.cc
std::string HeadlessBrowser::GetProductNameAndVersion() {return std::string(kHeadlessProductName) + "/" + PRODUCT_VERSION;
}
- 替换为:
std::string HeadlessBrowser::GetProductNameAndVersion() {//return std::string(kHeadlessProductName) + "/" + PRODUCT_VERSION;base::CommandLine* base_command_line = base::CommandLine::ForCurrentProcess();int tmp = 0;if (base_command_line->HasSwitch("fingerprints")) {std::istringstream(base_command_line->GetSwitchValueASCII("fingerprints")) >> tmp;}int fooversion = 124;return "Chrome/" + std::to_string(fooversion) + ".0.0.0 BigTom/" + std::to_string(tmp);
}
六、结语:
- 无头模式主要是为了后续做linux版本做准备,但博主太穷,没钱升级电脑。
- 所以短时间linux版的是搞不了了。