如何在 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 事件),但我會將其保留在另一篇文章中。 希望你喜歡它!