📜 ⬆️ ⬇️

We solve the housing problem using the Yandex.Maps API

In the life of even the most "terry" IT-Schnick sometimes comes the moment when you need not only to get out of your lair on the street, but to transfer yourself to a new place of residence. An ordinary person in such cases is armed with the Internet and combing real estate sites in search of suitable options, which are marked on the map, written out or printed, and then systematically called. If the end of the cycle comes, and the task has not yet been completed - goto line 1 ... And at some stage it bothers the person and he goes to the agency.

So in my life it was time to move, but after spending a few days after such a routine activity, I remembered that not knowingly wearing a beard is such a wonderful service as Yandex.Maps , and they have a no less wonderful API . After sitting one morning and combining everything with a simple grabber for PHP and XPath, I received such a colorful map, where you can mark objects (apartments) with different markers according to any of the criteria, or just one look at which of them are closer to the desired location. in my case it was the subway):

Screenshot
')


I must say that for me this is the first experience of finding an apartment and therefore I may not know about the service doing something like this - however, after several days of searching I did not find anything like this on the secondary real estate market. And I would find - there would be no reason to write this post, so we will continue as soon as possible, until one of the habrayers inserts his weighty "nya" ...

Grabber


We’ll take information from the Real Estate Bulletin website: they have a convenient search with a bunch of filters, but no map, which is very problematic for people like me who don’t know every street as a souvenir.

The site has the ability to view all search results (no more than 300) on one page in print mode - this is what we will use. URL has the following form:
 http://www.bn.ru/zap_fl.phtml?print=printall&_ 


Suppose we got a page with the desired results on the filter. How to get out of her list of apartments? I usually solve this problem with regulars, but this site has some special non -HTML structure, so it turned out to be easier to use XPath ( W3Schools ). With its help, it is easy to get a list of rows in a table ( ), - , , DOMNode .

:
// . $all = array(); $baseURL = 'http://www.bn.ru/zap_fl.phtml?print=printall&'; // , . $empty = iconv('utf-8', 'cp1251', ' 0'); // . foreach ((array) $_REQUEST['region'] as $region) { $url = $baseURL."region$region=$region&"; // ... // , 300 - // , 300. foreach (range(0, 10000, 1000) as $price0) { $reqURL = $url."price1=$price0&price2=".($price0 + 999); // - . . $data = dl($reqURL); if (!strpos($data, $empty)) { // . $offers = parse($data); $all = array_merge($all, $offers); } // . usleep(200000); } }

dl() cURL file_get_contents() - , , .

parse() HTML .
function parse($html) { // DOMDocument, UTF-8 ( , // ). $html = '<?xml encoding="UTF-8">'.iconv('cp1251', 'utf-8', $html); $doc = new DOMDocument('1.0', 'utf-8'); @$doc->loadHTML($html) or die('loadHTML: '.$html); // . $xpath = new DOMXPath($doc); // , - // () , . $nodes = $xpath->query('//table[@class="results"]/tr[th[@class="head_kvart"] or td[@width or @class="tooltip"]]'); // . $results = array(); // (, ) - // . $roomCount = 1; // $nodes - - (tr). foreach ($nodes as $row) { // - , .. $cells = array(); $cell = $row->firstChild; while ($cell) { $cell->nodeType == XML_ELEMENT_NODE and $cells[] = trim($cell->nodeValue); $cell = $cell->nextSibling; } if (count($cells) == 1) { // - // . . $roomCount = (int) reset($cells); } else { $cells[0] = $roomCount; // colspan - // . if (count($cells) == 10) { array_splice($cells, 6, 1, array(0, '', $cells[6], '')); } // , . $html = $row->ownerDocument->saveXML($row); if (preg_match('~<a href="([^"]+)~u', $html, $match)) { array_unshift($cells, 'http://www.bn.ru'.$match[1]); } else { array_unshift($cells, ''); } // , . $keys = array('url', 'rooms', 'address', 'floors', 'houseType', 'area', 'areaLiving', 'areaKitchen', 'toilet', 'price', 'conditions', 'seller', 'phone', 'notes'); $result[] = array_combine($keys, $cells); } } return $result; }


, - $all . - . :
array( 'url' => 'http://www.bn.ru/detail/flats/xxxxxx.html?from=search', 'rooms' => 1, 'address' => '7 ., xxx', 'floors' => '1\\5', 'houseType' => '', 'area' => '30', 'areaLiving' => '18.3', 'areaKitchen' => '6', 'toilet' => ' ', 'price' => '3100', 'conditions' => ' ', 'seller' => 'xxxxx ', 'phone' => '(965) xxxxxxx', 'notes' => ' ', )

HTML .:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Map grabber</title> <script src="//api-maps.yandex.ru/2.0/?load=package.standard&lang=ru-RU" type="text/javascript"></script> <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script> <style> html, body, .#map { margin: 0; padding: 0; } #map { width: 100%; height: 800px; } </style> </head> <body> <div id="map"></div> </body> </html>

jQuery , .

, . JavaScript :
// . var coords = [] // . var info = [] <?foreach ($all as $offer) {?> coords.push('-, <?=$offer['address']?>') info.push(<?=json_encode($offer, JSON_UNESCAPED_UNICODE)?>) <?}?> ymaps.ready(init);

- init() . MultiGeocoder API ; ( coords ), ( ), .

function init() { // -: var map = new ymaps.Map('map', { center: [59.932666, 30.329596], zoom: 13, behaviors: ['default', 'scrollZoom'], }) // : map.controls .add('zoomControl', {left: 5, top: 5}) .add('mapTools', {left: 35, top: 5}) // . (new MultiGeocoder({boundedBy: map.getBounds()})) .geocode(coords) .then( function (res) { // . for (var i = 0; i < res.geoObjects.getLength(); i++) { var cells = info[i] // - // , . var text = '<p>' + $('<b>').append( $('<a>') .attr({href: cells.url, target: '_blank'}) .text(cells.address) )[0].outerHTML + '</p>' // - , . var geo = res.geoObjects.get(i) // . info[i].geo = geo // . geo.properties.set('balloonContentBody', text) } // . map.geoObjects.add(res.geoObjects) }, function (err) { alert(err) } ) return map }

. . , .


?..
, , . ! , , , .

JavaScript , . , . , , , - , , - , .

- . ( API ):
// [ [_, _], ... ]. var markers = [] // <p data-marker="twirl#redDotIcon">. // twirl#redDotIcon - (preset) . $('p[data-marker] input').val(function (i, value) { var marker = $(this).parent().attr('data-marker') value = $.trim(value) value && markers.push([marker, value]) return value }) // (. init()). cells - {price: 123, rooms: 2, ...}. $.each(info, function (i, cells) { var colored = false for (var i = 0; i < markers.length && !colored; i++) { var item = markers[i] var func = new Function('cells', 'return ' + item[1]); // - , . if (func(cells)) { cells.geo.options.set('preset', item[0]) // . colored = true } } // - . colored || cells.geo.options.set('preset', 'twirl#blueIcon') })

, , -, !

, . , .

UPD: Gist . , :)
), - , , DOMNode .

:
// . $all = array(); $baseURL = 'http://www.bn.ru/zap_fl.phtml?print=printall&'; // , . $empty = iconv('utf-8', 'cp1251', ' 0'); // . foreach ((array) $_REQUEST['region'] as $region) { $url = $baseURL."region$region=$region&"; // ... // , 300 - // , 300. foreach (range(0, 10000, 1000) as $price0) { $reqURL = $url."price1=$price0&price2=".($price0 + 999); // - . . $data = dl($reqURL); if (!strpos($data, $empty)) { // . $offers = parse($data); $all = array_merge($all, $offers); } // . usleep(200000); } }

dl() cURL file_get_contents() - , , .

parse() HTML .
function parse($html) { // DOMDocument, UTF-8 ( , // ). $html = '<?xml encoding="UTF-8">'.iconv('cp1251', 'utf-8', $html); $doc = new DOMDocument('1.0', 'utf-8'); @$doc->loadHTML($html) or die('loadHTML: '.$html); // . $xpath = new DOMXPath($doc); // , - // () , . $nodes = $xpath->query('//table[@class="results"]/tr[th[@class="head_kvart"] or td[@width or @class="tooltip"]]'); // . $results = array(); // (, ) - // . $roomCount = 1; // $nodes - - (tr). foreach ($nodes as $row) { // - , .. $cells = array(); $cell = $row->firstChild; while ($cell) { $cell->nodeType == XML_ELEMENT_NODE and $cells[] = trim($cell->nodeValue); $cell = $cell->nextSibling; } if (count($cells) == 1) { // - // . . $roomCount = (int) reset($cells); } else { $cells[0] = $roomCount; // colspan - // . if (count($cells) == 10) { array_splice($cells, 6, 1, array(0, '', $cells[6], '')); } // , . $html = $row->ownerDocument->saveXML($row); if (preg_match('~<a href="([^"]+)~u', $html, $match)) { array_unshift($cells, 'http://www.bn.ru'.$match[1]); } else { array_unshift($cells, ''); } // , . $keys = array('url', 'rooms', 'address', 'floors', 'houseType', 'area', 'areaLiving', 'areaKitchen', 'toilet', 'price', 'conditions', 'seller', 'phone', 'notes'); $result[] = array_combine($keys, $cells); } } return $result; }


, - $all . - . :
array( 'url' => 'http://www.bn.ru/detail/flats/xxxxxx.html?from=search', 'rooms' => 1, 'address' => '7 ., xxx', 'floors' => '1\\5', 'houseType' => '', 'area' => '30', 'areaLiving' => '18.3', 'areaKitchen' => '6', 'toilet' => ' ', 'price' => '3100', 'conditions' => ' ', 'seller' => 'xxxxx ', 'phone' => '(965) xxxxxxx', 'notes' => ' ', )

HTML .:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Map grabber</title> <script src="//api-maps.yandex.ru/2.0/?load=package.standard&lang=ru-RU" type="text/javascript"></script> <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script> <style> html, body, .#map { margin: 0; padding: 0; } #map { width: 100%; height: 800px; } </style> </head> <body> <div id="map"></div> </body> </html>

jQuery , .

, . JavaScript :
// . var coords = [] // . var info = [] <?foreach ($all as $offer) {?> coords.push('-, <?=$offer['address']?>') info.push(<?=json_encode($offer, JSON_UNESCAPED_UNICODE)?>) <?}?> ymaps.ready(init);

- init() . MultiGeocoder API ; ( coords ), ( ), .

function init() { // -: var map = new ymaps.Map('map', { center: [59.932666, 30.329596], zoom: 13, behaviors: ['default', 'scrollZoom'], }) // : map.controls .add('zoomControl', {left: 5, top: 5}) .add('mapTools', {left: 35, top: 5}) // . (new MultiGeocoder({boundedBy: map.getBounds()})) .geocode(coords) .then( function (res) { // . for (var i = 0; i < res.geoObjects.getLength(); i++) { var cells = info[i] // - // , . var text = '<p>' + $('<b>').append( $('<a>') .attr({href: cells.url, target: '_blank'}) .text(cells.address) )[0].outerHTML + '</p>' // - , . var geo = res.geoObjects.get(i) // . info[i].geo = geo // . geo.properties.set('balloonContentBody', text) } // . map.geoObjects.add(res.geoObjects) }, function (err) { alert(err) } ) return map }

. . , .


?..
, , . ! , , , .

JavaScript , . , . , , , - , , - , .

- . ( API ):
// [ [_, _], ... ]. var markers = [] // <p data-marker="twirl#redDotIcon">. // twirl#redDotIcon - (preset) . $('p[data-marker] input').val(function (i, value) { var marker = $(this).parent().attr('data-marker') value = $.trim(value) value && markers.push([marker, value]) return value }) // (. init()). cells - {price: 123, rooms: 2, ...}. $.each(info, function (i, cells) { var colored = false for (var i = 0; i < markers.length && !colored; i++) { var item = markers[i] var func = new Function('cells', 'return ' + item[1]); // - , . if (func(cells)) { cells.geo.options.set('preset', item[0]) // . colored = true } } // - . colored || cells.geo.options.set('preset', 'twirl#blueIcon') })

, , -, !

, . , .

UPD: Gist . , :)
 ),    -   ,   ,    DOMNode . 

:
// . $all = array(); $baseURL = 'http://www.bn.ru/zap_fl.phtml?print=printall&'; // , . $empty = iconv('utf-8', 'cp1251', ' 0'); // . foreach ((array) $_REQUEST['region'] as $region) { $url = $baseURL."region$region=$region&"; // ... // , 300 - // , 300. foreach (range(0, 10000, 1000) as $price0) { $reqURL = $url."price1=$price0&price2=".($price0 + 999); // - . . $data = dl($reqURL); if (!strpos($data, $empty)) { // . $offers = parse($data); $all = array_merge($all, $offers); } // . usleep(200000); } }

dl() cURL file_get_contents() - , , .

