Attention ! Etes vous sûrs d'avoir une bonne assurance emprunteur pour votre crédit immobilier ?


nov 08

Suivre l’activité de Googlebot sur votre site grâce aux logs Apache

Tag: Coding, SEOnoreply @ 14:59

Vous avez été des milliers à vous plaindre du manque d’articles sur le référencement sur ce blog, je profite donc d’un petit script d’analyse de logs pour revenir dans le droit chemin !

Le suivi de l’activité des robots des moteurs de recherche sur votre site, et tout particulièrement du Googlebot, fait partie intégrante d’un bon référencement. Certes, Google mets à disposition des éditeurs depuis quelque temps déjà une série d’outils de suivi, les Google Webmaster Tools (GWT). C’est bien, mais pas toujours très complet et les mises à jours souvent aléatoires…

Les webmasters ont pourtant tout ce qu’il faut sous la main pour avoir des stats précises et surtout en temps réel pour suivre les bots : les logs du serveur Apache, souvent les meilleurs amis du référenceur !

Que faire avec ces logs ?

Les logs ne sont qu’un indicateur de plus pour l’analyse de la crawlabilité d’un site mais il y a de nombreuses façons de les utiliser. En vrac :

  • Identifier des liens cassés (404) ou d’autres erreurs rencontrées par le bot lors de ses visites
  • Si une page du site ne ressort pas dans l’index de Google, la première chose à faire est de vérifier si cette page a ou pas été crawlée par le googlebot
  • On peut également s’amuser à corréler la fréquence de passage du bot au PageRank dune page, ou à son traffic réel, ou encore à sa position dans les SERP
  • L’étude des visites du googlebot peut aussi servir à améliorer la structure des liens internes, détecter des pages isolées, etc.

Il y a encore sans doute de nombreuses autres apllications mais entrer dans le détail n’est pas l’objet de cet article.

Le principe du script

Le script consiste en un seul fichier PHP à installer où vous voulez sur votre serveur, tant qu’il est accéssible via votre navigateur. Pas de base de donnée, pas de cron, il devrait fonctionner out of the box.

Seule petite contrainte, au préalable vous devrez ajouter quelques lignes dans votre config apache afin de générer un fichier de log spécial pour le googlebot. Ceci n’altèrera en rien vos autres logs, mais permettra au script de travailler plus vite et plus efficacement.

Attention, un fichier de log « combined » ne convient pas au script de monitoring que je vous propose ! En effet, ceux qui connaissent parfaitement la directive LogFormat auront vu que ce fichier de log est composé de :

  1. IP du robot
  2. IP du robot (l’IP est loguée en double pour une utilisation éventuelle de l’outil logresolve…)
  3. timestamp UNIX
  4. domaine
  5. méthode (typiquement HEAD, GET ou POST)
  6. adresse de la page
  7. code de retour du serveur (200 si tout va bien, 404 si la page n’existe pas, etc.)
  8. useragent du robot

Pour en savoir plus sur les formats des logs apache, je vous invite à lire la doc en ligne ici.

Vous noterez également que j’ai choisi de sélectionner les visites à loguer en fonction du useragent, ce qui est facilement spoofable, il est possible d’intégrer d’autres useragents pour loguer les passages d’autres robots, ou de filtrer sur d’autres critères comme par exemple l’IP. Dans le rapport de l’outil toutefois, les lignes où l’IP ne semble pas provenir de google sont grisées et en italique.

Les principales fonctionnalités en quelques mots

  • Activité du bot : l’aiguille sera centrée pour une activité normale, dans le rouge pour une activité faible (moins de visites qu’à l’ordinnaire) et dans le vert si le bot s’exite !
  • Courbe sur 30 jours : Pour avoir un aperçu rapide du nombre de pages crawlées par Googlebot sur les trentes derniers jours.
  • Pages les plus crawlées : Le top 15 des pages les plus visitées par googlebot sur trente jours.
  • Log des visites : Les visites les plus récentes sont en haut, vous pouvez cliquer sur les URL pour avoir le détail pour une page (ou utiliser le mini moteur de recherche…)

A noter que si le fichier de logs est zippé lorsqu’il devient trop gros, vous aurez l’impression d’avoir perdu l’historique… Je coderais probablement une alternative le jour où je serai confronté à ce « bug » :)

Le script à installer

Voici le script HTML / PHP à copier et à coller sur votre serveur. Il devrait fonctionner tel quel à condition de renseigner correctement la variable $logFile et d’avoir au préalable ajouté les 3 lignes dans votre config Apache (et relancé Apache ensuite évidemment).

