如何在 Google Analytics 中查看由 Google 呈现的 URL
已发表: 2021-06-11首先,特别感谢 Christian 帮我翻译!
几年前,Google 开始大幅改进其抓取和加载 Javascript 内容的能力,就像真正的手机用户看到的那样。
尽管如此,即使 Google 改进了其基础架构,它也无法抓取它找到的所有 URL,因为抓取和呈现(将 HTML 文档转换为可视结构的过程)的成本远高于简单的抓取和获取URL 的 HTML。 Google 自己也承认了这一点,因此确保 Google 能够找到、呈现和索引我们网站最重要的 URL 非常重要,特别是在较大的网站和/或依赖于客户端执行的 JS 的网站中(CSR,客户端渲染)
多年前,为了评估 URL 的内容并决定是否将其添加到索引中,Google 已经足够获取 URL 的 HTML(以及那里链接的图像)。 该 HTML 是 Google 用于对 URL 进行索引和排名的内容,而没有考虑该 HTML 是否在呈现后使用 Javascript 进行了修改。
现在,随着修改 HTML 客户端的 Javascript 框架大肆宣传,Google 需要获取 HTML、JS 代码、CSS 样式和其他资源(如图像、正面等)才能呈现内容并获取最终的 HTML,因此它可以决定是否进入索引。
整个过程并不是像普通用户看到的那样在一个批次中完成:它分两步完成。 首先,Google 抓取 URL 并获取“未渲染”的 HTML(直到现在它一直在做),一段时间后(没有固定的指定时间),它获取该 HTML 中引用的其余资源并尝试呈现页面以获得最终呈现的 HTML。 这第二步被称为“第二波索引”。
我们不需要具备很多技术知识就可以理解,为了抓取和索引多个 URL,无论是在时间还是资源上,渲染它们的成本都比获取未渲染的 HTML 要大得多。 因此,使用相同数量的有限资源,如果需要呈现它们,Google 将能够抓取和索引更少的 URL。 这就是为什么谷歌需要决定/优先考虑哪些 URL 呈现,哪些不呈现。
为了决定接下来应该抓取哪个网址,Google 会计算该网址自上次抓取后发生更改的概率,同时考虑其他因素,例如每个网址的 PageRank,或者网站管理员是否配置了有关抓取的任何特定设置频率。 这是有道理的,因为花费有限的资源来抓取没有改变的东西是没有用的。
我想与您分享这篇文章,因为我认为它并不为人所知,而且它可能非常具有启发性,以便了解 Google 如何决定接下来要抓取哪个 URL。 它由 Google 的工程师编写,是解决实际问题的数学抽象。 不要对数学公式感到害怕,对于不是数据科学家的人来说,它已经得到了完美的解释。
在决定接下来要抓取哪个 URL 之后,Googlebot 需要为每个抓取的 URL 决定是否应该呈现该 URL,如果它决定呈现一个 URL,它将需要所有资源来完成该操作。 为了决定它是否需要请求每个所需的资源,它可能使用类似的数学过程,但有一些差异,如缓存时间、获取资源的成本等。
由于所有这些,了解我们网站中的哪些 URL 正在被 Google 抓取,以及哪些正在被呈现,这一点非常重要。 我们在 Funnel▼Punk(我们与大型网站合作的地方)使用的获取该信息的一种简单方法是分析服务器日志(这是我的博客中的一篇关于此的帖子,西班牙语,另一篇在 Oncrawl 的博客上),全面了解 Googlebot 在我们的网站上所做的事情。 日志分析对于很多人来说可能是乏味且昂贵的,这就是为什么我想与您分享一种跟踪 Googlebot 在 Google Analytics 中呈现哪些 URL 的方法。
[案例研究] 管理 Google 的机器人抓取
跟踪 Google 呈现的 URL
该方法相对简单,至少对于任何开发团队和任何使用 PHP 或类似工具的网站管理员来说都是如此。 它有3个步骤:
- 添加javascript代码
该代码将检测 Googlebot 何时以与普通用户相同的方式执行 Javascript,并将使用 Javascript(透明像素)加载图像。 - 服务器配置
将服务器配置为在请求透明像素的 URL 时执行 PHP 文件(或后端使用的任何其他编程语言)。 - 将数据发送到 Google Analytics
我们的 PHP 文件将检查 Googlebot 是否真的是 Googlebot,如果是,则将数据发送到 Google Analytics。
添加javascript代码
在我尝试的不同实验中,我检查了 Googlebot 只有在 Javascript 代码不需要用户交互时才会执行 Javascript。 例如,Googlebot 将执行任何由 onload 或 onready 事件触发的 Javascript 代码。 在此示例中,我们将创建一个函数,该函数将由 onLoad 事件触发,即当页面的所有元素都加载完毕时。
此函数将检查用户代理是否包含任何 Googlebot 的已知机器人,如果是,它将加载图像(透明像素),我们将其命名为 TransparentPixelGooglebot.gif
<脚本> window.addEventListener("加载", function(){ var botPattern = "googlebot|Googlebot-Mobile|Googlebot-Image|Google favicon|Mediapartners-Google"; var re = new RegExp(botPattern, 'i'); var userAgent = navigator.userAgent; 如果(重新测试(userAgent)){ var client = new XMLHttpRequest(); var trackRenderURL='https://www.mecagoenlos.com/TransparentPixelGooglebot.gif?OriginUrl='+window.location.href; client.open('GET',trackRenderURL); client.setRequestHeader('Content-Type', 'text/plain;charset=UTF-8'); 客户端.send(null); } }); </脚本>每当 Googlebot 访问并执行 Javascript 时,我们的函数将被触发,加载“TransparentPixelGooglebot.gif”图像,在图像的 URL 中添加一些参数,我们将在其中指定已访问的特定 URL。
在这个变量中,我们将组成将被请求加载“TransparentPixelGooglebot.gif”图像的完整 URL,我们在其中添加访问的 URL 以及请求它的用户代理。
var trackRenderURL='https://www.mecagoenlos.com/TransparentPixelGooglebot.gif?OriginUrl='+window.location.href;
服务器配置 (.htaccess)
我们的下一步是配置我们的服务器,以便在请求像素 (TransparentPixelGooglebot.gif) 的 URL 时执行 PHP 文件 (GooglebotRenderJS.php)
为此,我们必须对 .htaccess 文件进行一些更改(因为我们使用 Apache 服务器和 PHP 作为后端编程语言)
这两个特定的行将实现这一点:
RewriteCond %{REQUEST_URI} TransparentPixelGooglebot.gif RewriteRule TransparentPixelGooglebot.gif(.*)$ https://www.mecagoenlos.com.com/GooglebotRenderJS.php$1
您可以猜到,像素请求中包含的参数会被传播,以便 PHP 文件 (GooglebotRenderJS.php) 可以“读取”它们。
抓取数据³
从 PHP 文件将数据发送到 Google Analytics
在我们的最后一步中,我们创建了将在请求像素 (TransparentPixelGooglebot.gif) 时执行的 PHP 文件 (GooglebotRenderJS.php)。
该文件将:
- 使用反向 DNS 检查请求是由 Googlebot 发出还是由使用 Googlebot 用户代理的假 Googlebot 发出
- 确定它是什么类型的机器人(Googlebot Mobile、图片、广告等)
- 在我们将分配以下变量的事件中,将数据发送到 Google Analytics(使用 Google Analytics 的测量协议):
- 事件类别:“GoogleRenderFromHtaccess”
- 事件操作:呈现的 URL(像素请求的引用者)
- 事件标签:连接用户代理、IP 以及机器人是真正的 Googlebot(“Real”)还是假的(“Fake”)的字符串。 我将他们三个发送到 GA,以便能够查看 Googlebot 的识别是否正常工作。
- *重要提示:我仅将 IP 存储了几天以测试一切是否正常,之后我停止这样做以防数据保护法出现任何问题
<?php header("Pragma-directive: no-cache"); header("缓存指令:无缓存"); header("缓存控制:无缓存"); header("Pragma: no-cache"); header("过期时间:0"); if ($_GET["OriginUrl"]) $src=$_GET["OriginUrl"]; 别的 $src = $_SERVER['HTTP_REFERER']; $UA=$_SERVER["HTTP_USER_AGENT"]; $RenderParameters=$_GET["RenderParameters"]; 函数 GoogleCheker($Ip){ # 为避免不必要的查找,只检查 UA 是否匹配其中之一 # 我们喜欢的机器人 $hostname=gethostbyaddr($Ip); $ip_by_hostname=gethostbyname($hostname); if(preg_match("/googlebot/i",$hostname)) if ($ip_by_hostname == $Ip) 返回真; 别的 返回假; 别的 返回假; } 函数 GoogleChekerExtend($Ip){ # 为避免不必要的查找,只检查 UA 是否匹配其中之一 # 我们喜欢的机器人 $hostname=gethostbyaddr($Ip); $ip_by_hostname=gethostbyname($hostname); if(preg_match("/\.google\.com[\.]?$/i",$hostname)) if ($ip_by_hostname == $Ip) 返回真; 别的 返回假; 别的 返回假; } $botname="初始化"; $bots = array('Mediapartners-Google[ /]([0-9.]{1,10})' => 'Google Mediapartners', 'Mediapartners-Google' => 'Google Mediapartners', 'Googl(e|ebot)(-Image)/([0-9.]{1,10})' => 'Google 图片', 'Googl(e|ebot)(-Image)/' => '谷歌图片', '^gsa-crawler' => '谷歌', 'Googl(e|ebot)(-Sitemaps)/([0-9.]{1,10})?' => '谷歌站点地图', 'GSiteCrawler[ /v]*([0-9.az]{1,10})?' => '谷歌站点地图', 'Googl(e|ebot)(-Sitemaps)' => 'Google-Sitemaps', 'Mobile.*Googlebot' => 'Google-Mobile', '^AdsBot-Google' => 'Google-AdsBot', '^Feedfetcher-Google' => 'Google-Feedfetcher', '兼容的; Google 桌面' => 'Google 桌面', 'Googlebot' => 'Googlebot'); foreach( $bots as $pattern => $bot ) { if ( preg_match( '#'.$pattern.'#i' , $UA) == 1 ) { $botname = preg_replace ( "/\\s{1,}/i" , '-' , $bot ); 休息; } } if(GoogleCheker($_SERVER['REMOTE_ADDR'])) $isGoogle="真实"; elseif(GoogleChekerExtend($_SERVER['REMOTE_ADDR'])) $isGoogle="扩展"; 别的 $isGoogle="假货"; 类 BotTracker { 静态函数跟踪($s,$params){ $机器人 = ""; $数据 = 数组( 'v' => 1, 'tid' => 'UA-XXXXXXX-1', 'cid' => self::generate_uuid(), 't' => '事件', 'dh' => $s['HTTP_HOST'], 'dl' => $s['REQUEST_URI'], 'dr' => $s['HTTP_REFERER'], 'dp' => $s['REQUEST_URI'], 'dt' => $params['page_title'], 'ck' => $s['HTTP_USER_AGENT'], 'uip' => $s['REMOTE_ADDR'], '你' => 1, 'ec' => 'GoogleRenderHtaccess', 'el' => $params['UA']." - ".$params["RenderParameters"]." -" .$params['botname']." - ".$params['isGoogle']." - ip: ".$s['REMOTE_ADDR'], //测试后删除 //'el' => $params['UA']." - ".$params["RenderParameters"]." -" .$params['botname']." - ".$params['isGoogle'] , 'ea' => $params['RenderedURL'] ); $url = 'http://www.google-analytics.com/collect'; $content = http_build_query($data); $ch = curl_init(); curl_setopt($ch, CURLOPT_USERAGENT, $s['HTTP_USER_AGENT']); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 0); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT_MS, 0); curl_setopt($ch, CURLOPT_TIMEOUT_MS, 0); curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-type: application/x-www-form-urlencoded')); curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch,CURLOPT_ENCODING , "gzip"); curl_setopt($ch, CURLOPT_POSTFIELDS, $content); $result = curl_exec($ch); $info= curl_getinfo($ch); curl_close($ch); } 静态私有函数 generate_uuid() { return sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x', mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0x0fff) | 0x4000, mt_rand(0, 0x3fff) | 0x8000, mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff) ); } } BotTracker::track($_SERVER, array("page_title"=>"VirtualRenderTitle","RenderedURL"=>$src,"isGoogle"=>$isGoogle,"botname"=>$botname,"UA"=>$UA ,"RenderParameters"=>$RenderParameters)); ?>
检查我们的设置是否在 Google Analytics 中运行
一切都准备好了! 现在我们可以检查一切是否按预期工作。 为此,我们可以使用 Google Analytics 的实时报告并选择“事件”报告。 在另一个选项卡上,我们打开 Search Console,转到我们网站的属性并使用 URL Inspector 强制 Google 抓取和呈现我们的任何 URL。 如果一切正常,您将在 Google Analytics(分析)实时事件报告中看到新事件。
正如您将看到的,这些事件不会被计为我们站点中的活跃用户,因为这些事件是使用“nonInteraction”参数配置的。
如果我们点击事件类别“GoogleRenderFromHtaccess”,我们将能够看到用户代理、IP 以及机器人是否被识别为真实或虚假。
由 Google 尝试呈现 URL 生成的跟踪错误
我们已经了解了如何跟踪和检查 Google 正在呈现哪些 URL。 但我们可以更进一步,跟踪当 Google 尝试呈现我们网站的 URL 时生成了哪些 Javascript 错误。
呈现 Javascript 时,可能会生成仅在用户浏览器上可见的错误(而不是在我们的服务器上),因此跟踪这些错误并非易事。
如今,如果我们想检查 Googlebot 在呈现我们的 URL 时产生了哪些 Javascript 错误,我们只能使用 Search Console 中的 URL Inspector 来完成。
- 检查 URL:
- 点击“测试直播网址”:
- 检查是否有任何错误:
为大量 URL 手动执行此操作需要大量工作,但我们可以使用我刚刚向您展示的代码来跟踪 Googlebot 尝试呈现我们的 URL 时是否存在任何 Javascript 错误。
故意生成的错误示例以检查代码是否正常工作:
添加 Javascript 代码
与我们在上一个示例中所做的相同,我们将使用以下代码行捕获任何 Javascript 错误: "window.addEventListener('error', function(e)"
。
每当生成错误时,将执行允许我们保存这些错误并将它们发送到 Google Analytics 的功能。 这将与我们在上一个示例中所做的非常相似,但需要注意的是,该函数仅在出现 Javascript 错误时才会执行。
window.addEventListener('error', function(e) { var botPattern = "googlebot|Googlebot-Mobile|Googlebot-Image|Google favicon|Mediapartners-Google"; var re = new RegExp(botPattern, 'i'); var userAgent = navigator.userAgent; 如果(重新测试(userAgent)){ var client = new XMLHttpRequest(); var ErrorsURLPixel='https://www.mecagoenlos.com/TransparentPixelGooglebotError.gif?OriginUrl='+window.location.href+'&textError='+unescape(encodeURIComponent(e.message))+'&LineError='+unescape(encodeURIComponent (e.lineno.toString()))+'&UA='+unescape(encodeURIComponent(userAgent)); client.open('GET',ErrorsURLPixel); client.setRequestHeader('Content-Type', 'text/plain;charset=UTF-8'); client.send(e); } });
此代码将执行将加载另一个透明像素 (TransparentPixelGooglebotError.gif) 的函数,添加正在呈现的 URL、错误和用户代理作为参数,生成对 URL 的请求,如下所示:
var ErrorsURLPixel='https://www.mecagoenlos.com/TransparentPixelGooglebotError.gif?OriginUrl='+window.location.href+'&textError='+unescape(encodeURIComponent(e.message))+'&LineError='+unescape(encodeURIComponent (e.lineno.toString()))+'&UA='+unescape(encodeURIComponent(userAgent));
服务器配置 (.htaccess)
与上一个示例相同,我们将在 .htaccess 中添加一些规则来检测像素何时加载并执行 PHP 文件:
RewriteCond %{REQUEST_URI} TransparentPixelGooglebotError.gif RewriteRule TransparentPixelGooglebotError.gif(.*)$ https://modelode.com/GooglebotErrorRenderJS.php$1
这样,每当请求“https://www.mecagoenlos.com/TransparentPixelGooglebotError.gif”时,都会执行“GooglebotErrorRenderJS.php”PHP 文件。
PHP 文件
此 PHP 文件将检查 Googlebot 是否真实,并使用“ErrorsGoogleRender”类别的事件将数据发送到 Google Analytics,使用呈现的 URL 作为事件操作,错误本身作为事件标签。
<?php header("Pragma-directive: no-cache"); header("缓存指令:无缓存"); header("缓存控制:无缓存"); header("Pragma: no-cache"); header("过期时间:0"); if ($_GET["OriginUrl"]) $src=$_GET["OriginUrl"]; 别的 $src = $_SERVER['HTTP_REFERER']; $UA=$_SERVER["HTTP_USER_AGENT"]; $RenderParameters=$_GET["RenderParameters"]; $textError=$_GET["textError"]; $lineError=$_GET["LineError"]; 函数 GoogleCheker($Ip){ # 为避免不必要的查找,只检查 UA 是否匹配其中之一 # 我们喜欢的机器人 $hostname=gethostbyaddr($Ip); $ip_by_hostname=gethostbyname($hostname); if(preg_match("/googlebot/i",$hostname)) if ($ip_by_hostname == $Ip) 返回真; 别的 返回假; 别的 返回假; } 函数 GoogleChekerExtend($Ip){ # 为避免不必要的查找,只检查 UA 是否匹配其中之一 # 我们喜欢的机器人 $hostname=gethostbyaddr($Ip); $ip_by_hostname=gethostbyname($hostname); if(preg_match("/\.google\.com[\.]?$/i",$hostname)) if ($ip_by_hostname == $Ip) 返回真; 别的 返回假; 别的 返回假; } $botname="初始化"; $bots = array('Mediapartners-Google[ /]([0-9.]{1,10})' => 'Google Mediapartners', 'Mediapartners-Google' => 'Google Mediapartners', 'Googl(e|ebot)(-Image)/([0-9.]{1,10})' => 'Google 图片', 'Googl(e|ebot)(-Image)/' => '谷歌图片', '^gsa-crawler' => '谷歌', 'Googl(e|ebot)(-Sitemaps)/([0-9.]{1,10})?' => '谷歌站点地图', 'GSiteCrawler[ /v]*([0-9.az]{1,10})?' => '谷歌站点地图', 'Googl(e|ebot)(-Sitemaps)' => 'Google-Sitemaps', 'Mobile.*Googlebot' => 'Google-Mobile', '^AdsBot-Google' => 'Google-AdsBot', '^Feedfetcher-Google' => 'Google-Feedfetcher', '兼容的; Google 桌面' => 'Google 桌面', 'Googlebot' => 'Googlebot'); foreach( $bots as $pattern => $bot ) { if ( preg_match( '#'.$pattern.'#i' , $UA) == 1 ) { $botname = preg_replace ( "/\\s{1,}/i" , '-' , $bot ); 休息; } } if(GoogleCheker($_SERVER['REMOTE_ADDR'])) $isGoogle="真实"; elseif(GoogleChekerExtend($_SERVER['REMOTE_ADDR'])) $isGoogle="扩展"; 别的 $isGoogle="假货"; 类 BotTracker { 静态函数跟踪($s,$params){ $机器人 = ""; $数据 = 数组( 'v' => 1, 'tid' => 'UA-XXXX-1', 'cid' => self::generate_uuid(), 't' => '事件', 'dh' => $s['HTTP_HOST'], 'dl' => $s['REQUEST_URI'], 'dr' => $s['HTTP_REFERER'], 'dp' => $s['REQUEST_URI'], 'dt' => $params['page_title'], 'ck' => $s['HTTP_USER_AGENT'], 'uip' => $s['REMOTE_ADDR'], '你' => 1, 'ec' => 'ErrorsGoogleRender', 'el' => $params['textError']." (line:".$params['lineError'].") - ".$params['UA']." - " .$params['botname' ]." - ".$params['isGoogle']."- ip: ".$s['REMOTE_ADDR'], //测试后删除 //'el' => $params['UA']." - ".$params["RenderParameters"]." -" .$params['botname']." - ".$params['isGoogle'] , 'ea' => $params['RenderedURL'] ); $url = 'http://www.google-analytics.com/collect'; $content = http_build_query($data); $ch = curl_init(); curl_setopt($ch, CURLOPT_USERAGENT, $s['HTTP_USER_AGENT']); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 0); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT_MS, 0); curl_setopt($ch, CURLOPT_TIMEOUT_MS, 0); curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-type: application/x-www-form-urlencoded')); curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch,CURLOPT_ENCODING , "gzip"); curl_setopt($ch, CURLOPT_POSTFIELDS, $content); $result = curl_exec($ch); $info= curl_getinfo($ch); curl_close($ch); } 静态私有函数 generate_uuid() { return sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x', mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0x0fff) | 0x4000, mt_rand(0, 0x3fff) | 0x8000, mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff) ); } } BotTracker::track($_SERVER, array("page_title"=>"VirtualRenderTitle","RenderedURL"=>$src,"isGoogle"=>$isGoogle,"botname"=>$botname,"UA"=>$UA ,"RenderParameters"=>$RenderParameters,"textError"=>$textError,"lineError"=>$lineError)); ?>
现在我们已经可以看到当 Google 尝试呈现我们的 URL 时发生了哪些 Javascript 错误。
从我们的 PHP 文件向 Google Analytics 发送数据
通过这个实现,我们可以看到当 Google 尝试呈现我们的 URL 时生成了哪些特定的 Javascript 错误,以及它们发生在哪些特定的 URL 中。
我想到了很多关于 Google 渲染过程的其他信息要跟踪,比如检查 Googlebot 是否正在尝试一些交互(如滚动、点击或任何其他 Javascript 事件),但我会将其保留在另一篇文章中。 希望你喜欢它!