parse() HTML .
function parse($html) { // DOMDocument, UTF-8 ( , // ). $html = '<?xml encoding="UTF-8">'.iconv('cp1251', 'utf-8', $html); $doc = new DOMDocument('1.0', 'utf-8'); @$doc->loadHTML($html) or die('loadHTML: '.$html); // . $xpath = new DOMXPath($doc); // , - // () , . $nodes = $xpath->query('//table[@class="results"]/tr[th[@class="head_kvart"] or td[@width or @class="tooltip"]]'); // . $results = array(); // (, ) - // . $roomCount = 1; // $nodes - - (tr). foreach ($nodes as $row) { // - , .. $cells = array(); $cell = $row->firstChild; while ($cell) { $cell->nodeType == XML_ELEMENT_NODE and $cells[] = trim($cell->nodeValue); $cell = $cell->nextSibling; } if (count($cells) == 1) { // - // . . $roomCount = (int) reset($cells); } else { $cells[0] = $roomCount; // colspan - // . if (count($cells) == 10) { array_splice($cells, 6, 1, array(0, '', $cells[6], '')); } // , . $html = $row->ownerDocument->saveXML($row); if (preg_match('~<a href="([^"]+)~u', $html, $match)) { array_unshift($cells, 'http://www.bn.ru'.$match[1]); } else { array_unshift($cells, ''); } // , . $keys = array('url', 'rooms', 'address', 'floors', 'houseType', 'area', 'areaLiving', 'areaKitchen', 'toilet', 'price', 'conditions', 'seller', 'phone', 'notes'); $result[] = array_combine($keys, $cells); } } return $result; }


, - $all . - . :
array( 'url' => 'http://www.bn.ru/detail/flats/xxxxxx.html?from=search', 'rooms' => 1, 'address' => '7 ., xxx', 'floors' => '1\\5', 'houseType' => '', 'area' => '30', 'areaLiving' => '18.3', 'areaKitchen' => '6', 'toilet' => ' ', 'price' => '3100', 'conditions' => ' ', 'seller' => 'xxxxx ', 'phone' => '(965) xxxxxxx', 'notes' => ' ', )

HTML .:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Map grabber</title> <script src="//api-maps.yandex.ru/2.0/?load=package.standard&lang=ru-RU" type="text/javascript"></script> <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script> <style> html, body, .#map { margin: 0; padding: 0; } #map { width: 100%; height: 800px; } </style> </head> <body> <div id="map"></div> </body> </html>

jQuery , .

, . JavaScript :
// . var coords = [] // . var info = [] <?foreach ($all as $offer) {?> coords.push('-, <?=$offer['address']?>') info.push(<?=json_encode($offer, JSON_UNESCAPED_UNICODE)?>) <?}?> ymaps.ready(init);

- init() . MultiGeocoder API ; ( coords ), ( ), .

function init() { // -: var map = new ymaps.Map('map', { center: [59.932666, 30.329596], zoom: 13, behaviors: ['default', 'scrollZoom'], }) // : map.controls .add('zoomControl', {left: 5, top: 5}) .add('mapTools', {left: 35, top: 5}) // . (new MultiGeocoder({boundedBy: map.getBounds()})) .geocode(coords) .then( function (res) { // . for (var i = 0; i < res.geoObjects.getLength(); i++) { var cells = info[i] // - // , . var text = '<p>' + $('<b>').append( $('<a>') .attr({href: cells.url, target: '_blank'}) .text(cells.address) )[0].outerHTML + '</p>' // - , . var geo = res.geoObjects.get(i) // . info[i].geo = geo // . geo.properties.set('balloonContentBody', text) } // . map.geoObjects.add(res.geoObjects) }, function (err) { alert(err) } ) return map }

. . , .


?..
, , . ! , , , .

JavaScript , . , . , , , - , , - , .

- . ( API ):
// [ [_, _], ... ]. var markers = [] // <p data-marker="twirl#redDotIcon">. // twirl#redDotIcon - (preset) . $('p[data-marker] input').val(function (i, value) { var marker = $(this).parent().attr('data-marker') value = $.trim(value) value && markers.push([marker, value]) return value }) // (. init()). cells - {price: 123, rooms: 2, ...}. $.each(info, function (i, cells) { var colored = false for (var i = 0; i < markers.length && !colored; i++) { var item = markers[i] var func = new Function('cells', 'return ' + item[1]); // - , . if (func(cells)) { cells.geo.options.set('preset', item[0]) // . colored = true } } // - . colored || cells.geo.options.set('preset', 'twirl#blueIcon') })

, , -, !

, . , .

UPD: Gist . , :)
), - , , DOMNode .

:
// . $all = array(); $baseURL = 'http://www.bn.ru/zap_fl.phtml?print=printall&'; // , . $empty = iconv('utf-8', 'cp1251', ' 0'); // . foreach ((array) $_REQUEST['region'] as $region) { $url = $baseURL."region$region=$region&"; // ... // , 300 - // , 300. foreach (range(0, 10000, 1000) as $price0) { $reqURL = $url."price1=$price0&price2=".($price0 + 999); // - . . $data = dl($reqURL); if (!strpos($data, $empty)) { // . $offers = parse($data); $all = array_merge($all, $offers); } // . usleep(200000); } }

dl() cURL file_get_contents() - , , .

parse() HTML .
function parse($html) { // DOMDocument, UTF-8 ( , // ). $html = '<?xml encoding="UTF-8">'.iconv('cp1251', 'utf-8', $html); $doc = new DOMDocument('1.0', 'utf-8'); @$doc->loadHTML($html) or die('loadHTML: '.$html); // . $xpath = new DOMXPath($doc); // , - // () , . $nodes = $xpath->query('//table[@class="results"]/tr[th[@class="head_kvart"] or td[@width or @class="tooltip"]]'); // . $results = array(); // (, ) - // . $roomCount = 1; // $nodes - - (tr). foreach ($nodes as $row) { // - , .. $cells = array(); $cell = $row->firstChild; while ($cell) { $cell->nodeType == XML_ELEMENT_NODE and $cells[] = trim($cell->nodeValue); $cell = $cell->nextSibling; } if (count($cells) == 1) { // - // . . $roomCount = (int) reset($cells); } else { $cells[0] = $roomCount; // colspan - // . if (count($cells) == 10) { array_splice($cells, 6, 1, array(0, '', $cells[6], '')); } // , . $html = $row->ownerDocument->saveXML($row); if (preg_match('~<a href="([^"]+)~u', $html, $match)) { array_unshift($cells, 'http://www.bn.ru'.$match[1]); } else { array_unshift($cells, ''); } // , . $keys = array('url', 'rooms', 'address', 'floors', 'houseType', 'area', 'areaLiving', 'areaKitchen', 'toilet', 'price', 'conditions', 'seller', 'phone', 'notes'); $result[] = array_combine($keys, $cells); } } return $result; }


, - $all . - . :
array( 'url' => 'http://www.bn.ru/detail/flats/xxxxxx.html?from=search', 'rooms' => 1, 'address' => '7 ., xxx', 'floors' => '1\\5', 'houseType' => '', 'area' => '30', 'areaLiving' => '18.3', 'areaKitchen' => '6', 'toilet' => ' ', 'price' => '3100', 'conditions' => ' ', 'seller' => 'xxxxx ', 'phone' => '(965) xxxxxxx', 'notes' => ' ', )

HTML .:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Map grabber</title> <script src="//api-maps.yandex.ru/2.0/?load=package.standard&lang=ru-RU" type="text/javascript"></script> <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script> <style> html, body, .#map { margin: 0; padding: 0; } #map { width: 100%; height: 800px; } </style> </head> <body> <div id="map"></div> </body> </html>

jQuery , .

, . JavaScript :
// . var coords = [] // . var info = [] <?foreach ($all as $offer) {?> coords.push('-, <?=$offer['address']?>') info.push(<?=json_encode($offer, JSON_UNESCAPED_UNICODE)?>) <?}?> ymaps.ready(init);

- init() . MultiGeocoder API ; ( coords ), ( ), .

function init() { // -: var map = new ymaps.Map('map', { center: [59.932666, 30.329596], zoom: 13, behaviors: ['default', 'scrollZoom'], }) // : map.controls .add('zoomControl', {left: 5, top: 5}) .add('mapTools', {left: 35, top: 5}) // . (new MultiGeocoder({boundedBy: map.getBounds()})) .geocode(coords) .then( function (res) { // . for (var i = 0; i < res.geoObjects.getLength(); i++) { var cells = info[i] // - // , . var text = '<p>' + $('<b>').append( $('<a>') .attr({href: cells.url, target: '_blank'}) .text(cells.address) )[0].outerHTML + '</p>' // - , . var geo = res.geoObjects.get(i) // . info[i].geo = geo // . geo.properties.set('balloonContentBody', text) } // . map.geoObjects.add(res.geoObjects) }, function (err) { alert(err) } ) return map }

. . , .


?..
, , . ! , , , .

JavaScript , . , . , , , - , , - , .

- . ( API ):
// [ [_, _], ... ]. var markers = [] // <p data-marker="twirl#redDotIcon">. // twirl#redDotIcon - (preset) . $('p[data-marker] input').val(function (i, value) { var marker = $(this).parent().attr('data-marker') value = $.trim(value) value && markers.push([marker, value]) return value }) // (. init()). cells - {price: 123, rooms: 2, ...}. $.each(info, function (i, cells) { var colored = false for (var i = 0; i < markers.length && !colored; i++) { var item = markers[i] var func = new Function('cells', 'return ' + item[1]); // - , . if (func(cells)) { cells.geo.options.set('preset', item[0]) // . colored = true } } // - . colored || cells.geo.options.set('preset', 'twirl#blueIcon') })

, , -, !

, . , .

UPD: Gist . , :)
 ),    -   ,   ,    DOMNode . 

:
// . $all = array(); $baseURL = 'http://www.bn.ru/zap_fl.phtml?print=printall&'; // , . $empty = iconv('utf-8', 'cp1251', ' 0'); // . foreach ((array) $_REQUEST['region'] as $region) { $url = $baseURL."region$region=$region&"; // ... // , 300 - // , 300. foreach (range(0, 10000, 1000) as $price0) { $reqURL = $url."price1=$price0&price2=".($price0 + 999); // - . . $data = dl($reqURL); if (!strpos($data, $empty)) { // . $offers = parse($data); $all = array_merge($all, $offers); } // . usleep(200000); } }

dl() cURL file_get_contents() - , , .

parse() HTML .
function parse($html) { // DOMDocument, UTF-8 ( , // ). $html = '<?xml encoding="UTF-8">'.iconv('cp1251', 'utf-8', $html); $doc = new DOMDocument('1.0', 'utf-8'); @$doc->loadHTML($html) or die('loadHTML: '.$html); // . $xpath = new DOMXPath($doc); // , - // () , . $nodes = $xpath->query('//table[@class="results"]/tr[th[@class="head_kvart"] or td[@width or @class="tooltip"]]'); // . $results = array(); // (, ) - // . $roomCount = 1; // $nodes - - (tr). foreach ($nodes as $row) { // - , .. $cells = array(); $cell = $row->firstChild; while ($cell) { $cell->nodeType == XML_ELEMENT_NODE and $cells[] = trim($cell->nodeValue); $cell = $cell->nextSibling; } if (count($cells) == 1) { // - // . . $roomCount = (int) reset($cells); } else { $cells[0] = $roomCount; // colspan - // . if (count($cells) == 10) { array_splice($cells, 6, 1, array(0, '', $cells[6], '')); } // , . $html = $row->ownerDocument->saveXML($row); if (preg_match('~<a href="([^"]+)~u', $html, $match)) { array_unshift($cells, 'http://www.bn.ru'.$match[1]); } else { array_unshift($cells, ''); } // , . $keys = array('url', 'rooms', 'address', 'floors', 'houseType', 'area', 'areaLiving', 'areaKitchen', 'toilet', 'price', 'conditions', 'seller', 'phone', 'notes'); $result[] = array_combine($keys, $cells); } } return $result; }


, - $all . - . :
array( 'url' => 'http://www.bn.ru/detail/flats/xxxxxx.html?from=search', 'rooms' => 1, 'address' => '7 ., xxx', 'floors' => '1\\5', 'houseType' => '', 'area' => '30', 'areaLiving' => '18.3', 'areaKitchen' => '6', 'toilet' => ' ', 'price' => '3100', 'conditions' => ' ', 'seller' => 'xxxxx ', 'phone' => '(965) xxxxxxx', 'notes' => ' ', )

HTML .:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Map grabber</title> <script src="//api-maps.yandex.ru/2.0/?load=package.standard&lang=ru-RU" type="text/javascript"></script> <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script> <style> html, body, .#map { margin: 0; padding: 0; } #map { width: 100%; height: 800px; } </style> </head> <body> <div id="map"></div> </body> </html>

jQuery , .

, . JavaScript :
// . var coords = [] // . var info = [] <?foreach ($all as $offer) {?> coords.push('-, <?=$offer['address']?>') info.push(<?=json_encode($offer, JSON_UNESCAPED_UNICODE)?>) <?}?> ymaps.ready(init);

- init() . MultiGeocoder API ; ( coords ), ( ), .

function init() { // -: var map = new ymaps.Map('map', { center: [59.932666, 30.329596], zoom: 13, behaviors: ['default', 'scrollZoom'], }) // : map.controls .add('zoomControl', {left: 5, top: 5}) .add('mapTools', {left: 35, top: 5}) // . (new MultiGeocoder({boundedBy: map.getBounds()})) .geocode(coords) .then( function (res) { // . for (var i = 0; i < res.geoObjects.getLength(); i++) { var cells = info[i] // - // , . var text = '<p>' + $('<b>').append( $('<a>') .attr({href: cells.url, target: '_blank'}) .text(cells.address) )[0].outerHTML + '</p>' // - , . var geo = res.geoObjects.get(i) // . info[i].geo = geo // . geo.properties.set('balloonContentBody', text) } // . map.geoObjects.add(res.geoObjects) }, function (err) { alert(err) } ) return map }

. . , .


?..
, , . ! , , , .

JavaScript , . , . , , , - , , - , .

- . ( API ):
// [ [_, _], ... ]. var markers = [] // <p data-marker="twirl#redDotIcon">. // twirl#redDotIcon - (preset) . $('p[data-marker] input').val(function (i, value) { var marker = $(this).parent().attr('data-marker') value = $.trim(value) value && markers.push([marker, value]) return value }) // (. init()). cells - {price: 123, rooms: 2, ...}. $.each(info, function (i, cells) { var colored = false for (var i = 0; i < markers.length && !colored; i++) { var item = markers[i] var func = new Function('cells', 'return ' + item[1]); // - , . if (func(cells)) { cells.geo.options.set('preset', item[0]) // . colored = true } } // - . colored || cells.geo.options.set('preset', 'twirl#blueIcon') })

, , -, !

, . , .

UPD: Gist . , :)
), - , , DOMNode .

:
// . $all = array(); $baseURL = 'http://www.bn.ru/zap_fl.phtml?print=printall&'; // , . $empty = iconv('utf-8', 'cp1251', ' 0'); // . foreach ((array) $_REQUEST['region'] as $region) { $url = $baseURL."region$region=$region&"; // ... // , 300 - // , 300. foreach (range(0, 10000, 1000) as $price0) { $reqURL = $url."price1=$price0&price2=".($price0 + 999); // - . . $data = dl($reqURL); if (!strpos($data, $empty)) { // . $offers = parse($data); $all = array_merge($all, $offers); } // . usleep(200000); } }

dl() cURL file_get_contents() - , , .

parse() HTML .
function parse($html) { // DOMDocument, UTF-8 ( , // ). $html = '<?xml encoding="UTF-8">'.iconv('cp1251', 'utf-8', $html); $doc = new DOMDocument('1.0', 'utf-8'); @$doc->loadHTML($html) or die('loadHTML: '.$html); // . $xpath = new DOMXPath($doc); // , - // () , . $nodes = $xpath->query('//table[@class="results"]/tr[th[@class="head_kvart"] or td[@width or @class="tooltip"]]'); // . $results = array(); // (, ) - // . $roomCount = 1; // $nodes - - (tr). foreach ($nodes as $row) { // - , .. $cells = array(); $cell = $row->firstChild; while ($cell) { $cell->nodeType == XML_ELEMENT_NODE and $cells[] = trim($cell->nodeValue); $cell = $cell->nextSibling; } if (count($cells) == 1) { // - // . . $roomCount = (int) reset($cells); } else { $cells[0] = $roomCount; // colspan - // . if (count($cells) == 10) { array_splice($cells, 6, 1, array(0, '', $cells[6], '')); } // , . $html = $row->ownerDocument->saveXML($row); if (preg_match('~<a href="([^"]+)~u', $html, $match)) { array_unshift($cells, 'http://www.bn.ru'.$match[1]); } else { array_unshift($cells, ''); } // , . $keys = array('url', 'rooms', 'address', 'floors', 'houseType', 'area', 'areaLiving', 'areaKitchen', 'toilet', 'price', 'conditions', 'seller', 'phone', 'notes'); $result[] = array_combine($keys, $cells); } } return $result; }


, - $all . - . :
array( 'url' => 'http://www.bn.ru/detail/flats/xxxxxx.html?from=search', 'rooms' => 1, 'address' => '7 ., xxx', 'floors' => '1\\5', 'houseType' => '', 'area' => '30', 'areaLiving' => '18.3', 'areaKitchen' => '6', 'toilet' => ' ', 'price' => '3100', 'conditions' => ' ', 'seller' => 'xxxxx ', 'phone' => '(965) xxxxxxx', 'notes' => ' ', )

HTML .:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Map grabber</title> <script src="//api-maps.yandex.ru/2.0/?load=package.standard&lang=ru-RU" type="text/javascript"></script> <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script> <style> html, body, .#map { margin: 0; padding: 0; } #map { width: 100%; height: 800px; } </style> </head> <body> <div id="map"></div> </body> </html>

jQuery , .

, . JavaScript :
// . var coords = [] // . var info = [] <?foreach ($all as $offer) {?> coords.push('-, <?=$offer['address']?>') info.push(<?=json_encode($offer, JSON_UNESCAPED_UNICODE)?>) <?}?> ymaps.ready(init);

- init() . MultiGeocoder API ; ( coords ), ( ), .

function init() { // -: var map = new ymaps.Map('map', { center: [59.932666, 30.329596], zoom: 13, behaviors: ['default', 'scrollZoom'], }) // : map.controls .add('zoomControl', {left: 5, top: 5}) .add('mapTools', {left: 35, top: 5}) // . (new MultiGeocoder({boundedBy: map.getBounds()})) .geocode(coords) .then( function (res) { // . for (var i = 0; i < res.geoObjects.getLength(); i++) { var cells = info[i] // - // , . var text = '<p>' + $('<b>').append( $('<a>') .attr({href: cells.url, target: '_blank'}) .text(cells.address) )[0].outerHTML + '</p>' // - , . var geo = res.geoObjects.get(i) // . info[i].geo = geo // . geo.properties.set('balloonContentBody', text) } // . map.geoObjects.add(res.geoObjects) }, function (err) { alert(err) } ) return map }

. . , .


?..
, , . ! , , , .

JavaScript , . , . , , , - , , - , .

- . ( API ):
// [ [_, _], ... ]. var markers = [] // <p data-marker="twirl#redDotIcon">. // twirl#redDotIcon - (preset) . $('p[data-marker] input').val(function (i, value) { var marker = $(this).parent().attr('data-marker') value = $.trim(value) value && markers.push([marker, value]) return value }) // (. init()). cells - {price: 123, rooms: 2, ...}. $.each(info, function (i, cells) { var colored = false for (var i = 0; i < markers.length && !colored; i++) { var item = markers[i] var func = new Function('cells', 'return ' + item[1]); // - , . if (func(cells)) { cells.geo.options.set('preset', item[0]) // . colored = true } } // - . colored || cells.geo.options.set('preset', 'twirl#blueIcon') })

, , -, !

, . , .

UPD: Gist . , :)

), - , , DOMNode .

:
// . $all = array(); $baseURL = 'http://www.bn.ru/zap_fl.phtml?print=printall&'; // , . $empty = iconv('utf-8', 'cp1251', ' 0'); // . foreach ((array) $_REQUEST['region'] as $region) { $url = $baseURL."region$region=$region&"; // ... // , 300 - // , 300. foreach (range(0, 10000, 1000) as $price0) { $reqURL = $url."price1=$price0&price2=".($price0 + 999); // - . . $data = dl($reqURL); if (!strpos($data, $empty)) { // . $offers = parse($data); $all = array_merge($all, $offers); } // . usleep(200000); } }

dl() cURL file_get_contents() - , , .

parse() HTML .
function parse($html) { // DOMDocument, UTF-8 ( , // ). $html = '<?xml encoding="UTF-8">'.iconv('cp1251', 'utf-8', $html); $doc = new DOMDocument('1.0', 'utf-8'); @$doc->loadHTML($html) or die('loadHTML: '.$html); // . $xpath = new DOMXPath($doc); // , - // () , . $nodes = $xpath->query('//table[@class="results"]/tr[th[@class="head_kvart"] or td[@width or @class="tooltip"]]'); // . $results = array(); // (, ) - // . $roomCount = 1; // $nodes - - (tr). foreach ($nodes as $row) { // - , .. $cells = array(); $cell = $row->firstChild; while ($cell) { $cell->nodeType == XML_ELEMENT_NODE and $cells[] = trim($cell->nodeValue); $cell = $cell->nextSibling; } if (count($cells) == 1) { // - // . . $roomCount = (int) reset($cells); } else { $cells[0] = $roomCount; // colspan - // . if (count($cells) == 10) { array_splice($cells, 6, 1, array(0, '', $cells[6], '')); } // , . $html = $row->ownerDocument->saveXML($row); if (preg_match('~<a href="([^"]+)~u', $html, $match)) { array_unshift($cells, 'http://www.bn.ru'.$match[1]); } else { array_unshift($cells, ''); } // , . $keys = array('url', 'rooms', 'address', 'floors', 'houseType', 'area', 'areaLiving', 'areaKitchen', 'toilet', 'price', 'conditions', 'seller', 'phone', 'notes'); $result[] = array_combine($keys, $cells); } } return $result; }


, - $all . - . :
array( 'url' => 'http://www.bn.ru/detail/flats/xxxxxx.html?from=search', 'rooms' => 1, 'address' => '7 ., xxx', 'floors' => '1\\5', 'houseType' => '', 'area' => '30', 'areaLiving' => '18.3', 'areaKitchen' => '6', 'toilet' => ' ', 'price' => '3100', 'conditions' => ' ', 'seller' => 'xxxxx ', 'phone' => '(965) xxxxxxx', 'notes' => ' ', )

HTML .:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Map grabber</title> <script src="//api-maps.yandex.ru/2.0/?load=package.standard&lang=ru-RU" type="text/javascript"></script> <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script> <style> html, body, .#map { margin: 0; padding: 0; } #map { width: 100%; height: 800px; } </style> </head> <body> <div id="map"></div> </body> </html>

jQuery , .

, . JavaScript :
// . var coords = [] // . var info = [] <?foreach ($all as $offer) {?> coords.push('-, <?=$offer['address']?>') info.push(<?=json_encode($offer, JSON_UNESCAPED_UNICODE)?>) <?}?> ymaps.ready(init);

- init() . MultiGeocoder API ; ( coords ), ( ), .

function init() { // -: var map = new ymaps.Map('map', { center: [59.932666, 30.329596], zoom: 13, behaviors: ['default', 'scrollZoom'], }) // : map.controls .add('zoomControl', {left: 5, top: 5}) .add('mapTools', {left: 35, top: 5}) // . (new MultiGeocoder({boundedBy: map.getBounds()})) .geocode(coords) .then( function (res) { // . for (var i = 0; i < res.geoObjects.getLength(); i++) { var cells = info[i] // - // , . var text = '<p>' + $('<b>').append( $('<a>') .attr({href: cells.url, target: '_blank'}) .text(cells.address) )[0].outerHTML + '</p>' // - , . var geo = res.geoObjects.get(i) // . info[i].geo = geo // . geo.properties.set('balloonContentBody', text) } // . map.geoObjects.add(res.geoObjects) }, function (err) { alert(err) } ) return map }

. . , .


?..
, , . ! , , , .

JavaScript , . , . , , , - , , - , .

- . ( API ):
// [ [_, _], ... ]. var markers = [] // <p data-marker="twirl#redDotIcon">. // twirl#redDotIcon - (preset) . $('p[data-marker] input').val(function (i, value) { var marker = $(this).parent().attr('data-marker') value = $.trim(value) value && markers.push([marker, value]) return value }) // (. init()). cells - {price: 123, rooms: 2, ...}. $.each(info, function (i, cells) { var colored = false for (var i = 0; i < markers.length && !colored; i++) { var item = markers[i] var func = new Function('cells', 'return ' + item[1]); // - , . if (func(cells)) { cells.geo.options.set('preset', item[0]) // . colored = true } } // - . colored || cells.geo.options.set('preset', 'twirl#blueIcon') })

, , -, !

, . , .

UPD: Gist . , :)

), - , , DOMNode .

:
// . $all = array(); $baseURL = 'http://www.bn.ru/zap_fl.phtml?print=printall&'; // , . $empty = iconv('utf-8', 'cp1251', ' 0'); // . foreach ((array) $_REQUEST['region'] as $region) { $url = $baseURL."region$region=$region&"; // ... // , 300 - // , 300. foreach (range(0, 10000, 1000) as $price0) { $reqURL = $url."price1=$price0&price2=".($price0 + 999); // - . . $data = dl($reqURL); if (!strpos($data, $empty)) { // . $offers = parse($data); $all = array_merge($all, $offers); } // . usleep(200000); } }

dl() cURL file_get_contents() - , , .

parse() HTML .
function parse($html) { // DOMDocument, UTF-8 ( , // ). $html = '<?xml encoding="UTF-8">'.iconv('cp1251', 'utf-8', $html); $doc = new DOMDocument('1.0', 'utf-8'); @$doc->loadHTML($html) or die('loadHTML: '.$html); // . $xpath = new DOMXPath($doc); // , - // () , . $nodes = $xpath->query('//table[@class="results"]/tr[th[@class="head_kvart"] or td[@width or @class="tooltip"]]'); // . $results = array(); // (, ) - // . $roomCount = 1; // $nodes - - (tr). foreach ($nodes as $row) { // - , .. $cells = array(); $cell = $row->firstChild; while ($cell) { $cell->nodeType == XML_ELEMENT_NODE and $cells[] = trim($cell->nodeValue); $cell = $cell->nextSibling; } if (count($cells) == 1) { // - // . . $roomCount = (int) reset($cells); } else { $cells[0] = $roomCount; // colspan - // . if (count($cells) == 10) { array_splice($cells, 6, 1, array(0, '', $cells[6], '')); } // , . $html = $row->ownerDocument->saveXML($row); if (preg_match('~<a href="([^"]+)~u', $html, $match)) { array_unshift($cells, 'http://www.bn.ru'.$match[1]); } else { array_unshift($cells, ''); } // , . $keys = array('url', 'rooms', 'address', 'floors', 'houseType', 'area', 'areaLiving', 'areaKitchen', 'toilet', 'price', 'conditions', 'seller', 'phone', 'notes'); $result[] = array_combine($keys, $cells); } } return $result; }


, - $all . - . :
array( 'url' => 'http://www.bn.ru/detail/flats/xxxxxx.html?from=search', 'rooms' => 1, 'address' => '7 ., xxx', 'floors' => '1\\5', 'houseType' => '', 'area' => '30', 'areaLiving' => '18.3', 'areaKitchen' => '6', 'toilet' => ' ', 'price' => '3100', 'conditions' => ' ', 'seller' => 'xxxxx ', 'phone' => '(965) xxxxxxx', 'notes' => ' ', )

HTML .:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Map grabber</title> <script src="//api-maps.yandex.ru/2.0/?load=package.standard&lang=ru-RU" type="text/javascript"></script> <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script> <style> html, body, .#map { margin: 0; padding: 0; } #map { width: 100%; height: 800px; } </style> </head> <body> <div id="map"></div> </body> </html>

jQuery , .

, . JavaScript :
// . var coords = [] // . var info = [] <?foreach ($all as $offer) {?> coords.push('-, <?=$offer['address']?>') info.push(<?=json_encode($offer, JSON_UNESCAPED_UNICODE)?>) <?}?> ymaps.ready(init);

- init() . MultiGeocoder API ; ( coords ), ( ), .

function init() { // -: var map = new ymaps.Map('map', { center: [59.932666, 30.329596], zoom: 13, behaviors: ['default', 'scrollZoom'], }) // : map.controls .add('zoomControl', {left: 5, top: 5}) .add('mapTools', {left: 35, top: 5}) // . (new MultiGeocoder({boundedBy: map.getBounds()})) .geocode(coords) .then( function (res) { // . for (var i = 0; i < res.geoObjects.getLength(); i++) { var cells = info[i] // - // , . var text = '<p>' + $('<b>').append( $('<a>') .attr({href: cells.url, target: '_blank'}) .text(cells.address) )[0].outerHTML + '</p>' // - , . var geo = res.geoObjects.get(i) // . info[i].geo = geo // . geo.properties.set('balloonContentBody', text) } // . map.geoObjects.add(res.geoObjects) }, function (err) { alert(err) } ) return map }

. . , .


?..
, , . ! , , , .

JavaScript , . , . , , , - , , - , .

- . ( API ):
// [ [_, _], ... ]. var markers = [] // <p data-marker="twirl#redDotIcon">. // twirl#redDotIcon - (preset) . $('p[data-marker] input').val(function (i, value) { var marker = $(this).parent().attr('data-marker') value = $.trim(value) value && markers.push([marker, value]) return value }) // (. init()). cells - {price: 123, rooms: 2, ...}. $.each(info, function (i, cells) { var colored = false for (var i = 0; i < markers.length && !colored; i++) { var item = markers[i] var func = new Function('cells', 'return ' + item[1]); // - , . if (func(cells)) { cells.geo.options.set('preset', item[0]) // . colored = true } } // - . colored || cells.geo.options.set('preset', 'twirl#blueIcon') })

, , -, !

, . , .

UPD: Gist . , :)
 ),    -   ,   ,    DOMNode . 

:
// . $all = array(); $baseURL = 'http://www.bn.ru/zap_fl.phtml?print=printall&'; // , . $empty = iconv('utf-8', 'cp1251', ' 0'); // . foreach ((array) $_REQUEST['region'] as $region) { $url = $baseURL."region$region=$region&"; // ... // , 300 - // , 300. foreach (range(0, 10000, 1000) as $price0) { $reqURL = $url."price1=$price0&price2=".($price0 + 999); // - . . $data = dl($reqURL); if (!strpos($data, $empty)) { // . $offers = parse($data); $all = array_merge($all, $offers); } // . usleep(200000); } }

dl() cURL file_get_contents() - , , .

parse() HTML .
function parse($html) { // DOMDocument, UTF-8 ( , // ). $html = '<?xml encoding="UTF-8">'.iconv('cp1251', 'utf-8', $html); $doc = new DOMDocument('1.0', 'utf-8'); @$doc->loadHTML($html) or die('loadHTML: '.$html); // . $xpath = new DOMXPath($doc); // , - // () , . $nodes = $xpath->query('//table[@class="results"]/tr[th[@class="head_kvart"] or td[@width or @class="tooltip"]]'); // . $results = array(); // (, ) - // . $roomCount = 1; // $nodes - - (tr). foreach ($nodes as $row) { // - , .. $cells = array(); $cell = $row->firstChild; while ($cell) { $cell->nodeType == XML_ELEMENT_NODE and $cells[] = trim($cell->nodeValue); $cell = $cell->nextSibling; } if (count($cells) == 1) { // - // . . $roomCount = (int) reset($cells); } else { $cells[0] = $roomCount; // colspan - // . if (count($cells) == 10) { array_splice($cells, 6, 1, array(0, '', $cells[6], '')); } // , . $html = $row->ownerDocument->saveXML($row); if (preg_match('~<a href="([^"]+)~u', $html, $match)) { array_unshift($cells, 'http://www.bn.ru'.$match[1]); } else { array_unshift($cells, ''); } // , . $keys = array('url', 'rooms', 'address', 'floors', 'houseType', 'area', 'areaLiving', 'areaKitchen', 'toilet', 'price', 'conditions', 'seller', 'phone', 'notes'); $result[] = array_combine($keys, $cells); } } return $result; }


, - $all . - . :
array( 'url' => 'http://www.bn.ru/detail/flats/xxxxxx.html?from=search', 'rooms' => 1, 'address' => '7 ., xxx', 'floors' => '1\\5', 'houseType' => '', 'area' => '30', 'areaLiving' => '18.3', 'areaKitchen' => '6', 'toilet' => ' ', 'price' => '3100', 'conditions' => ' ', 'seller' => 'xxxxx ', 'phone' => '(965) xxxxxxx', 'notes' => ' ', )

HTML .:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Map grabber</title> <script src="//api-maps.yandex.ru/2.0/?load=package.standard&lang=ru-RU" type="text/javascript"></script> <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script> <style> html, body, .#map { margin: 0; padding: 0; } #map { width: 100%; height: 800px; } </style> </head> <body> <div id="map"></div> </body> </html>

jQuery , .

, . JavaScript :
// . var coords = [] // . var info = [] <?foreach ($all as $offer) {?> coords.push('-, <?=$offer['address']?>') info.push(<?=json_encode($offer, JSON_UNESCAPED_UNICODE)?>) <?}?> ymaps.ready(init);

- init() . MultiGeocoder API ; ( coords ), ( ), .

function init() { // -: var map = new ymaps.Map('map', { center: [59.932666, 30.329596], zoom: 13, behaviors: ['default', 'scrollZoom'], }) // : map.controls .add('zoomControl', {left: 5, top: 5}) .add('mapTools', {left: 35, top: 5}) // . (new MultiGeocoder({boundedBy: map.getBounds()})) .geocode(coords) .then( function (res) { // . for (var i = 0; i < res.geoObjects.getLength(); i++) { var cells = info[i] // - // , . var text = '<p>' + $('<b>').append( $('<a>') .attr({href: cells.url, target: '_blank'}) .text(cells.address) )[0].outerHTML + '</p>' // - , . var geo = res.geoObjects.get(i) // . info[i].geo = geo // . geo.properties.set('balloonContentBody', text) } // . map.geoObjects.add(res.geoObjects) }, function (err) { alert(err) } ) return map }

. . , .


?..
, , . ! , , , .

JavaScript , . , . , , , - , , - , .

- . ( API ):
// [ [_, _], ... ]. var markers = [] // <p data-marker="twirl#redDotIcon">. // twirl#redDotIcon - (preset) . $('p[data-marker] input').val(function (i, value) { var marker = $(this).parent().attr('data-marker') value = $.trim(value) value && markers.push([marker, value]) return value }) // (. init()). cells - {price: 123, rooms: 2, ...}. $.each(info, function (i, cells) { var colored = false for (var i = 0; i < markers.length && !colored; i++) { var item = markers[i] var func = new Function('cells', 'return ' + item[1]); // - , . if (func(cells)) { cells.geo.options.set('preset', item[0]) // . colored = true } } // - . colored || cells.geo.options.set('preset', 'twirl#blueIcon') })

, , -, !

, . , .

UPD: Gist . , :)
), - , , DOMNode .

:
// . $all = array(); $baseURL = 'http://www.bn.ru/zap_fl.phtml?print=printall&'; // , . $empty = iconv('utf-8', 'cp1251', ' 0'); // . foreach ((array) $_REQUEST['region'] as $region) { $url = $baseURL."region$region=$region&"; // ... // , 300 - // , 300. foreach (range(0, 10000, 1000) as $price0) { $reqURL = $url."price1=$price0&price2=".($price0 + 999); // - . . $data = dl($reqURL); if (!strpos($data, $empty)) { // . $offers = parse($data); $all = array_merge($all, $offers); } // . usleep(200000); } }

dl() cURL file_get_contents() - , , .

parse() HTML .
function parse($html) { // DOMDocument, UTF-8 ( , // ). $html = '<?xml encoding="UTF-8">'.iconv('cp1251', 'utf-8', $html); $doc = new DOMDocument('1.0', 'utf-8'); @$doc->loadHTML($html) or die('loadHTML: '.$html); // . $xpath = new DOMXPath($doc); // , - // () , . $nodes = $xpath->query('//table[@class="results"]/tr[th[@class="head_kvart"] or td[@width or @class="tooltip"]]'); // . $results = array(); // (, ) - // . $roomCount = 1; // $nodes - - (tr). foreach ($nodes as $row) { // - , .. $cells = array(); $cell = $row->firstChild; while ($cell) { $cell->nodeType == XML_ELEMENT_NODE and $cells[] = trim($cell->nodeValue); $cell = $cell->nextSibling; } if (count($cells) == 1) { // - // . . $roomCount = (int) reset($cells); } else { $cells[0] = $roomCount; // colspan - // . if (count($cells) == 10) { array_splice($cells, 6, 1, array(0, '', $cells[6], '')); } // , . $html = $row->ownerDocument->saveXML($row); if (preg_match('~<a href="([^"]+)~u', $html, $match)) { array_unshift($cells, 'http://www.bn.ru'.$match[1]); } else { array_unshift($cells, ''); } // , . $keys = array('url', 'rooms', 'address', 'floors', 'houseType', 'area', 'areaLiving', 'areaKitchen', 'toilet', 'price', 'conditions', 'seller', 'phone', 'notes'); $result[] = array_combine($keys, $cells); } } return $result; }


, - $all . - . :
array( 'url' => 'http://www.bn.ru/detail/flats/xxxxxx.html?from=search', 'rooms' => 1, 'address' => '7 ., xxx', 'floors' => '1\\5', 'houseType' => '', 'area' => '30', 'areaLiving' => '18.3', 'areaKitchen' => '6', 'toilet' => ' ', 'price' => '3100', 'conditions' => ' ', 'seller' => 'xxxxx ', 'phone' => '(965) xxxxxxx', 'notes' => ' ', )

HTML .:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Map grabber</title> <script src="//api-maps.yandex.ru/2.0/?load=package.standard&lang=ru-RU" type="text/javascript"></script> <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script> <style> html, body, .#map { margin: 0; padding: 0; } #map { width: 100%; height: 800px; } </style> </head> <body> <div id="map"></div> </body> </html>

jQuery , .

, . JavaScript :
// . var coords = [] // . var info = [] <?foreach ($all as $offer) {?> coords.push('-, <?=$offer['address']?>') info.push(<?=json_encode($offer, JSON_UNESCAPED_UNICODE)?>) <?}?> ymaps.ready(init);

- init() . MultiGeocoder API ; ( coords ), ( ), .

function init() { // -: var map = new ymaps.Map('map', { center: [59.932666, 30.329596], zoom: 13, behaviors: ['default', 'scrollZoom'], }) // : map.controls .add('zoomControl', {left: 5, top: 5}) .add('mapTools', {left: 35, top: 5}) // . (new MultiGeocoder({boundedBy: map.getBounds()})) .geocode(coords) .then( function (res) { // . for (var i = 0; i < res.geoObjects.getLength(); i++) { var cells = info[i] // - // , . var text = '<p>' + $('<b>').append( $('<a>') .attr({href: cells.url, target: '_blank'}) .text(cells.address) )[0].outerHTML + '</p>' // - , . var geo = res.geoObjects.get(i) // . info[i].geo = geo // . geo.properties.set('balloonContentBody', text) } // . map.geoObjects.add(res.geoObjects) }, function (err) { alert(err) } ) return map }

. . , .


?..
, , . ! , , , .

JavaScript , . , . , , , - , , - , .

- . ( API ):
// [ [_, _], ... ]. var markers = [] // <p data-marker="twirl#redDotIcon">. // twirl#redDotIcon - (preset) . $('p[data-marker] input').val(function (i, value) { var marker = $(this).parent().attr('data-marker') value = $.trim(value) value && markers.push([marker, value]) return value }) // (. init()). cells - {price: 123, rooms: 2, ...}. $.each(info, function (i, cells) { var colored = false for (var i = 0; i < markers.length && !colored; i++) { var item = markers[i] var func = new Function('cells', 'return ' + item[1]); // - , . if (func(cells)) { cells.geo.options.set('preset', item[0]) // . colored = true } } // - . colored || cells.geo.options.set('preset', 'twirl#blueIcon') })

, , -, !

, . , .

UPD: Gist . , :)
 ),    -   ,   ,    DOMNode . 

:
// . $all = array(); $baseURL = 'http://www.bn.ru/zap_fl.phtml?print=printall&'; // , . $empty = iconv('utf-8', 'cp1251', ' 0'); // . foreach ((array) $_REQUEST['region'] as $region) { $url = $baseURL."region$region=$region&"; // ... // , 300 - // , 300. foreach (range(0, 10000, 1000) as $price0) { $reqURL = $url."price1=$price0&price2=".($price0 + 999); // - . . $data = dl($reqURL); if (!strpos($data, $empty)) { // . $offers = parse($data); $all = array_merge($all, $offers); } // . usleep(200000); } }

dl() cURL file_get_contents() - , , .

parse() HTML .
function parse($html) { // DOMDocument, UTF-8 ( , // ). $html = '<?xml encoding="UTF-8">'.iconv('cp1251', 'utf-8', $html); $doc = new DOMDocument('1.0', 'utf-8'); @$doc->loadHTML($html) or die('loadHTML: '.$html); // . $xpath = new DOMXPath($doc); // , - // () , . $nodes = $xpath->query('//table[@class="results"]/tr[th[@class="head_kvart"] or td[@width or @class="tooltip"]]'); // . $results = array(); // (, ) - // . $roomCount = 1; // $nodes - - (tr). foreach ($nodes as $row) { // - , .. $cells = array(); $cell = $row->firstChild; while ($cell) { $cell->nodeType == XML_ELEMENT_NODE and $cells[] = trim($cell->nodeValue); $cell = $cell->nextSibling; } if (count($cells) == 1) { // - // . . $roomCount = (int) reset($cells); } else { $cells[0] = $roomCount; // colspan - // . if (count($cells) == 10) { array_splice($cells, 6, 1, array(0, '', $cells[6], '')); } // , . $html = $row->ownerDocument->saveXML($row); if (preg_match('~<a href="([^"]+)~u', $html, $match)) { array_unshift($cells, 'http://www.bn.ru'.$match[1]); } else { array_unshift($cells, ''); } // , . $keys = array('url', 'rooms', 'address', 'floors', 'houseType', 'area', 'areaLiving', 'areaKitchen', 'toilet', 'price', 'conditions', 'seller', 'phone', 'notes'); $result[] = array_combine($keys, $cells); } } return $result; }


, - $all . - . :
array( 'url' => 'http://www.bn.ru/detail/flats/xxxxxx.html?from=search', 'rooms' => 1, 'address' => '7 ., xxx', 'floors' => '1\\5', 'houseType' => '', 'area' => '30', 'areaLiving' => '18.3', 'areaKitchen' => '6', 'toilet' => ' ', 'price' => '3100', 'conditions' => ' ', 'seller' => 'xxxxx ', 'phone' => '(965) xxxxxxx', 'notes' => ' ', )

HTML .:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Map grabber</title> <script src="//api-maps.yandex.ru/2.0/?load=package.standard&lang=ru-RU" type="text/javascript"></script> <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script> <style> html, body, .#map { margin: 0; padding: 0; } #map { width: 100%; height: 800px; } </style> </head> <body> <div id="map"></div> </body> </html>

jQuery , .

, . JavaScript :
// . var coords = [] // . var info = [] <?foreach ($all as $offer) {?> coords.push('-, <?=$offer['address']?>') info.push(<?=json_encode($offer, JSON_UNESCAPED_UNICODE)?>) <?}?> ymaps.ready(init);

- init() . MultiGeocoder API ; ( coords ), ( ), .

function init() { // -: var map = new ymaps.Map('map', { center: [59.932666, 30.329596], zoom: 13, behaviors: ['default', 'scrollZoom'], }) // : map.controls .add('zoomControl', {left: 5, top: 5}) .add('mapTools', {left: 35, top: 5}) // . (new MultiGeocoder({boundedBy: map.getBounds()})) .geocode(coords) .then( function (res) { // . for (var i = 0; i < res.geoObjects.getLength(); i++) { var cells = info[i] // - // , . var text = '<p>' + $('<b>').append( $('<a>') .attr({href: cells.url, target: '_blank'}) .text(cells.address) )[0].outerHTML + '</p>' // - , . var geo = res.geoObjects.get(i) // . info[i].geo = geo // . geo.properties.set('balloonContentBody', text) } // . map.geoObjects.add(res.geoObjects) }, function (err) { alert(err) } ) return map }

. . , .


?..
, , . ! , , , .

JavaScript , . , . , , , - , , - , .

- . ( API ):
// [ [_, _], ... ]. var markers = [] // <p data-marker="twirl#redDotIcon">. // twirl#redDotIcon - (preset) . $('p[data-marker] input').val(function (i, value) { var marker = $(this).parent().attr('data-marker') value = $.trim(value) value && markers.push([marker, value]) return value }) // (. init()). cells - {price: 123, rooms: 2, ...}. $.each(info, function (i, cells) { var colored = false for (var i = 0; i < markers.length && !colored; i++) { var item = markers[i] var func = new Function('cells', 'return ' + item[1]); // - , . if (func(cells)) { cells.geo.options.set('preset', item[0]) // . colored = true } } // - . colored || cells.geo.options.set('preset', 'twirl#blueIcon') })

, , -, !

, . , .

UPD: Gist . , :)
), - , , DOMNode .

:
// . $all = array(); $baseURL = 'http://www.bn.ru/zap_fl.phtml?print=printall&'; // , . $empty = iconv('utf-8', 'cp1251', ' 0'); // . foreach ((array) $_REQUEST['region'] as $region) { $url = $baseURL."region$region=$region&"; // ... // , 300 - // , 300. foreach (range(0, 10000, 1000) as $price0) { $reqURL = $url."price1=$price0&price2=".($price0 + 999); // - . . $data = dl($reqURL); if (!strpos($data, $empty)) { // . $offers = parse($data); $all = array_merge($all, $offers); } // . usleep(200000); } }

dl() cURL file_get_contents() - , , .

parse() HTML .
function parse($html) { // DOMDocument, UTF-8 ( , // ). $html = '<?xml encoding="UTF-8">'.iconv('cp1251', 'utf-8', $html); $doc = new DOMDocument('1.0', 'utf-8'); @$doc->loadHTML($html) or die('loadHTML: '.$html); // . $xpath = new DOMXPath($doc); // , - // () , . $nodes = $xpath->query('//table[@class="results"]/tr[th[@class="head_kvart"] or td[@width or @class="tooltip"]]'); // . $results = array(); // (, ) - // . $roomCount = 1; // $nodes - - (tr). foreach ($nodes as $row) { // - , .. $cells = array(); $cell = $row->firstChild; while ($cell) { $cell->nodeType == XML_ELEMENT_NODE and $cells[] = trim($cell->nodeValue); $cell = $cell->nextSibling; } if (count($cells) == 1) { // - // . . $roomCount = (int) reset($cells); } else { $cells[0] = $roomCount; // colspan - // . if (count($cells) == 10) { array_splice($cells, 6, 1, array(0, '', $cells[6], '')); } // , . $html = $row->ownerDocument->saveXML($row); if (preg_match('~<a href="([^"]+)~u', $html, $match)) { array_unshift($cells, 'http://www.bn.ru'.$match[1]); } else { array_unshift($cells, ''); } // , . $keys = array('url', 'rooms', 'address', 'floors', 'houseType', 'area', 'areaLiving', 'areaKitchen', 'toilet', 'price', 'conditions', 'seller', 'phone', 'notes'); $result[] = array_combine($keys, $cells); } } return $result; }


, - $all . - . :
array( 'url' => 'http://www.bn.ru/detail/flats/xxxxxx.html?from=search', 'rooms' => 1, 'address' => '7 ., xxx', 'floors' => '1\\5', 'houseType' => '', 'area' => '30', 'areaLiving' => '18.3', 'areaKitchen' => '6', 'toilet' => ' ', 'price' => '3100', 'conditions' => ' ', 'seller' => 'xxxxx ', 'phone' => '(965) xxxxxxx', 'notes' => ' ', )

HTML .:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Map grabber</title> <script src="//api-maps.yandex.ru/2.0/?load=package.standard&lang=ru-RU" type="text/javascript"></script> <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script> <style> html, body, .#map { margin: 0; padding: 0; } #map { width: 100%; height: 800px; } </style> </head> <body> <div id="map"></div> </body> </html>

jQuery , .

, . JavaScript :
// . var coords = [] // . var info = [] <?foreach ($all as $offer) {?> coords.push('-, <?=$offer['address']?>') info.push(<?=json_encode($offer, JSON_UNESCAPED_UNICODE)?>) <?}?> ymaps.ready(init);

- init() . MultiGeocoder API ; ( coords ), ( ), .

function init() { // -: var map = new ymaps.Map('map', { center: [59.932666, 30.329596], zoom: 13, behaviors: ['default', 'scrollZoom'], }) // : map.controls .add('zoomControl', {left: 5, top: 5}) .add('mapTools', {left: 35, top: 5}) // . (new MultiGeocoder({boundedBy: map.getBounds()})) .geocode(coords) .then( function (res) { // . for (var i = 0; i < res.geoObjects.getLength(); i++) { var cells = info[i] // - // , . var text = '<p>' + $('<b>').append( $('<a>') .attr({href: cells.url, target: '_blank'}) .text(cells.address) )[0].outerHTML + '</p>' // - , . var geo = res.geoObjects.get(i) // . info[i].geo = geo // . geo.properties.set('balloonContentBody', text) } // . map.geoObjects.add(res.geoObjects) }, function (err) { alert(err) } ) return map }

. . , .


?..
, , . ! , , , .

JavaScript , . , . , , , - , , - , .

- . ( API ):
// [ [_, _], ... ]. var markers = [] // <p data-marker="twirl#redDotIcon">. // twirl#redDotIcon - (preset) . $('p[data-marker] input').val(function (i, value) { var marker = $(this).parent().attr('data-marker') value = $.trim(value) value && markers.push([marker, value]) return value }) // (. init()). cells - {price: 123, rooms: 2, ...}. $.each(info, function (i, cells) { var colored = false for (var i = 0; i < markers.length && !colored; i++) { var item = markers[i] var func = new Function('cells', 'return ' + item[1]); // - , . if (func(cells)) { cells.geo.options.set('preset', item[0]) // . colored = true } } // - . colored || cells.geo.options.set('preset', 'twirl#blueIcon') })

, , -, !

, . , .

UPD: Gist . , :)
 ),    -   ,   ,    DOMNode . 

:
// . $all = array(); $baseURL = 'http://www.bn.ru/zap_fl.phtml?print=printall&'; // , . $empty = iconv('utf-8', 'cp1251', ' 0'); // . foreach ((array) $_REQUEST['region'] as $region) { $url = $baseURL."region$region=$region&"; // ... // , 300 - // , 300. foreach (range(0, 10000, 1000) as $price0) { $reqURL = $url."price1=$price0&price2=".($price0 + 999); // - . . $data = dl($reqURL); if (!strpos($data, $empty)) { // . $offers = parse($data); $all = array_merge($all, $offers); } // . usleep(200000); } }

dl() cURL file_get_contents() - , , .

parse() HTML .
function parse($html) { // DOMDocument, UTF-8 ( , // ). $html = '<?xml encoding="UTF-8">'.iconv('cp1251', 'utf-8', $html); $doc = new DOMDocument('1.0', 'utf-8'); @$doc->loadHTML($html) or die('loadHTML: '.$html); // . $xpath = new DOMXPath($doc); // , - // () , . $nodes = $xpath->query('//table[@class="results"]/tr[th[@class="head_kvart"] or td[@width or @class="tooltip"]]'); // . $results = array(); // (, ) - // . $roomCount = 1; // $nodes - - (tr). foreach ($nodes as $row) { // - , .. $cells = array(); $cell = $row->firstChild; while ($cell) { $cell->nodeType == XML_ELEMENT_NODE and $cells[] = trim($cell->nodeValue); $cell = $cell->nextSibling; } if (count($cells) == 1) { // - // . . $roomCount = (int) reset($cells); } else { $cells[0] = $roomCount; // colspan - // . if (count($cells) == 10) { array_splice($cells, 6, 1, array(0, '', $cells[6], '')); } // , . $html = $row->ownerDocument->saveXML($row); if (preg_match('~<a href="([^"]+)~u', $html, $match)) { array_unshift($cells, 'http://www.bn.ru'.$match[1]); } else { array_unshift($cells, ''); } // , . $keys = array('url', 'rooms', 'address', 'floors', 'houseType', 'area', 'areaLiving', 'areaKitchen', 'toilet', 'price', 'conditions', 'seller', 'phone', 'notes'); $result[] = array_combine($keys, $cells); } } return $result; }


, - $all . - . :
array( 'url' => 'http://www.bn.ru/detail/flats/xxxxxx.html?from=search', 'rooms' => 1, 'address' => '7 ., xxx', 'floors' => '1\\5', 'houseType' => '', 'area' => '30', 'areaLiving' => '18.3', 'areaKitchen' => '6', 'toilet' => ' ', 'price' => '3100', 'conditions' => ' ', 'seller' => 'xxxxx ', 'phone' => '(965) xxxxxxx', 'notes' => ' ', )

HTML .:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Map grabber</title> <script src="//api-maps.yandex.ru/2.0/?load=package.standard&lang=ru-RU" type="text/javascript"></script> <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script> <style> html, body, .#map { margin: 0; padding: 0; } #map { width: 100%; height: 800px; } </style> </head> <body> <div id="map"></div> </body> </html>

jQuery , .

, . JavaScript :
// . var coords = [] // . var info = [] <?foreach ($all as $offer) {?> coords.push('-, <?=$offer['address']?>') info.push(<?=json_encode($offer, JSON_UNESCAPED_UNICODE)?>) <?}?> ymaps.ready(init);

- init() . MultiGeocoder API ; ( coords ), ( ), .

function init() { // -: var map = new ymaps.Map('map', { center: [59.932666, 30.329596], zoom: 13, behaviors: ['default', 'scrollZoom'], }) // : map.controls .add('zoomControl', {left: 5, top: 5}) .add('mapTools', {left: 35, top: 5}) // . (new MultiGeocoder({boundedBy: map.getBounds()})) .geocode(coords) .then( function (res) { // . for (var i = 0; i < res.geoObjects.getLength(); i++) { var cells = info[i] // - // , . var text = '<p>' + $('<b>').append( $('<a>') .attr({href: cells.url, target: '_blank'}) .text(cells.address) )[0].outerHTML + '</p>' // - , . var geo = res.geoObjects.get(i) // . info[i].geo = geo // . geo.properties.set('balloonContentBody', text) } // . map.geoObjects.add(res.geoObjects) }, function (err) { alert(err) } ) return map }

. . , .


?..
, , . ! , , , .

JavaScript , . , . , , , - , , - , .

- . ( API ):
// [ [_, _], ... ]. var markers = [] // <p data-marker="twirl#redDotIcon">. // twirl#redDotIcon - (preset) . $('p[data-marker] input').val(function (i, value) { var marker = $(this).parent().attr('data-marker') value = $.trim(value) value && markers.push([marker, value]) return value }) // (. init()). cells - {price: 123, rooms: 2, ...}. $.each(info, function (i, cells) { var colored = false for (var i = 0; i < markers.length && !colored; i++) { var item = markers[i] var func = new Function('cells', 'return ' + item[1]); // - , . if (func(cells)) { cells.geo.options.set('preset', item[0]) // . colored = true } } // - . colored || cells.geo.options.set('preset', 'twirl#blueIcon') })

, , -, !

, . , .

UPD: Gist . , :)
), - , , DOMNode .

:
// . $all = array(); $baseURL = 'http://www.bn.ru/zap_fl.phtml?print=printall&'; // , . $empty = iconv('utf-8', 'cp1251', ' 0'); // . foreach ((array) $_REQUEST['region'] as $region) { $url = $baseURL."region$region=$region&"; // ... // , 300 - // , 300. foreach (range(0, 10000, 1000) as $price0) { $reqURL = $url."price1=$price0&price2=".($price0 + 999); // - . . $data = dl($reqURL); if (!strpos($data, $empty)) { // . $offers = parse($data); $all = array_merge($all, $offers); } // . usleep(200000); } }

dl() cURL file_get_contents() - , , .

parse() HTML .
function parse($html) { // DOMDocument, UTF-8 ( , // ). $html = '<?xml encoding="UTF-8">'.iconv('cp1251', 'utf-8', $html); $doc = new DOMDocument('1.0', 'utf-8'); @$doc->loadHTML($html) or die('loadHTML: '.$html); // . $xpath = new DOMXPath($doc); // , - // () , . $nodes = $xpath->query('//table[@class="results"]/tr[th[@class="head_kvart"] or td[@width or @class="tooltip"]]'); // . $results = array(); // (, ) - // . $roomCount = 1; // $nodes - - (tr). foreach ($nodes as $row) { // - , .. $cells = array(); $cell = $row->firstChild; while ($cell) { $cell->nodeType == XML_ELEMENT_NODE and $cells[] = trim($cell->nodeValue); $cell = $cell->nextSibling; } if (count($cells) == 1) { // - // . . $roomCount = (int) reset($cells); } else { $cells[0] = $roomCount; // colspan - // . if (count($cells) == 10) { array_splice($cells, 6, 1, array(0, '', $cells[6], '')); } // , . $html = $row->ownerDocument->saveXML($row); if (preg_match('~<a href="([^"]+)~u', $html, $match)) { array_unshift($cells, 'http://www.bn.ru'.$match[1]); } else { array_unshift($cells, ''); } // , . $keys = array('url', 'rooms', 'address', 'floors', 'houseType', 'area', 'areaLiving', 'areaKitchen', 'toilet', 'price', 'conditions', 'seller', 'phone', 'notes'); $result[] = array_combine($keys, $cells); } } return $result; }


, - $all . - . :
array( 'url' => 'http://www.bn.ru/detail/flats/xxxxxx.html?from=search', 'rooms' => 1, 'address' => '7 ., xxx', 'floors' => '1\\5', 'houseType' => '', 'area' => '30', 'areaLiving' => '18.3', 'areaKitchen' => '6', 'toilet' => ' ', 'price' => '3100', 'conditions' => ' ', 'seller' => 'xxxxx ', 'phone' => '(965) xxxxxxx', 'notes' => ' ', )

HTML .:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Map grabber</title> <script src="//api-maps.yandex.ru/2.0/?load=package.standard&lang=ru-RU" type="text/javascript"></script> <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script> <style> html, body, .#map { margin: 0; padding: 0; } #map { width: 100%; height: 800px; } </style> </head> <body> <div id="map"></div> </body> </html>

jQuery , .

, . JavaScript :
// . var coords = [] // . var info = [] <?foreach ($all as $offer) {?> coords.push('-, <?=$offer['address']?>') info.push(<?=json_encode($offer, JSON_UNESCAPED_UNICODE)?>) <?}?> ymaps.ready(init);

- init() . MultiGeocoder API ; ( coords ), ( ), .

function init() { // -: var map = new ymaps.Map('map', { center: [59.932666, 30.329596], zoom: 13, behaviors: ['default', 'scrollZoom'], }) // : map.controls .add('zoomControl', {left: 5, top: 5}) .add('mapTools', {left: 35, top: 5}) // . (new MultiGeocoder({boundedBy: map.getBounds()})) .geocode(coords) .then( function (res) { // . for (var i = 0; i < res.geoObjects.getLength(); i++) { var cells = info[i] // - // , . var text = '<p>' + $('<b>').append( $('<a>') .attr({href: cells.url, target: '_blank'}) .text(cells.address) )[0].outerHTML + '</p>' // - , . var geo = res.geoObjects.get(i) // . info[i].geo = geo // . geo.properties.set('balloonContentBody', text) } // . map.geoObjects.add(res.geoObjects) }, function (err) { alert(err) } ) return map }

. . , .


?..
, , . ! , , , .

JavaScript , . , . , , , - , , - , .

- . ( API ):
// [ [_, _], ... ]. var markers = [] // <p data-marker="twirl#redDotIcon">. // twirl#redDotIcon - (preset) . $('p[data-marker] input').val(function (i, value) { var marker = $(this).parent().attr('data-marker') value = $.trim(value) value && markers.push([marker, value]) return value }) // (. init()). cells - {price: 123, rooms: 2, ...}. $.each(info, function (i, cells) { var colored = false for (var i = 0; i < markers.length && !colored; i++) { var item = markers[i] var func = new Function('cells', 'return ' + item[1]); // - , . if (func(cells)) { cells.geo.options.set('preset', item[0]) // . colored = true } } // - . colored || cells.geo.options.set('preset', 'twirl#blueIcon') })

, , -, !

, . , .

UPD: Gist . , :)
 ),    -   ,   ,    DOMNode . 

:
// . $all = array(); $baseURL = 'http://www.bn.ru/zap_fl.phtml?print=printall&'; // , . $empty = iconv('utf-8', 'cp1251', ' 0'); // . foreach ((array) $_REQUEST['region'] as $region) { $url = $baseURL."region$region=$region&"; // ... // , 300 - // , 300. foreach (range(0, 10000, 1000) as $price0) { $reqURL = $url."price1=$price0&price2=".($price0 + 999); // - . . $data = dl($reqURL); if (!strpos($data, $empty)) { // . $offers = parse($data); $all = array_merge($all, $offers); } // . usleep(200000); } }

dl() cURL file_get_contents() - , , .

parse() HTML .
function parse($html) { // DOMDocument, UTF-8 ( , // ). $html = '<?xml encoding="UTF-8">'.iconv('cp1251', 'utf-8', $html); $doc = new DOMDocument('1.0', 'utf-8'); @$doc->loadHTML($html) or die('loadHTML: '.$html); // . $xpath = new DOMXPath($doc); // , - // () , . $nodes = $xpath->query('//table[@class="results"]/tr[th[@class="head_kvart"] or td[@width or @class="tooltip"]]'); // . $results = array(); // (, ) - // . $roomCount = 1; // $nodes - - (tr). foreach ($nodes as $row) { // - , .. $cells = array(); $cell = $row->firstChild; while ($cell) { $cell->nodeType == XML_ELEMENT_NODE and $cells[] = trim($cell->nodeValue); $cell = $cell->nextSibling; } if (count($cells) == 1) { // - // . . $roomCount = (int) reset($cells); } else { $cells[0] = $roomCount; // colspan - // . if (count($cells) == 10) { array_splice($cells, 6, 1, array(0, '', $cells[6], '')); } // , . $html = $row->ownerDocument->saveXML($row); if (preg_match('~<a href="([^"]+)~u', $html, $match)) { array_unshift($cells, 'http://www.bn.ru'.$match[1]); } else { array_unshift($cells, ''); } // , . $keys = array('url', 'rooms', 'address', 'floors', 'houseType', 'area', 'areaLiving', 'areaKitchen', 'toilet', 'price', 'conditions', 'seller', 'phone', 'notes'); $result[] = array_combine($keys, $cells); } } return $result; }


, - $all . - . :
array( 'url' => 'http://www.bn.ru/detail/flats/xxxxxx.html?from=search', 'rooms' => 1, 'address' => '7 ., xxx', 'floors' => '1\\5', 'houseType' => '', 'area' => '30', 'areaLiving' => '18.3', 'areaKitchen' => '6', 'toilet' => ' ', 'price' => '3100', 'conditions' => ' ', 'seller' => 'xxxxx ', 'phone' => '(965) xxxxxxx', 'notes' => ' ', )

HTML .:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Map grabber</title> <script src="//api-maps.yandex.ru/2.0/?load=package.standard&lang=ru-RU" type="text/javascript"></script> <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script> <style> html, body, .#map { margin: 0; padding: 0; } #map { width: 100%; height: 800px; } </style> </head> <body> <div id="map"></div> </body> </html>

jQuery , .

, . JavaScript :
// . var coords = [] // . var info = [] <?foreach ($all as $offer) {?> coords.push('-, <?=$offer['address']?>') info.push(<?=json_encode($offer, JSON_UNESCAPED_UNICODE)?>) <?}?> ymaps.ready(init);

- init() . MultiGeocoder API ; ( coords ), ( ), .

function init() { // -: var map = new ymaps.Map('map', { center: [59.932666, 30.329596], zoom: 13, behaviors: ['default', 'scrollZoom'], }) // : map.controls .add('zoomControl', {left: 5, top: 5}) .add('mapTools', {left: 35, top: 5}) // . (new MultiGeocoder({boundedBy: map.getBounds()})) .geocode(coords) .then( function (res) { // . for (var i = 0; i < res.geoObjects.getLength(); i++) { var cells = info[i] // - // , . var text = '<p>' + $('<b>').append( $('<a>') .attr({href: cells.url, target: '_blank'}) .text(cells.address) )[0].outerHTML + '</p>' // - , . var geo = res.geoObjects.get(i) // . info[i].geo = geo // . geo.properties.set('balloonContentBody', text) } // . map.geoObjects.add(res.geoObjects) }, function (err) { alert(err) } ) return map }

. . , .


?..
, , . ! , , , .

JavaScript , . , . , , , - , , - , .

- . ( API ):
// [ [_, _], ... ]. var markers = [] // <p data-marker="twirl#redDotIcon">. // twirl#redDotIcon - (preset) . $('p[data-marker] input').val(function (i, value) { var marker = $(this).parent().attr('data-marker') value = $.trim(value) value && markers.push([marker, value]) return value }) // (. init()). cells - {price: 123, rooms: 2, ...}. $.each(info, function (i, cells) { var colored = false for (var i = 0; i < markers.length && !colored; i++) { var item = markers[i] var func = new Function('cells', 'return ' + item[1]); // - , . if (func(cells)) { cells.geo.options.set('preset', item[0]) // . colored = true } } // - . colored || cells.geo.options.set('preset', 'twirl#blueIcon') })

, , -, !

, . , .

UPD: Gist . , :)
), - , , DOMNode .