<?php
/*

 exemple de config apache  :

SetEnvIfNoCase User-Agent "googlebot" googlebot
LogFormat "%a %a %{%s}t %v %m %U %>s %{User-agent}i" googlebot
CustomLog /chemin_vers_vos_logs/googlebot.log googlebot env=googlebot

Notez que la ligne LogFormat est particulière, vous devez la laisser telle quelle pour que le script de monitoring fonctionne correctement

*/

$logFile = ‘/chemin_vers_vos_logs/googlebot.log’; // à personnaliser bien sûr

// Plus rien à modifier à partir de là

header(‘Content-Type: text/html’,true);

define(‘LAST_24_HOURS’,24*3600);
define(‘LAST_30_DAYS’,24*3600*30);

$show = str_replace(‘ ‘,‘+’,stripslashes($_REQUEST[’show’]));

if ($show)
{
    $show = preg_replace(‘#^https?://[^/]+#si’, »,$show);
    $show = preg_match(‘#^[/*]#s’,$show) ? $show : "/$show";
}

$regex = preg_quote(‘ ‘ . str_replace(‘*’,‘_wildcard_’,$show) . ‘ ‘,‘/’);
$regex = str_replace(‘_wildcard_’,‘[^ ]*’,$regex);

$dateStats = array();
$pageStats = array();

$now = time();
$lastDay = $now – LAST_24_HOURS;
$lastMonth = $now – LAST_30_DAYS;

$firstMonthDate = $now;
$firstDayDate = $now;

$dayCount = 0;
$monthCount = 0;

$f = fopen($logFile,‘r’);

for ($i = $lastMonth; $i <= $now; $i += LAST_24_HOURS) $dateStats[date(‘d-m-Y’,$i)] = 0;

while ($line = fgets($f))
{
    list($ip,$host,$time,$domain,$method,$path,$status,$agent) = preg_split(‘# +#s’,$line,8);
    if (!$show || preg_match("/^" . trim($regex) . "$/si",$path))
    {
        if ($time >= $lastMonth)
        {
            if ($firstMonthDate == $now) $firstMonthDate = $time;
            $monthCount++;
            $dateStats[date(‘d-m-Y’,$time)]++;
            $pageStats[$path]++;
           
            if ($time >= $lastDay)
            {
                $dayCount++;
                if ($firstDayDate == $now) $firstDayDate = $time;
            }
        }
    }
}

fclose($f);

arsort($pageStats);

$monthInterval = max(1,min(LAST_30_DAYS,$now$firstMonthDate));
$dayInterval = max(1,min(LAST_24_HOURS,$monthInterval));

$avgMonthCount = $monthCount / $monthInterval;
$avgDayCount = $dayCount / $dayInterval;

$realBotActivity = @round(100 * $avgDayCount / $avgMonthCount) or 0;
$botActivity = min(100,$realBotActivity/2);

$count = intval($show ? shell_exec("grep -E ‘$regex’ $logFile | wc -l") : shell_exec("wc -l $logFile"));
$start = intval($_REQUEST[’start’]);
$limit = 100;
$n = min($count,($start+1)*$limit);
$s = min($limit,$count-$start*$limit);
$visits = preg_split(‘#\n#s’,$show ? shell_exec("grep -E ‘$regex’ $logFile | tail -n$n | tac | tail -n$s") : shell_exec("tail -n$n $logFile | tac | tail -n$s"),-1,PREG_SPLIT_NO_EMPTY);
$paginationCount = floor(max(0,$count-1)/$limit);
$paginationUrl = $show ? "?show=$show&" : ‘?’;

$dns = array();
$results = array();

foreach ($visits as $v)
{
    list($ip,$host,$time,$domain,$method,$path,$status,$agent) = preg_split(‘# +#s’,$v,8);
    $agent = strip_tags($agent);
    if (!@$dns[$ip]) $dns[$ip] = gethostbyaddr($ip);
    array_push($results,array(
        ‘ip’=>$ip,
        ‘host’=>$dns[$ip],
        ‘date’=>date(‘d-m-Y H:i:s’,$time),
        ‘method’=>$method,
        ‘url’=>sprintf(‘http://%s%s’,$domain,$path),
        ’status’=>$status,
        ‘agent’=>$agent,
        ‘path’=>$path
    ));
}
?>
<html>
    <head>
        <title>GOOGLEBOT<?php if ($show) echo " on $show"; ?> : <?php echo (1+$start*$limit) . ‘-’ . min(($start+1)*$limit,$count) . ‘ / ‘ . $count; ?></title>
        <style>
        table { background-color: black; border: 1px solid black; width: 100%; }
        th {background-color: black; color: white; }
        tr.odd { background-color: #afa; }
        tr.even { background-color: #cfc; }
        tr.fake { background-color: #eef; font-style: italic; }
        tr:hover { background-color: white;}
        tr.error { background-color: #fcc;}
        tr.info { background-color: white; }
        td { vertical-align: bottom; }
        a.link { color: black; text-decoration: none; }
        div.myPagination {
            text-align: center;
            margin: 5px auto;
        }
        a.myPaginationLink {
            text-align: center;
            border: 1px solid #aaa;
            margin-right: 5px;
            padding: 2px 5px;
            color: #000;
            background-color: #fff;
            text-decoration: none;
        }
        a.myPaginationLink:hover {
            background-color: #eee;
            border-color: #000;
        }
        span.myPaginationSelected {
            text-align: center;
            border: 1px solid #000;
            margin-right: 5px;
            padding: 2px 5px;
            background-color: #000;
            color: #fff;
        }
        span.myPaginationDisabled {
            text-align: center;
            border: 1px solid #aaa;
            margin-right: 5px;
            padding: 2px 5px;
            background-color: #fff;
            color: #aaa;
        }
        span.myPaginationEtc {
            text-align: center;
            border: none;
            margin-right: 5px;
            padding: 0px;
            background-color: #fff;
            color: #aaa;
        }
        a.menu { color: black; text-decoration: none; }
        a.menu:hover { text-decoration: underline; }
        form { margin: 10px auto; }
        legend { font-style: italic; }
        label { font-weight: bold; display: block; }
        input { width: 300px; }
        </style>
    </head>
    <body onload="document.getElementById(’show’).focus();">
        <?php if ($show): ?>
        <p align="center"><a class="menu" href="?">Back to home</a></p>
        <?php endif; ?>
        <table>
            <tr>
                <th>Current Bot activity</th>
                <th>Last 30 days<?php if ($show) echo " on $show"; ?></th>
                <?php if (!$show): ?><th>Most crawled pages last 30 days</th><?php endif; ?>
            </tr>
            <tr class="info">
                <td align="center"><img src="http://chart.apis.google.com/chart?chs=225×125&cht=gom&chd=t:<?php echo $botActivity; ?>&chl=<?php echo urlencode($realBotActivity .’%');?>" />
<?php echo $dayCount; ?> pages crawled last 24h</td>
                <td align="center"><img src="http://chart.apis.google.com/chart?cht=lc&chco=0077CC&chm=B,E6F2FA,0,0,0&chls=1,0,0&chs=600×150&chd=t:<?php echo implode(‘,’,array_values($dateStats)); ?>&chds=0,<?php echo max($dateStats); ?>&chxt=x,y&chxl=0:|<?php echo date(‘d/m’,$lastMonth) . ‘|’ . date(‘d/m’,$now); ?>|1:|0|<?php echo max($dateStats); ?>" />
<?php echo $monthCount; ?> pages crawled last 30 days</td>
                <?php if (!$show): ?>
                <td align="right" style="font-size: 11px;">
                    <?php $i = 0; foreach ($pageStats as $pagePath=>$pageCount): if ($i++ == 15) break; ?>
                    <a href="?show=<?php echo $pagePath; ?>" class="link"><?php echo "$pagePath : $pageCount"; ?></a>

                    <?php endforeach; ?>
                </td>
                <?php endif; ?>
            </tr>
        </table>
        <form action="?" method="post">
            <fieldset>
                <legend>Search for specific pages</legend>
                <label for="show">Page name (use * for wildcard) :</label>
                <input type="text" name="show" id="show" value="<?php echo $show; ?>" />
            </fieldset>
        </form>
        <table>
            <tr>
                <th>Date</th>
                <th>IP</th>
                <th>Host</th>
                <th>Method</th>
                <?php if ($show && (strpos($show,‘*’) === false)): ?>
                <th>Agent</th>
                <?php else: ?>
                <th>URL</th>
                <?php endif; ?>
                <th>Status</th>
            </tr>
            <?php foreach ($results as $k=>$v): ?>
            <tr class="<?php echo $v['status'] != 200 ? ‘error’ : ($k % 2 ? ‘odd’ : ‘even’); echo preg_match(‘#\.google(bot)?\.[a-z]+$#si’,$v['host']) ?  » : ‘ fake’; ?>"<?php if (!$show || (strpos($show,‘*’) !== false)): ?> title="Agent: <?php echo $v['agent']; ?>"<?php endif; ?>>
                <td align="center"><?php echo $v[‘date’]; ?></td>
                <td align="center"><?php echo $v[‘ip’]; ?></td>
                <td><?php echo $v[‘host’]; ?></td>
                <td align="center"><?php echo $v[‘method’]; ?></td>
                <?php if ($show && (strpos($show,‘*’) === false)): ?>
                <td><?php echo $v[‘agent’]; ?></td>
                <?php else: ?>
                <td><a href="?show=<?php echo $v['path']; ?>" class="link"><?php echo $v[‘url’]; ?></a></td>
                <?php endif; ?>
                <td align="center"><?php echo $v[’status’]; ?></td>
            </tr>
            <?php endforeach; ?>
        </table>
        <?php if ($paginationCount): ?>
        <div class="myPagination">
            <?php if ($start): ?>
            <a class="myPaginationLink" href="<?php echo $paginationUrl . ’start=’ . ($start-1); ?>">◄</a>
            <a class="myPaginationLink" href="<?php echo $paginationUrl . ’start=0′; ?>">1</a>
            <?php else: ?>
            <span class="myPaginationDisabled">◄</span>
            <span class="myPaginationSelected">1</span>
            <?php endif; ?>
           
            <?php
            $iStart = max(1,$start-2);
            $iStop = min($paginationCount,$start+3);
           
            if ($iStart != 1): ?>
            <span class="myPaginationEtc">…</span>
            <?php endif; ?>
           
            <?php for($i = $iStart; $i < $iStop; $i++): ?>
            <?php if ($i != $start): ?>
            <a class="myPaginationLink" href="<?php echo $paginationUrl . ’start=’ . $i; ?>"><?php echo ($i+1); ?></a>
            <?php else: ?>
            <span class="myPaginationSelected"><?php echo ($i+1); ?></span>
            <?php endif; ?>
            <?php endfor; ?>
           
            <?php if ($iStop != $paginationCount): ?>
            <span class="myPaginationEtc">…</span>
            <?php endif; ?>
           
            <?php if ($start < $paginationCount): ?>
            <a class="myPaginationLink" href="<?php echo $paginationUrl . ’start=’ . $paginationCount; ?>"><?php echo ($paginationCount+1); ?></a>
            <a class="myPaginationLink" href="<?php echo $paginationUrl . ’start=’ . ($start+1); ?>">►</a>
            <?php else: ?>
            <span class="myPaginationSelected"><?php echo ($paginationCount+1); ?></span>
            <span class="myPaginationDisabled">►</span>
            <?php endif; ?>
        </div>
        <?php endif; ?>
    </body>
</html>
 

Exemple de monitoring de Googlebot

Pour finir, je vous ai fait une copie d’écran du rendu final sur un site pour lequel j’utilise ce script de monitoring :

Cela reste bien sûr un outil d’appoint, codé à l’arrache je l’avoue, mais c’est néanmoins très pratique, notamment pour suivre l’indexation des nouvelles pages…

9 Responses à “Suivre l’activité de Googlebot sur votre site grâce aux logs Apache”

  1. Aurélien dit :

    Merci pour le script.

  2. Peter_P dit :

    Merci pour le script, ça faisait un moment que je cherchais.

  3. sid dit :

    Merci msieur !

  4. noreply dit :

    De rien Peter, merci à toi pour le lien sur le HUB :) J’y vais plus depuis un bail… Pas trop dur de supporter arlette and co ?
    Edit: Ahah je vois que c’est toujours bon esprit mon lien a disparu :p

  5. Peter_P dit :

    Salut, ton lien n’a pas été supprimé, il suffit juste de faire un copié collé pour ceux qui sont intéressé. Je le poste sur mon blog @ + Pierre

  6. Googlebot visite la page d'un article après publication | Conceptoulouse, création de site avec joomla dit :

    [...] vous propose d’aller faire un tour sur ce site, vous apprendrez quoi faire avec ces logs. Suivre l’activité de Googlebot sur votre site grâce aux logs Apache [...]

  7. Améliorez votre référencement ! | Conceptoulouse, création de site avec joomla dit :

    [...] Je me suis intéressé au référencement, et je me suis apperçu qu’avec un script qui enregistre toutes les visites de Googlebot dans un fichier, nous pouvons mesurer le temps qui s’écoulent entre la publication d’un billet et l’exploration de celui-ci par Googlebot. En savoir plus sur les pings. Retrouvez le script ici [...]

  8. Kyyple dit :

    Quelles sont les lignes à mettre dans la conf d’apache pour suivre l’activité des crawlers de Yahoo et de Bing ?

  9. Kyyple dit :

    Pour Bing çà fonctionne avec çà:

    SetEnvIfNoCase User-Agent « msnbot » msnbot
    LogFormat « %a %a %{%s}t %v %m %U %>s %{User-agent}i » msnbot
    CustomLog /chemin_vers_vos_logs/msnbot.log msnbot env=msnbot

Poster un commentaire