Множественное геокодирование с использованием API Яндекс.Карт
При работе над проектом с использованием API Яндекс.Карт возникает задача определения географических координат для множества точек.
Можно использовать для этого два подхода.
- Воспользоваться функцией геокодирования и каждый раз при выводе определять координаты объекта по его почтовому адресу.
У этого подхода есть два недостатка: геокодеру необходимо некоторое время на обработку запроса и ответ, еще количество обращений к сервису геокодирования ограничено 25000 запросов для одного API-Ключа в сутки.
2. Предварительно использовать сервис определения координат по адресу http://api.yandex.ru/maps/tools/getlonglat/
Если точек много, то вручную это очень утомительно.
Я предлагаю автоматизировать процесс определения координат.
Для этого мы будем использовать возможность формирования HTTP-запроса, подробнее смотри http://api.yandex.ru/maps/geocoder/doc/desc/concepts/geocode.xml
С начала мы в базе данных MySQL создадим таблицу для хранения информации об объектах.
Это можно сделать, используя утилиту PhpMyAdmin или SQL-запросом:
CREATE TABLE IF NOT EXISTS `markers_geocod` ( `id` int(11) NOT NULL auto_increment, `name` varchar(255) NOT NULL, `address` varchar(100) NOT NULL, `lat` varchar(255) NOT NULL, `lng` varchar(255) NOT NULL, `telephon` varchar(30) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
После этого заполняем таблицу тестовыми данными вида:
Наименование, адрес, координаты – долгота, широта (0.0, 0.0), номер телефона.
Для обработки ответа геокодера нам понадобиться работающее расширение php – библиотека curl (входит в состав php5).
Если Вы работаете на локальном компьютере необходимо убрать точку с запятой возле строки extension=php_curl.dll в файле php.ini и перезапустить сервер.
На хостинге данная библиотека, как правило, уже бывает задействовано.
Полный код примера:
<?php
set_time_limit(360);
require("config.php");
define("MAPS_HOST", "geocode-maps.yandex.ru");
define("KEY", "AIW0o0kBAAAAkwyUMwMAEkDz8ddCkU0UnlyLEu4ddFBXhQQAAAAAAAAAAAA1Md4ULCo5QbciEo5T26eV1lhuEQ==");
// Select all the rows in the markers table
$query = "SELECT * FROM markers_geocod";
$result = mysql_query($query);
if (!$result) {
die("Invalid query: " . mysql_error());
}
// Initialize delay in geocode speed
$delay = 0;
$base_url = "http://" . MAPS_HOST . "/1.x/?geocode=";
// Iterate through the rows, geocoding each address
while ($row = @mysql_fetch_array($result)) {
$exp_str1 = explode(",", $row["address"]);
$address = implode($exp_str1, ",+");
$id = $row["id"];
$request_url = $base_url . urlencode($address)."&key=" . KEY;
$ch = curl_init($request_url);
$fp = fopen("example_homepage.txt", "w+");
curl_setopt($ch, CURLOPT_FILE, $fp);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_exec($ch);
curl_close($ch);
fclose($fp);
$lines = file("example_homepage.txt");
if($lines[5] == '<ygeo:request>несуществующая улица</ygeo:request>'){
echo 'адрес: ', $row["address"], ' ', 'не найден', '<br><br>';
}
else
{
foreach ($lines as $line_num => $line)
{
if(strpos($line, "<pos>")!= FALSE)
{
echo "Строка #<b>{$line_num}</b> : " . htmlspecialchars($line) . "<br>";
$line = trim ($line);
$coord = substr($line, 5, -6);
echo $coord;
$newcoord = explode(" ", $coord);
$lat1 = $newcoord[1];
$lng1 = $newcoord[0];
echo '<br><br>';
$query = sprintf("UPDATE markers_geocod " .
" SET lat = '%s', lng = '%s' " .
" WHERE id = '%s' LIMIT 1;",
mysql_real_escape_string($lat1),
mysql_real_escape_string($lng1),
mysql_real_escape_string($id));
$update_result = mysql_query($query);
if (!$update_result) {
die("Invalid query: " . mysql_error());
}
}
}
echo '<br><br>';
}
}
?>С начала мы последовательно читаем из таблицы адреса объектов и формируем ссылку для запроса в формате http:// geocode-maps.yandex.ru /1.x/?geocode= строка с адресом, который требуется геокодировать в координаты &key= API-ключ Яндекс.Карт
После этого ответ геокодера мы записываем в файл example_homepage.txt и обрабатываем его, находим строку с координатами и заносим их в базу данных.
После этого мы можем сформировать из данных таблицы YMapsML-файл и вывести его на карте.
Еще одно замечание.
Если геокодер не нашел данный адрес в своей базе, он ищет ближайший по адресу.
Например, мы ищем дом по адресу Нижний Новгород, Казанское шоссе, 10/6, а геокодер определяет координаты дома по адресу Россия, Нижегородская область, Нижний Новгород, Казанское шоссе, 10.
Поэтому, после автоматического геокодирования необходимо провести проверку.


22 ноября 2009 в 20:12
Огромное спасибо автору этого сайта за отличный материал по Картам.
Я мучился с Яндекс.картами очень долгое время и много было непонятного. На оф.сайте карт настолько запутанная документация что разобраться в ней для меня составило многих недель изучения, а вот у вас на сайте Описано и даны примеры. Я в восторге.
Еще раз спасибо!
19 января 2010 в 19:06
Здравствуйте, я начал делать по вашему примеру на Денвере. Нашел в файле php.ini нужную строку, убрал точку с запятой, перезапустил сервер, но вылетает ошибка: Fatal error: Call to undefined function curl_init() in Z:\home\localhost\www\myphp\config_2.php. Как видно не найдена функция curl_init() …Подскажите, что делать?
19 января 2010 в 21:56
Я извиняюсь, что забыл написать следующее. Поддержка функции curl_init() отсутствует в Денвере. Чтобы все нормально работало не достаточно убрать точку с запятой, нужно скачать полную версию PHP с сайта http://www.php.net/downloads.php — файл PHP 5.2.12 zip package [10,268Kb] — 17 December 2009
Разархивировать его и все содержимое папки php-5.2.12-Win32 скопировать в папку Имя диска:WebServers\usr\local\php5\ Денвера, после чего перезапустить сервер.
20 января 2010 в 21:01
Хорошее дополнение. Надо на локальном сделать. Спасибо всем! Особенно admin!
2 июля 2010 в 13:01
Здравствуйте У меня такая ошибка вылезла:
Warning: mysql_query() [function.mysql-query]: Access denied for user ‘ODBC’@'localhost’ (using password: NO) in Z:\home\geo.loc\www\index.php on line 13
Warning: mysql_query() [function.mysql-query]: A link to the server could not be established in Z:\home\geo.loc\www\index.php on line 13
Invalid query: Access denied for user ‘ODBC’@'localhost’ (using password: NO)
2 июля 2010 в 13:29
Вы в файле config.php правильно прописали параметры для соединения с базой данных: имя бд, имя пользователя и пароль?
28 февраля 2011 в 18:28
Здравствуйте!
Ваш вариант множественного геокодирования возвращает несколько вариантов координат, по какому принципу выбирается единственный, который заносится в таблицу?
Как можно задать зону поиска, например Москву?
Спасибо заранее.
28 февраля 2011 в 23:18
Нужно ограничить область поиска, для этого у геокодера существует параметр boundedBy, подробнее см. статью Как ограничить область поиска?. У html-геокодера, который используется в скрипте заметки, задать область поиска можно с помощью параметров ll и spn, а с помощью параметра rspn ограничить поиск только заданной областью. Подробнее о параметрах здесь
26 мая 2011 в 18:08
Добрый день!
Еще один вопрос по геокодеру. Если взять для примера адрес: Ленинский 53 и геокодировать его непосредственно через сайт maps.yandex.ru, то в результате выдается Россия, Москва, Ленинский проспект, 53с1 или http://maps.yandex.ru/-/CBQnuLZj . В случае использования представленного геокодера или использования сервиса — http://api.yandex.ru/maps/tools/getlonglat/ выдается: Ленинский проезд, Россия, Московская область, Юбилейный. И так по многим адресам… С чем это может быть связано?