:
// . $all = array(); $baseURL = 'http://www.bn.ru/zap_fl.phtml?print=printall&'; // , . $empty = iconv('utf-8', 'cp1251', ' 0'); // . foreach ((array) $_REQUEST['region'] as $region) { $url = $baseURL."region$region=$region&"; // ... // , 300 - // , 300. foreach (range(0, 10000, 1000) as $price0) { $reqURL = $url."price1=$price0&price2=".($price0 + 999); // - . . $data = dl($reqURL); if (!strpos($data, $empty)) { // . $offers = parse($data); $all = array_merge($all, $offers); } // . usleep(200000); } }

dl() cURL file_get_contents() - , , .

parse() HTML .
function parse($html) { // DOMDocument, UTF-8 ( , // ). $html = '<?xml encoding="UTF-8">'.iconv('cp1251', 'utf-8', $html); $doc = new DOMDocument('1.0', 'utf-8'); @$doc->loadHTML($html) or die('loadHTML: '.$html); // . $xpath = new DOMXPath($doc); // , - // () , . $nodes = $xpath->query('//table[@class="results"]/tr[th[@class="head_kvart"] or td[@width or @class="tooltip"]]'); // . $results = array(); // (, ) - // . $roomCount = 1; // $nodes - - (tr). foreach ($nodes as $row) { // - , .. $cells = array(); $cell = $row->firstChild; while ($cell) { $cell->nodeType == XML_ELEMENT_NODE and $cells[] = trim($cell->nodeValue); $cell = $cell->nextSibling; } if (count($cells) == 1) { // - // . . $roomCount = (int) reset($cells); } else { $cells[0] = $roomCount; // colspan - // . if (count($cells) == 10) { array_splice($cells, 6, 1, array(0, '', $cells[6], '')); } // , . $html = $row->ownerDocument->saveXML($row); if (preg_match('~<a href="([^"]+)~u', $html, $match)) { array_unshift($cells, 'http://www.bn.ru'.$match[1]); } else { array_unshift($cells, ''); } // , . $keys = array('url', 'rooms', 'address', 'floors', 'houseType', 'area', 'areaLiving', 'areaKitchen', 'toilet', 'price', 'conditions', 'seller', 'phone', 'notes'); $result[] = array_combine($keys, $cells); } } return $result; }


, - $all . - . :
array( 'url' => 'http://www.bn.ru/detail/flats/xxxxxx.html?from=search', 'rooms' => 1, 'address' => '7 ., xxx', 'floors' => '1\\5', 'houseType' => '', 'area' => '30', 'areaLiving' => '18.3', 'areaKitchen' => '6', 'toilet' => ' ', 'price' => '3100', 'conditions' => ' ', 'seller' => 'xxxxx ', 'phone' => '(965) xxxxxxx', 'notes' => ' ', )

HTML .:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Map grabber</title> <script src="//api-maps.yandex.ru/2.0/?load=package.standard&lang=ru-RU" type="text/javascript"></script> <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script> <style> html, body, .#map { margin: 0; padding: 0; } #map { width: 100%; height: 800px; } </style> </head> <body> <div id="map"></div> </body> </html>

jQuery , .

, . JavaScript :
// . var coords = [] // . var info = [] <?foreach ($all as $offer) {?> coords.push('-, <?=$offer['address']?>') info.push(<?=json_encode($offer, JSON_UNESCAPED_UNICODE)?>) <?}?> ymaps.ready(init);

- init() . MultiGeocoder API ; ( coords ), ( ), .

function init() { // -: var map = new ymaps.Map('map', { center: [59.932666, 30.329596], zoom: 13, behaviors: ['default', 'scrollZoom'], }) // : map.controls .add('zoomControl', {left: 5, top: 5}) .add('mapTools', {left: 35, top: 5}) // . (new MultiGeocoder({boundedBy: map.getBounds()})) .geocode(coords) .then( function (res) { // . for (var i = 0; i < res.geoObjects.getLength(); i++) { var cells = info[i] // - // , . var text = '<p>' + $('<b>').append( $('<a>') .attr({href: cells.url, target: '_blank'}) .text(cells.address) )[0].outerHTML + '</p>' // - , . var geo = res.geoObjects.get(i) // . info[i].geo = geo // . geo.properties.set('balloonContentBody', text) } // . map.geoObjects.add(res.geoObjects) }, function (err) { alert(err) } ) return map }

. . , .


?..
, , . ! , , , .

JavaScript , . , . , , , - , , - , .

- . ( API ):
// [ [_, _], ... ]. var markers = [] // <p data-marker="twirl#redDotIcon">. // twirl#redDotIcon - (preset) . $('p[data-marker] input').val(function (i, value) { var marker = $(this).parent().attr('data-marker') value = $.trim(value) value && markers.push([marker, value]) return value }) // (. init()). cells - {price: 123, rooms: 2, ...}. $.each(info, function (i, cells) { var colored = false for (var i = 0; i < markers.length && !colored; i++) { var item = markers[i] var func = new Function('cells', 'return ' + item[1]); // - , . if (func(cells)) { cells.geo.options.set('preset', item[0]) // . colored = true } } // - . colored || cells.geo.options.set('preset', 'twirl#blueIcon') })

, , -, !

, . , .

UPD: Gist . , :)

), - , , DOMNode .

:
// . $all = array(); $baseURL = 'http://www.bn.ru/zap_fl.phtml?print=printall&'; // , . $empty = iconv('utf-8', 'cp1251', ' 0'); // . foreach ((array) $_REQUEST['region'] as $region) { $url = $baseURL."region$region=$region&"; // ... // , 300 - // , 300. foreach (range(0, 10000, 1000) as $price0) { $reqURL = $url."price1=$price0&price2=".($price0 + 999); // - . . $data = dl($reqURL); if (!strpos($data, $empty)) { // . $offers = parse($data); $all = array_merge($all, $offers); } // . usleep(200000); } }

dl() cURL file_get_contents() - , , .

parse() HTML .
function parse($html) { // DOMDocument, UTF-8 ( , // ). $html = '<?xml encoding="UTF-8">'.iconv('cp1251', 'utf-8', $html); $doc = new DOMDocument('1.0', 'utf-8'); @$doc->loadHTML($html) or die('loadHTML: '.$html); // . $xpath = new DOMXPath($doc); // , - // () , . $nodes = $xpath->query('//table[@class="results"]/tr[th[@class="head_kvart"] or td[@width or @class="tooltip"]]'); // . $results = array(); // (, ) - // . $roomCount = 1; // $nodes - - (tr). foreach ($nodes as $row) { // - , .. $cells = array(); $cell = $row->firstChild; while ($cell) { $cell->nodeType == XML_ELEMENT_NODE and $cells[] = trim($cell->nodeValue); $cell = $cell->nextSibling; } if (count($cells) == 1) { // - // . . $roomCount = (int) reset($cells); } else { $cells[0] = $roomCount; // colspan - // . if (count($cells) == 10) { array_splice($cells, 6, 1, array(0, '', $cells[6], '')); } // , . $html = $row->ownerDocument->saveXML($row); if (preg_match('~<a href="([^"]+)~u', $html, $match)) { array_unshift($cells, 'http://www.bn.ru'.$match[1]); } else { array_unshift($cells, ''); } // , . $keys = array('url', 'rooms', 'address', 'floors', 'houseType', 'area', 'areaLiving', 'areaKitchen', 'toilet', 'price', 'conditions', 'seller', 'phone', 'notes'); $result[] = array_combine($keys, $cells); } } return $result; }


, - $all . - . :
array( 'url' => 'http://www.bn.ru/detail/flats/xxxxxx.html?from=search', 'rooms' => 1, 'address' => '7 ., xxx', 'floors' => '1\\5', 'houseType' => '', 'area' => '30', 'areaLiving' => '18.3', 'areaKitchen' => '6', 'toilet' => ' ', 'price' => '3100', 'conditions' => ' ', 'seller' => 'xxxxx ', 'phone' => '(965) xxxxxxx', 'notes' => ' ', )

HTML .:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Map grabber</title> <script src="//api-maps.yandex.ru/2.0/?load=package.standard&lang=ru-RU" type="text/javascript"></script> <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script> <style> html, body, .#map { margin: 0; padding: 0; } #map { width: 100%; height: 800px; } </style> </head> <body> <div id="map"></div> </body> </html>

jQuery , .

, . JavaScript :
// . var coords = [] // . var info = [] <?foreach ($all as $offer) {?> coords.push('-, <?=$offer['address']?>') info.push(<?=json_encode($offer, JSON_UNESCAPED_UNICODE)?>) <?}?> ymaps.ready(init);

- init() . MultiGeocoder API ; ( coords ), ( ), .

function init() { // -: var map = new ymaps.Map('map', { center: [59.932666, 30.329596], zoom: 13, behaviors: ['default', 'scrollZoom'], }) // : map.controls .add('zoomControl', {left: 5, top: 5}) .add('mapTools', {left: 35, top: 5}) // . (new MultiGeocoder({boundedBy: map.getBounds()})) .geocode(coords) .then( function (res) { // . for (var i = 0; i < res.geoObjects.getLength(); i++) { var cells = info[i] // - // , . var text = '<p>' + $('<b>').append( $('<a>') .attr({href: cells.url, target: '_blank'}) .text(cells.address) )[0].outerHTML + '</p>' // - , . var geo = res.geoObjects.get(i) // . info[i].geo = geo // . geo.properties.set('balloonContentBody', text) } // . map.geoObjects.add(res.geoObjects) }, function (err) { alert(err) } ) return map }

. . , .


?..
, , . ! , , , .

JavaScript , . , . , , , - , , - , .

- . ( API ):
// [ [_, _], ... ]. var markers = [] // <p data-marker="twirl#redDotIcon">. // twirl#redDotIcon - (preset) . $('p[data-marker] input').val(function (i, value) { var marker = $(this).parent().attr('data-marker') value = $.trim(value) value && markers.push([marker, value]) return value }) // (. init()). cells - {price: 123, rooms: 2, ...}. $.each(info, function (i, cells) { var colored = false for (var i = 0; i < markers.length && !colored; i++) { var item = markers[i] var func = new Function('cells', 'return ' + item[1]); // - , . if (func(cells)) { cells.geo.options.set('preset', item[0]) // . colored = true } } // - . colored || cells.geo.options.set('preset', 'twirl#blueIcon') })

, , -, !

, . , .

UPD: Gist . , :)

), - , , DOMNode .

:
// . $all = array(); $baseURL = 'http://www.bn.ru/zap_fl.phtml?print=printall&'; // , . $empty = iconv('utf-8', 'cp1251', ' 0'); // . foreach ((array) $_REQUEST['region'] as $region) { $url = $baseURL."region$region=$region&"; // ... // , 300 - // , 300. foreach (range(0, 10000, 1000) as $price0) { $reqURL = $url."price1=$price0&price2=".($price0 + 999); // - . . $data = dl($reqURL); if (!strpos($data, $empty)) { // . $offers = parse($data); $all = array_merge($all, $offers); } // . usleep(200000); } }

dl() cURL file_get_contents() - , , .

parse() HTML .
function parse($html) { // DOMDocument, UTF-8 ( , // ). $html = '<?xml encoding="UTF-8">'.iconv('cp1251', 'utf-8', $html); $doc = new DOMDocument('1.0', 'utf-8'); @$doc->loadHTML($html) or die('loadHTML: '.$html); // . $xpath = new DOMXPath($doc); // , - // () , . $nodes = $xpath->query('//table[@class="results"]/tr[th[@class="head_kvart"] or td[@width or @class="tooltip"]]'); // . $results = array(); // (, ) - // . $roomCount = 1; // $nodes - - (tr). foreach ($nodes as $row) { // - , .. $cells = array(); $cell = $row->firstChild; while ($cell) { $cell->nodeType == XML_ELEMENT_NODE and $cells[] = trim($cell->nodeValue); $cell = $cell->nextSibling; } if (count($cells) == 1) { // - // . . $roomCount = (int) reset($cells); } else { $cells[0] = $roomCount; // colspan - // . if (count($cells) == 10) { array_splice($cells, 6, 1, array(0, '', $cells[6], '')); } // , . $html = $row->ownerDocument->saveXML($row); if (preg_match('~<a href="([^"]+)~u', $html, $match)) { array_unshift($cells, 'http://www.bn.ru'.$match[1]); } else { array_unshift($cells, ''); } // , . $keys = array('url', 'rooms', 'address', 'floors', 'houseType', 'area', 'areaLiving', 'areaKitchen', 'toilet', 'price', 'conditions', 'seller', 'phone', 'notes'); $result[] = array_combine($keys, $cells); } } return $result; }


, - $all . - . :
array( 'url' => 'http://www.bn.ru/detail/flats/xxxxxx.html?from=search', 'rooms' => 1, 'address' => '7 ., xxx', 'floors' => '1\\5', 'houseType' => '', 'area' => '30', 'areaLiving' => '18.3', 'areaKitchen' => '6', 'toilet' => ' ', 'price' => '3100', 'conditions' => ' ', 'seller' => 'xxxxx ', 'phone' => '(965) xxxxxxx', 'notes' => ' ', )

HTML .:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Map grabber</title> <script src="//api-maps.yandex.ru/2.0/?load=package.standard&lang=ru-RU" type="text/javascript"></script> <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script> <style> html, body, .#map { margin: 0; padding: 0; } #map { width: 100%; height: 800px; } </style> </head> <body> <div id="map"></div> </body> </html>

jQuery , .

, . JavaScript :
// . var coords = [] // . var info = [] <?foreach ($all as $offer) {?> coords.push('-, <?=$offer['address']?>') info.push(<?=json_encode($offer, JSON_UNESCAPED_UNICODE)?>) <?}?> ymaps.ready(init);

- init() . MultiGeocoder API ; ( coords ), ( ), .

function init() { // -: var map = new ymaps.Map('map', { center: [59.932666, 30.329596], zoom: 13, behaviors: ['default', 'scrollZoom'], }) // : map.controls .add('zoomControl', {left: 5, top: 5}) .add('mapTools', {left: 35, top: 5}) // . (new MultiGeocoder({boundedBy: map.getBounds()})) .geocode(coords) .then( function (res) { // . for (var i = 0; i < res.geoObjects.getLength(); i++) { var cells = info[i] // - // , . var text = '<p>' + $('<b>').append( $('<a>') .attr({href: cells.url, target: '_blank'}) .text(cells.address) )[0].outerHTML + '</p>' // - , . var geo = res.geoObjects.get(i) // . info[i].geo = geo // . geo.properties.set('balloonContentBody', text) } // . map.geoObjects.add(res.geoObjects) }, function (err) { alert(err) } ) return map }

. . , .


?..
, , . ! , , , .

JavaScript , . , . , , , - , , - , .

- . ( API ):
// [ [_, _], ... ]. var markers = [] // <p data-marker="twirl#redDotIcon">. // twirl#redDotIcon - (preset) . $('p[data-marker] input').val(function (i, value) { var marker = $(this).parent().attr('data-marker') value = $.trim(value) value && markers.push([marker, value]) return value }) // (. init()). cells - {price: 123, rooms: 2, ...}. $.each(info, function (i, cells) { var colored = false for (var i = 0; i < markers.length && !colored; i++) { var item = markers[i] var func = new Function('cells', 'return ' + item[1]); // - , . if (func(cells)) { cells.geo.options.set('preset', item[0]) // . colored = true } } // - . colored || cells.geo.options.set('preset', 'twirl#blueIcon') })

, , -, !

, . , .

UPD: Gist . , :)
 ),    -   ,   ,    DOMNode . 

:
// . $all = array(); $baseURL = 'http://www.bn.ru/zap_fl.phtml?print=printall&'; // , . $empty = iconv('utf-8', 'cp1251', ' 0'); // . foreach ((array) $_REQUEST['region'] as $region) { $url = $baseURL."region$region=$region&"; // ... // , 300 - // , 300. foreach (range(0, 10000, 1000) as $price0) { $reqURL = $url."price1=$price0&price2=".($price0 + 999); // - . . $data = dl($reqURL); if (!strpos($data, $empty)) { // . $offers = parse($data); $all = array_merge($all, $offers); } // . usleep(200000); } }

dl() cURL file_get_contents() - , , .

parse() HTML .
function parse($html) { // DOMDocument, UTF-8 ( , // ). $html = '<?xml encoding="UTF-8">'.iconv('cp1251', 'utf-8', $html); $doc = new DOMDocument('1.0', 'utf-8'); @$doc->loadHTML($html) or die('loadHTML: '.$html); // . $xpath = new DOMXPath($doc); // , - // () , . $nodes = $xpath->query('//table[@class="results"]/tr[th[@class="head_kvart"] or td[@width or @class="tooltip"]]'); // . $results = array(); // (, ) - // . $roomCount = 1; // $nodes - - (tr). foreach ($nodes as $row) { // - , .. $cells = array(); $cell = $row->firstChild; while ($cell) { $cell->nodeType == XML_ELEMENT_NODE and $cells[] = trim($cell->nodeValue); $cell = $cell->nextSibling; } if (count($cells) == 1) { // - // . . $roomCount = (int) reset($cells); } else { $cells[0] = $roomCount; // colspan - // . if (count($cells) == 10) { array_splice($cells, 6, 1, array(0, '', $cells[6], '')); } // , . $html = $row->ownerDocument->saveXML($row); if (preg_match('~<a href="([^"]+)~u', $html, $match)) { array_unshift($cells, 'http://www.bn.ru'.$match[1]); } else { array_unshift($cells, ''); } // , . $keys = array('url', 'rooms', 'address', 'floors', 'houseType', 'area', 'areaLiving', 'areaKitchen', 'toilet', 'price', 'conditions', 'seller', 'phone', 'notes'); $result[] = array_combine($keys, $cells); } } return $result; }


, - $all . - . :
array( 'url' => 'http://www.bn.ru/detail/flats/xxxxxx.html?from=search', 'rooms' => 1, 'address' => '7 ., xxx', 'floors' => '1\\5', 'houseType' => '', 'area' => '30', 'areaLiving' => '18.3', 'areaKitchen' => '6', 'toilet' => ' ', 'price' => '3100', 'conditions' => ' ', 'seller' => 'xxxxx ', 'phone' => '(965) xxxxxxx', 'notes' => ' ', )

HTML .:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Map grabber</title> <script src="//api-maps.yandex.ru/2.0/?load=package.standard&lang=ru-RU" type="text/javascript"></script> <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script> <style> html, body, .#map { margin: 0; padding: 0; } #map { width: 100%; height: 800px; } </style> </head> <body> <div id="map"></div> </body> </html>

jQuery , .

, . JavaScript :
// . var coords = [] // . var info = [] <?foreach ($all as $offer) {?> coords.push('-, <?=$offer['address']?>') info.push(<?=json_encode($offer, JSON_UNESCAPED_UNICODE)?>) <?}?> ymaps.ready(init);

- init() . MultiGeocoder API ; ( coords ), ( ), .

function init() { // -: var map = new ymaps.Map('map', { center: [59.932666, 30.329596], zoom: 13, behaviors: ['default', 'scrollZoom'], }) // : map.controls .add('zoomControl', {left: 5, top: 5}) .add('mapTools', {left: 35, top: 5}) // . (new MultiGeocoder({boundedBy: map.getBounds()})) .geocode(coords) .then( function (res) { // . for (var i = 0; i < res.geoObjects.getLength(); i++) { var cells = info[i] // - // , . var text = '<p>' + $('<b>').append( $('<a>') .attr({href: cells.url, target: '_blank'}) .text(cells.address) )[0].outerHTML + '</p>' // - , . var geo = res.geoObjects.get(i) // . info[i].geo = geo // . geo.properties.set('balloonContentBody', text) } // . map.geoObjects.add(res.geoObjects) }, function (err) { alert(err) } ) return map }

. . , .


?..
, , . ! , , , .

JavaScript , . , . , , , - , , - , .

- . ( API ):
// [ [_, _], ... ]. var markers = [] // <p data-marker="twirl#redDotIcon">. // twirl#redDotIcon - (preset) . $('p[data-marker] input').val(function (i, value) { var marker = $(this).parent().attr('data-marker') value = $.trim(value) value && markers.push([marker, value]) return value }) // (. init()). cells - {price: 123, rooms: 2, ...}. $.each(info, function (i, cells) { var colored = false for (var i = 0; i < markers.length && !colored; i++) { var item = markers[i] var func = new Function('cells', 'return ' + item[1]); // - , . if (func(cells)) { cells.geo.options.set('preset', item[0]) // . colored = true } } // - . colored || cells.geo.options.set('preset', 'twirl#blueIcon') })

, , -, !

, . , .

UPD: Gist . , :)
), - , , DOMNode .

:
// . $all = array(); $baseURL = 'http://www.bn.ru/zap_fl.phtml?print=printall&'; // , . $empty = iconv('utf-8', 'cp1251', ' 0'); // . foreach ((array) $_REQUEST['region'] as $region) { $url = $baseURL."region$region=$region&"; // ... // , 300 - // , 300. foreach (range(0, 10000, 1000) as $price0) { $reqURL = $url."price1=$price0&price2=".($price0 + 999); // - . . $data = dl($reqURL); if (!strpos($data, $empty)) { // . $offers = parse($data); $all = array_merge($all, $offers); } // . usleep(200000); } }

dl() cURL file_get_contents() - , , .

parse() HTML .
function parse($html) { // DOMDocument, UTF-8 ( , // ). $html = '<?xml encoding="UTF-8">'.iconv('cp1251', 'utf-8', $html); $doc = new DOMDocument('1.0', 'utf-8'); @$doc->loadHTML($html) or die('loadHTML: '.$html); // . $xpath = new DOMXPath($doc); // , - // () , . $nodes = $xpath->query('//table[@class="results"]/tr[th[@class="head_kvart"] or td[@width or @class="tooltip"]]'); // . $results = array(); // (, ) - // . $roomCount = 1; // $nodes - - (tr). foreach ($nodes as $row) { // - , .. $cells = array(); $cell = $row->firstChild; while ($cell) { $cell->nodeType == XML_ELEMENT_NODE and $cells[] = trim($cell->nodeValue); $cell = $cell->nextSibling; } if (count($cells) == 1) { // - // . . $roomCount = (int) reset($cells); } else { $cells[0] = $roomCount; // colspan - // . if (count($cells) == 10) { array_splice($cells, 6, 1, array(0, '', $cells[6], '')); } // , . $html = $row->ownerDocument->saveXML($row); if (preg_match('~<a href="([^"]+)~u', $html, $match)) { array_unshift($cells, 'http://www.bn.ru'.$match[1]); } else { array_unshift($cells, ''); } // , . $keys = array('url', 'rooms', 'address', 'floors', 'houseType', 'area', 'areaLiving', 'areaKitchen', 'toilet', 'price', 'conditions', 'seller', 'phone', 'notes'); $result[] = array_combine($keys, $cells); } } return $result; }


, - $all . - . :
array( 'url' => 'http://www.bn.ru/detail/flats/xxxxxx.html?from=search', 'rooms' => 1, 'address' => '7 ., xxx', 'floors' => '1\\5', 'houseType' => '', 'area' => '30', 'areaLiving' => '18.3', 'areaKitchen' => '6', 'toilet' => ' ', 'price' => '3100', 'conditions' => ' ', 'seller' => 'xxxxx ', 'phone' => '(965) xxxxxxx', 'notes' => ' ', )

HTML .:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Map grabber</title> <script src="//api-maps.yandex.ru/2.0/?load=package.standard&lang=ru-RU" type="text/javascript"></script> <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script> <style> html, body, .#map { margin: 0; padding: 0; } #map { width: 100%; height: 800px; } </style> </head> <body> <div id="map"></div> </body> </html>

jQuery , .

, . JavaScript :
// . var coords = [] // . var info = [] <?foreach ($all as $offer) {?> coords.push('-, <?=$offer['address']?>') info.push(<?=json_encode($offer, JSON_UNESCAPED_UNICODE)?>) <?}?> ymaps.ready(init);

- init() . MultiGeocoder API ; ( coords ), ( ), .

function init() { // -: var map = new ymaps.Map('map', { center: [59.932666, 30.329596], zoom: 13, behaviors: ['default', 'scrollZoom'], }) // : map.controls .add('zoomControl', {left: 5, top: 5}) .add('mapTools', {left: 35, top: 5}) // . (new MultiGeocoder({boundedBy: map.getBounds()})) .geocode(coords) .then( function (res) { // . for (var i = 0; i < res.geoObjects.getLength(); i++) { var cells = info[i] // - // , . var text = '<p>' + $('<b>').append( $('<a>') .attr({href: cells.url, target: '_blank'}) .text(cells.address) )[0].outerHTML + '</p>' // - , . var geo = res.geoObjects.get(i) // . info[i].geo = geo // . geo.properties.set('balloonContentBody', text) } // . map.geoObjects.add(res.geoObjects) }, function (err) { alert(err) } ) return map }

. . , .


?..
, , . ! , , , .

JavaScript , . , . , , , - , , - , .

- . ( API ):
// [ [_, _], ... ]. var markers = [] // <p data-marker="twirl#redDotIcon">. // twirl#redDotIcon - (preset) . $('p[data-marker] input').val(function (i, value) { var marker = $(this).parent().attr('data-marker') value = $.trim(value) value && markers.push([marker, value]) return value }) // (. init()). cells - {price: 123, rooms: 2, ...}. $.each(info, function (i, cells) { var colored = false for (var i = 0; i < markers.length && !colored; i++) { var item = markers[i] var func = new Function('cells', 'return ' + item[1]); // - , . if (func(cells)) { cells.geo.options.set('preset', item[0]) // . colored = true } } // - . colored || cells.geo.options.set('preset', 'twirl#blueIcon') })

, , -, !

, . , .

UPD: Gist . , :)

Source: https://habr.com/ru/post/184334/


All Articles