Если условно брать topvisor, то он может показывать постоянно топ-1 позицию но это может быть далеко не так. Либо перемешивание позиций в течении дня от топ-1 до топ-10 в моменте. Из-за этого посмотреть реальную позицию сайта текущими сервисами фактически нереально.
В вебмастере относительно недавно появилась функция мониторинг запросом, до этого Яндекс мог отдавать данные только по API
Но данная система на текущий момент сырая и плохо читаемая:
Но в любом случае это лучше чем ничего.
Яндекс позволяет выгружать данные вебмастера по API, и он позволяет получить довольно полезные данные.
Для выгрузки с API подойдет небольшой php класс который отлично выгружает данные в удобном виде для работы.
<?php
class YandexWebmaster
{
public $parametrs = array();
function __construct()
{
$this->token;
$this->token_webmaster;
$this->user_id;
$this->url = "";
$this->url_path_config = "";
$this->answer = array();
$this->parametrs = [];
$this->parametrs_webmaster = [];
}
public function GetFromWebmaster() {
$parametrs = []+$this->parametrs_webmaster;
$this->GetCurlWebmaster($parametrs);
return($this->answer);
}
public function GetFromWebmasterData ($method, $parametrs = array()) {
$this->url = "https://api.webmaster.yandex.net/v4.1/user/{$this->user_id}/hosts{$method}";
$this->parametrs_webmaster = $parametrs;
return (object) $this->GetFromWebmaster();
}
public function GetCurlWebmaster($parametrs) {
$get = curl_init($this->url . urldecode($this->http_build_query_multi($parametrs)));
curl_setopt($get, CURLOPT_HTTPHEADER, array('Authorization: OAuth '.$this->token_webmaster));
curl_setopt($get, CURLOPT_RETURNTRANSFER, true);
curl_setopt($get, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($get, CURLOPT_HEADER, false);
$result = curl_exec($get);
curl_close($get);
$result = json_decode($result, true);
$this->answer=$result;
if ($result['error_code'] == 'INVALID_OAUTH_TOKEN') {
echo 'ОШИБКА: Авторизация к API webmaster не выполнена. Невалидный токен.' .PHP_EOL;
} elseif ($result['error_code'] == 'INVALID_USER_ID') {
echo 'ОШИБКА: Авторизация к API webmaster не выполнена. Невалидный юзер ид вебмастера.' .PHP_EOL;
}
}
// Ключи с вебмастера
public function webmaster_popular_words_data ($host, $start_day, $end_day, $offset, $limit) {
$method = "/{$host}/search-queries/popular?";
$parametrs = [
'order_by' => 'TOTAL_SHOWS',
'date_from' => $start_day,
'date_to' => $end_day,
'offset' => $offset,
'query_indicator' => ['TOTAL_SHOWS', 'TOTAL_CLICKS', 'AVG_SHOW_POSITION', 'AVG_CLICK_POSITION'],
'device_type_indicator' => ['ALL'],
'limit' => $limit,
];
$webmaster_day_data = $this -> GetFromWebmasterData($method, $parametrs);
if ($webmaster_day_data->queries) {
//echo "Собрано ключей с вебмастера: {$host} | {$start_day} | {$limit}" .PHP_EOL;
}
$data_words_key = [];
if ($webmaster_day_data->queries) {
foreach ($webmaster_day_data->queries as $value) {
$word_key = $value['query_text'];
$shows = $value['indicators']['TOTAL_SHOWS'];
$click = $value['indicators']['TOTAL_CLICKS'];
$avg_show = $value['indicators']['AVG_SHOW_POSITION'];
$avg_click = $value['indicators']['AVG_CLICK_POSITION'];
$data_words_key[$word_key] = array('shows' => $shows, 'click' => $click, 'avg_show' => $avg_show, 'avg_click' => $avg_click);
}
}
return $data_words_key;
}
public function data_webmaster($config_data = array()) {
$period_date_list = $this->getDatesFromRange($config_data['date'], $config_data['end_date']);
$data = [];
foreach ($period_date_list as $date) {
$config_data['date'] = $date;
$data[$date] = $this -> freq_data_webmaster($config_data);
}
return $data;
}
public function freq_data_webmaster($config_data = array()) {
$this->token_webmaster = $config_data['token_webmaster'];
$this->user_id = $config_data['user_id'];
$host = "https:{$config_data['domain']}:443";
$count_days = 1;
$webmaster_data = call_user_func_array('array_replace_recursive', $this->freq_data_webmaster_per_day($host, $config_data['date'], $config_data['date'], $config_data['limit'], $config_data['pages']));
$freq_data = [];
foreach ($webmaster_data as $word_key => $word_data) {
$ctr = ($word_data['click'] / $word_data['shows']) * 100;
$word_key_clean = $this->strpos_array($word_key, $config_data['bad_keys_arr']);
if ($word_data['shows'] >= $min_shows && $word_key_clean == NULL) {
$freq_data[$word_key] = array(
'webmaster_freq' => round($word_data['shows'] / $count_days, 0, PHP_ROUND_HALF_UP),
'webmaster_click' => round($word_data['click'] / $count_days, 0, PHP_ROUND_HALF_UP),
'webmaster_avg_click' => round($word_data['avg_click'], 1, PHP_ROUND_HALF_UP),
'webmaster_avg_show' => round($word_data['avg_show'], 1, PHP_ROUND_HALF_UP),
'webmaster_ctr' => round($ctr, 1, PHP_ROUND_HALF_UP),);
}
}
foreach ($freq_data as $word_key => $value) {
if ($value['webmaster_freq'] > 0) {
$total_avg_pos = ($value['webmaster_avg_click'] + $value['webmaster_avg_show']) / 2;
$total_data_ya_webmaster[$word_key] = array(
'wm_freq_avg' => (int)$value['webmaster_freq'],
'wm_visit_avg' => (int)$value['webmaster_click'],
'wm_avg_click' => (float)$value['webmaster_avg_click'],
'wm_avg_show' => (float)$value['webmaster_avg_show'],
'total_avg_pos' => (float)round($total_avg_pos, 1, PHP_ROUND_HALF_UP),
'wm_ctr' => (float)$value['webmaster_ctr']
);
}
}
return $total_data_ya_webmaster;
}
public function http_build_query_multi($array, $qs='',$index = false) {
foreach($array as $par => $val)
{
if($index)
$par = $index;
if(is_array($val))
{
$qs = $this->http_build_query_multi($val, $qs,$par);
}
else
{
$qs .= $par.'='.$val.'&';
}
}
return $qs;
}
public function getDatesFromRange($start, $end, $format = 'Y-m-d') {
$array = array();
$interval = new DateInterval('P1D');
$realEnd = new DateTime($end);
$realEnd->add($interval);
$period = new DatePeriod(new DateTime($start), $interval, $realEnd);
foreach($period as $date) {
$array[] = $date->format($format);
}
return $array;
}
public function strpos_array($haystack, $needles) {
if ( is_array($needles) ) {
foreach ($needles as $str) {
if ( is_array($str) ) {
$pos = strpos_array($haystack, $str);
} else {
$pos = mb_strpos($haystack, $str);
}
if ($pos !== FALSE) {
return $pos;
}
}
} else {
return mb_strpos($haystack, $needles);
}
}
public function freq_data_webmaster_per_day($host, $start_day, $end_day, $limit, $pages) {
$i = 0;
$webmaster_data_arr = [];
$limit = $limit;
$offset = $limit;
$limit_split = $pages;
for ($i = 0; ; $i++) {
if ($i === 0) {
$offset_i = 0;
} else {
$offset_i = $i*$offset;
}
$webmaster_data_arr[$i] = $this->webmaster_popular_words_data ($host, $start_day, $end_day, $offset_i, $limit);
if (empty($webmaster_data_arr[$i])) {
echo 'BREAK 1';
}
if ($i == $limit_split) {
break;
}
}
return $webmaster_data_arr;
}
}
?>
Получение данных и прототип таблички.
<?php
require_once 'YandexWebmaster.class.php'; // файл с классом
$config_data = array(
'token_webmaster' => 'XXXXXXXXXXX-XXXXXXXXXXX', //токен https://oauth.yandex.ru/client/new
'user_id' => 'user_id', //user id от токена
'date' => '2023-06-01', // начальная дата с которой будем собирать данные
'end_date' => '2023-06-03', // конечная
'domain' => 'domain.com', // имя домена
'limit' => 10, // количество запросов (от меньшего к большему максимально 500)
'pages' => 0, // страницы, до 5 страниц т.е 3000 запросов (считается от 0)
'bad_keys_arr' => array('.','-') //стоп слова для фильтрации
);
$YandexWebmaster = new YandexWebmaster();
$webmaster_data = $YandexWebmaster->data_webmaster($config_data);
?>
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
</head>
<body>
<div class="container">
<table class="table">
<thead>
<tr>
<th scope="col">Запрос</th>
<th scope="col">Частота в день</th>
<?php
// Динамическое создание заголовков таблицы с датами
foreach($webmaster_data as $date => $data) {
echo "<th scope='col'>{$date}</th>";
}
?>
</tr>
</thead>
<tbody>
<?php
// Сбор всех уникальных запросов
$allQueries = [];
foreach($webmaster_data as $data) {
foreach($data as $query => $query_data) {
if(!in_array($query, $allQueries)) {
$allQueries[] = $query;
}
}
}
// Создание строки для каждого запроса
foreach($allQueries as $query) {
echo "<tr>";
echo "<td>{$query}</td>";
// Общая частота в день для запроса
$totalFreq = 0;
$daysCount = 0;
foreach($webmaster_data as $data) {
if(isset($data[$query])) {
$totalFreq += $data[$query]['wm_freq_avg'];
$daysCount++;
}
}
$avgFreq = round($totalFreq / $daysCount, 0, PHP_ROUND_HALF_UP);
echo "<td>{$avgFreq}</td>";
// Данные для каждой даты
foreach($webmaster_data as $data) {
if(isset($data[$query])) {
echo "<td><small>Позиция просмотра {$data[$query]['wm_avg_show']} <br> Поз.кл {$data[$query]['wm_avg_click']} <br> CTR {$data[$query]['wm_ctr']}<br> Визитов {$data[$query]['wm_visit_avg']}</small></td>".PHP_EOL;
} else {
echo "<td></td>";
}
}
echo "</tr>";
}
?>
</tbody>
</table>
</div>
</body>
</html>
Минусы:
Плюсы: