Архивы для категории ‘Тонкости’.

Уйти от скриптов?

Постоянно читаю отклики разработчиков высоконагруженных приложений (коими парсеры и грабберы также являются) и просто стараюсь отслеживать что происходит в мире программирования и понемногу начинаю приходить к мысли, что при разработке самых крупных проектов надо отходить от скриптовых языков программирования и обращаться ко всяким там C++, C# и им подобным.

И по этому поводу хочу спросить, что думаю мои подписчики. Кто что пробовал? Какие тесты видели на эту тему? Какие шишки набили? Где многопоточность лучше показала себя? Что успели попробовать? Не молчите - выскажитесь! Поделитесь своим опытом, а другие поделятся с вами. И так все станут хоть на грамм умнее и эффективней!

Спасибо!

Увеличиваем отказоустойчивость парсинга/граббинга

Как я уже отмечал ранее, базы данных в последнее время становятся узким местом для приложений, предназначенных для парсинга, граббинга и сбора информации. Это связано с тем, что сейчас практически любой движок построен на основе четырех десятков таблиц и тучи сложных запросов, а когда на одном хостинге таких движков находится штук 100, то многого просить от БД не приходится, даже с учетом того, что MySQL (а чаще всего хостеры используют именно его) – чертовски быстрая штука при правильной настройке.

Эта проблема стала для меня очень остро ставать, когда мои клиенты начали жаловаться, что разработанные мною парсеры не делают своей работы. Я стал разбираться и пришел к выводу, что с подобными проблемами даже сложнее бороться, чем с тем же segfault.

Например, на одном из хостингов клиента при запуске парсера через 20-30 минут MySQL выдавал «MySQL server has gone away» и после этого вся далее собранная информация уходила в трубу. Также не редкими были проблемы, когда MySQL просто умирал от нагрузок (понятное дело, что не со стороны моих парсеров). Я начал искать решение данной проблемы. Пробовал даже разработать систему отложенного выполнения запросов, ставил таймауты, когда не мог выполнить запрос. В общем, думал я над этой проблемой и пришел к выводу, что проще всего всю информацию записывать в CSV или SQL dump файл, а по окончании парсинга одним запросом выгружать это в БД.

У этого решения есть ряд преимуществ:

  • файловая система намного устойчивей к перегрузкам, чем БД
  • файловая система не уступает по производительности БД (особенно на публичных хостингах)
  • за нагрузки на файловую систему вам не сделают втык админы сервера, в отличии от БД

Но также есть и некоторые недостатки у подобного подхода:

  • сложнее ВИЗУАЛЬНО контролировать процесс сбора информации (это проблема для тех, кто привык смотреть как заполняются его базы данных :))
  • невозможно использовать информацию «на лету» - всегда надо дожидаться завершения парсинга

То есть данное решение стоит применять, например, в ночных парсерах для больших массивов данных. Так что советую людям, которые собирают информацию взять данную идею на заметку. Конечно же эти проблемы не касаются тех, у кого стоит с 10 выделенных серверов на гигабитном инете ;)

Где я?

Очень часто в процессе парсинга информации наши скрипты циклически проходят набор каких-либо урлов.

Если парсинг идет с одного источника с изменением, например, некоторых GET или POST параметров, то в любую единицу времени вы можете точно определить месторасположение своего скрипта. Но бывают случаи когда массив урлов собирается, например, с поисковика. И все было бы хорошо, если бы человек не придумал такую штуку как редирект и если бы ваш заказчик не требовал заносить УРЛ конечной страницы в базу данных.

А можете ли вы однозначно утверждать, что урл, который вы достали из выдачи Гугла однозначно равен урлу, на который зашел ваш скрипт и на котором он производил поиск информации? Если вы говорите “ДА”, то вы сильно ошибаетесь. Можете попробовать поэкспериментировать с такими запросами к Google как “Viagra” - половина сайтов будут либо дорвеями, либо прочими видами редиректеров.

И, поверьте, это всего лишь одна из ситуаций, когда в процессе парсинга/граббинга надо точно определять урл страницы, на которой находится ваш скрипт.

В качестве других типичных примеров можно привести сборы урлов из каталогов компаниий или каталогов галерей картинок. Как часто вы видите подобные урлы: http://www.site.com/redirect.php?id=700? Понятное дело, что подобное записывать в поле URL в своей базе просто стыдно :), потому что через пару часов вы уже не сможете гарантировать, что вышеуказанная ссылка будет ссылаться на тот сайт, на котором вы произвели поиск информации.

Я столкнулся с подобной проблемой при работе над одним проектом по сбору картинок с галерей изображений. Редиректеры вытворяли что-то нереальное: одна и таже ссылка на редиректере вела на разные сайты. И даже не надо было ждать пару часов - это происходило ежесекундно!

И это бы ничего, ведь даже file() умеет следовать редиректам. Но ведь заказчик потребовал в базе в отдельное поле писать конечный URL…

Решить данную проблему можно достаточно просто и вариантов ее решение есть несколько.

Самым разумным и быстрым из них будет использование функции curl_getinfo. И вообще я бы советовал всем программистам, которые используют библиотеку curl присмотреться к этой функции, ведь бывают ситуации, когда она может быть очень полезной.

Вот типичный пример использования данной функции в одном из моих классов:

function GetLastURL() {
	return curl_getinfo($this->curl_handler, CURLINFO_EFFECTIVE_URL);
}

В результате использования данной незатейливой функции вы получите последний урл, куда был перенаправлен ваш скрипт.

А что же делать, если вы не пользуетесь функционалом curl’a, а используете, например, file_get_contents()? Тогда прийдется немного поиграться в функцией stream_get_meta_data(). Вот типичное решение, которое я использовал в одном из своих проектов, где по ТЗ нельзя было использовать CURL:

$content = file_get_contents($url);
$fp = fopen($url,'r');
$meta_data = stream_get_meta_data($fp);
foreach($meta_data['wrapper_data'] as $response) {
	if (substr(strtolower($response), 0, 10) == 'location: ') {
		$last_url = substr($response, 10);
	}
}
fclose($fp);

Из данного кода я убрал все проверки и прочие функции, которые не имеют непосредственного отношения к обсуждаемой теме.

Как мы видим второе решение намного более громоздкое по количеству написанного кода, да и ограничений у него побольше будет. Но тем не менее каждый из вышеуказанных вариантов имеет право на жизнь.

Пользуйтесь ими на здоровье в своих парсерах, грабберах и анализаторах и не никогда не теряйтесь! ;)

Оптимизируем работу с регулярными выражениями. 2 простые функции.

Главным оружием любого профессионального парсера являются регулярные выражение (особенно перловые PCRE). И я, если честно, вообще не представляю как без них можно делать просто и быстро свою работу.

Одним словом просто прелесть. И эту прелесть мы каждый день используем.

Сечас я приведу 2 классических варианта использования регулярных выражений:

if (preg_match("/$price_find/Ui",$content,$m)) {
        unset($m[0]);
	$price=mysql_escape_string(trim($m[1]));
} else {
        $price='';
}
 
if (preg_match_all("/$blocks_find/Ui",$content,$m)) {
	unset($m[0]);
        $blocks=$m[1];
} else {
        $blocks=array();
}

На первый взгляд довольно таки простой код. Ни отнять, ни прибавить. А теперь представьте, что вам надо искать по 100 параметров на странице. И тогда этот код начнет непомерно расти и станет для вас настоящим наказанием. В подобных случаях я использую две небольшие функции, которые действительно упрощают мне жизнь и уменьшают время, затрачиваемое на разработку:

function pregm($what, $where, $return=1, $keys='Ui') {
	$search="/$what/$keys";
	if (preg_match($search,$where,$matches)) {
		unset($matches[0]);
		if ($return==1) {
			return $matches[1];
		} else {
			return $matches;
		}
	} else {
		return false;
	}
}
 
function pregma($what, $where, $return=1, $keys='Ui') {
	$search="/$what/$keys";
	if (preg_match_all($search,$where,$matches)) {
		unset($matches[0]);
		if ($return==1) {
			return $matches[1];
		} else {
			return $matches;
		}
	} else {
		return false;
	}
}

Благодаря этим функциям весь начальный код можно преобразовать к следующему виду:

$price=mysql_escape_string(trim(pregm($price_find,$content));
$blocks=pregma($blocks_find,$content);

Вот так все просто. Мы сократили объем кода в несколько раз и сделали его более прозрачным и простым.

Конечно же если регулярные выражения вы используете два раза в год, то прибегать к данной библиотеке нет смысла, но если регулярки - ваша повседневная работа, то вам надо максимально использовать вышеупомянутый код и даже развить его под свои нужны. Так я, например, в случаях, когда надо найти большое количество параметров, использую массивы. Вот пример:

$param=array(
'Название',
'Цена',
'Размер',
'Автор'
//...
);
 
$find=array();
 
// Получаем контент и делаем прочие преобразования
 
foreach ($param as $key=>$item) {
	$find_it=$item."\:(.*)$";					
        $find[$key]=strip_tags(pregm($find_it,$block));
}

Получится, что в массиве $find у нас будут все найденные параметры. Потом можно просто сделать implode("','",$find), добавить пару кавычек и практически целиком залить эту строку в базу. Получается очень быстро и удобно.

Суть этой заметки. Регулярные выражения - мощный инструмент, а свои надстройки над ними - еще более мощный и удобный инструмент!

Новый рекорд

На очередном заказе я поставил новый личный рекорд по количеству собранных данных (отдельно собранные ссылки, картинки и прочее в счет не берем):

230 000 записей!

База собиралась изначально в 2 потока, а потом в 5 в течении 3х дней. В процессе работы над этим заказом я понял:

  • Что мне нужно купить новый компьютер :) (что я уже удачно и сделал);
  • Что для каждого проекта нужно писать контроллер процесса выполнения, чтобы случайная остановка сайта-источника на пару часов не останавливала процесс сбора информации и не привела к искривлению данных в базе;
  • Что в php memory_limit нужно ставить в значение 64М и постоянно вести мониторинг ресурсов, а то кто бы что не говорил, но php “течет” и это факт, доказанный практикой;
  • Что нужно проводить оптимизацию регулярных выражений (этому я думаю посвятить отдельную статью).

Думаю, что некоторые из этих мыслей могут быть полезны другим про в области сбора информации.

Особенно важным моментом является контроль процесса выполнения. В каждом конкретном случае его можно реализовать по разному и я вот сейчас работаю над созданием универсального класса. Как только будут первые наработки - я сразу же отпишу про это в очередной заметке.

Обнаружение и удаление дублирующихся записей

В данной заметке я хочу затронуть вопрос нахождения и удаления дублирующихся записей в MySQL.

И это касается не только вопроса сбора информации. Предлагаемые методы будут очень полезны начинающих программистам, которые ищут оптимальное решение в данном вопросе.

Для того, чтобы было проще объяснять код я создам тестовую таблицу work с ней буду производить свои эксперименты.

Таблица work имеет следующую структуру:

CREATE TABLE work( 
 id mediumint(8) UNSIGNED NOT NULL AUTO_INCREMENT, 
 region varchar(255) NOT NULL, 
 job_mask varchar(255) NOT NULL, 
 job_group varchar(255) NOT NULL, 
 job_info text, 
 PRIMARY KEY(id));

Вдаваться в тонкости создания таблиц мы не будем, так как это не является целью данной статьи.

Предположим, что таблица work уже заполнена данными.

Теперь вам надо оставить в таблице только уникальные данные в поле job_info для каждого значения region, job_group, job_mask.

Первым делом вы должны определить есть ли у вас дублирующиеся данные и сколько их (ведь если их нет, то вам и делать ничего не надо). Для этого вам стоит выполнить следующий запрос:

SELECT COUNT(*) AS dub, region, job_group, job_mask, job_info 
FROM work GROUP BY region, job_group, job_mask, job_info HAVING dub>1;

В результате выполнения запроса вы увидите таблицу с уже знакомыми вам полями и с дополнительным полем dub, которое будет содержать количество дублирующихся записей.

Далее удаление можно организовать следующими путями:

  1. Циклический обход-1.
    Данный метод я называю “циклический обход-1″, потому что одну запись мы всегда оставляем не тронутой.

    Реализуется данные метод следующим способом:

     
     // соединение с БД  
     
     $query='SELECT COUNT(*) AS dub, region, job_group, job_mask, job_info 
     FROM work GROUP BY region, job_group, job_mask, job_info HAVING dub>1'; 
     $res=$db->query($query); 
     if(!$res) { 
    	echo $db->error(); 
     } else { 
    	while($row=$db->fetchAssoc($res)) { 
    	        $region=$row['region']; 
      	        $job_mask=$row['job_mask']; 
      	        $job_group=$row['job_group']; 
    	        $job_info=$row['job_info']; 
     
    	        $query="SELECT id FROM work 
    WHERE region='$region' AND job_mask='$job_mask' 
    AND job_group='$job_group' AND job_info='$job_info'"; 
     
    		$result=$db->query($query); 
    		if(!$result) { 
    			echo $db->error(); 
    		} else { 
    			$i=1; 
    			while ($subrow=$db->fetchArray($result)) { 
    				if ($i==1) { 
    				    $i++; 
    				    continue; 
    				} 
     
    				$query="DELETE FROM work 
                                                 WHERE id='{$subrow[0]}'"; 
    				$del_res=$db->query($query); 
    				if(!$del_res) { 
    					echo $db->error(); 
    				} else { 
    					$deleted++; 
    				} 
    				$i++; 
    			} 
    		} 
    	} 
    }

    Методы объекта $db, которые используются по ходу выполнения скрипта, являются методами моего стандартного абстрактного класса для доступа к БД. Имена методов очень тесно переплетаются с именами стандартных функций для работы с MySQL, поэтому я не вижу смысла останавливаться на этом более детально.

    В своих скриптах вы можете использовать привычные вам инструменты.

    Главным преимуществом данного решения есть простота. Однако есть и очень большой недостаток - низкая скорость выполнения. На больших таблицах с большим количеством записей данный скрипт будет выполняться очень долго. Так что не забудьте поставить лимит времени и лимит памяти побольше.

  2. Использование запроса SELECT.
    Второй вариант решения поставленной проблемы также достаточно распространен и предполагает некоторые знания в области SQL.Далее я приведу несколько запросов направленных на удаление дублирующихся записей и дам детальное их описание.

    Выборка уникальных данных в отдельную таблицу. Реализуется данный метод следующим образом:

     CREATE TABLE original 
     SELECT DISTINCT * FROM work ORDER BY id;

    Данный запрос создаст таблицу original с оригинальными значениями, выбранными из таблицы work.

    Также можно использовать следующую модификацию вышеуказанного выражения:

     CREATE TABLE original 
     SELECT * FROM work GROUP BY region, job_group, job_mask, job_info 
     ORDER BY id;

Дополнительная информация:

P.S. Думаю, что для начала этого инструментария будет достаточно. Но я не оставляю данную тему и надеюсь в ближайшем будущем предоставить дополнительную информацию по обработке дублирующихся записей в MySQL.

Получаем от Google больше 1000 ссылок

Статистика назойливо показывает, что на мой сайт каждый день приходят посетители по запросу “больше 1000 ссылок в Google” и ему подобным. Поэтому я решил вынести тему получения более 1000 ссылок в выдаче Google в отдельный пост.

Итак. Есть следующие основные пути получения в выдаче более 1000 сайтов:

  1. Использование дополнительного оператора (иногда еще называют модификатора) site.

    Расскажу как можно это использовать на простом примере.Например вам надо собрать 5 000 ссылок по запросу “sex” (первое что пришло в голову).

    Тогда вы можете составить следующий список запросов для выполнения своим парсером:

    sex site:com
    sex site:org
    sex site:net
    sex site:info
    sex site:biz

    Это соберет все сайт, в чьих доменных именах есть слово sex и которые принадлежат к зоне com, net, org, info и biz. Если же надо собрать все сайты, которые просто содержат это слово и принадлежат к вышеуказанным доменам, то надо выполнить следующие запросы (сделать небольшую перестановку):

    site:com sex
    site:org sex
    site:net sex
    site:info sex
    site:biz sex

    И в результате распарсив выдачу Гугла вы получите желанные 5 000 ссылок.

    Также на некоторых форумах я видел новомодный метод сбора только доменных имен с “-” в имени. Для нашего запроса он будет имеет следующий вид:

    sex site:com -site:*com

    Данный запрос соберет все домены, у которых в имени есть слово sex и “-” (тире). Однако люди занимающиеся SEO знают, что домены с тире в имени попадают под некоторые определенные фильтры Гугла, что само по себе понижает их ценность. Но если уж слишком надо, то можно и таким запросом пользоваться.

    Для получения всех сайтов, у которых в доменном имени есть тире и на которых упоминается про sex опять надо немного перекрутить запрос:

    site:com -site:*com sex

    При помощи подобных инструментов можно получить просто немерянно ссылок по практически любому запросу. Особенно ВЧ англоязычному.

    Полный список доменных зон для подобных махинаций с запросами вы можете найти тут: ccTLD (региональные) | gTLD (general).

  2. Использование уточняющих слов.

    Про это я уже детально рассказывал. Главное - просто добавляйте к своему запросу еще по уточняющему слову.

  3. Синонимизация.

    Очень непростой и неоднозначный инструмент, которым, по моим наблюдениям, пользуются только некоторые профи.

    Принцип действия данного метода достаточно простой. Собирается (или чаще всего покупается) база синонимов. Потом на основе этой базы делается замена слов в запросе на синонимы. Таким образом вы увеличивается массу собранных ссылок.

    Хотя со своей стороны могу сказать, что я подобным методом не пользовался, так как при его использовании очень сложно контролировать качество выдачи. Понятное дело, если вам нужно насобирать базу каких-то досок или форумов для спама по определенной тематике, то вам абсолютно все равно какого качества идет выдача, но я, например, подобным не занимаюсь, а для статистических исследований качество выдачи имеет чуть-ли не главную роль.Поэтому советую оставить данный метод “про запас”.

  4. Танцы с бубном и прочими оператора (модификаторами) Гугла.

    Это такой обобщенный метод. Используется в основном для сбора баз для спама, поэтому я расскажу о нем вкратце.Метод основан на использовании всевозможнейших операторов: inurl, intitle …

    В основном спамеры используют запросы с inurl: script.php, что помогает им находить определенные движки, которые они умеют спамить. Но это совсем не интересно и не ко мне.

Дополнительная информация:

  1. ccTLD
  2. gTLD
  3. описание основных операторов (/модификаторов) запросов к Google
  4. Google Hacks (2nd Edition) (книга про всевозможнейшие трюки с запросами)

Кодекс чести парсинг-самурая

Данную заметку я написал для людей, которые всерьез занимаются парсингом и сбором информации.

Я читаю очень много профильных изданий на тему парсинга и вижу, что профи в этой области беспокоятся лишь об одном - чтобы их скрипты не забанил источник информации.

Как по мне это совершенно неправильно, ведь помните как говорится - “Поступай с ближним так, как ты хочешь чтобы он поступал с тобой”. И исходя из этого изречения я постарался сформулировать несколько тезисов для профипарсеров:

  1. Перед началом работы проанализируйте статистику сайта-источника и выберите оптимальное для парсинга время.
    В настоящее время сделать это достаточно просто, так как большинство интересных и стоящих сайтов участвуют во множестве рейтингов, где можно увидеть их посещаемость не только по дням, но и по часам, что особенно важно. Благодаря этому вы можете подобрать время, когда сервер максимально разгружен. Чаще всего это период между 3-7 часами утра.
    Но это не значит, что вы должны в 3 часа утра сидеть перед компом. От вас требуется всего лишь нормально настроить свой компьютер, веб-сервер, поставить на компе будильник (есть такая опция в BIOS Setup) и правильно настроить крон для запуска скриптов.
    А если вы используете сервер хостера, то и того проще - просто поставить скрипт на крон.
    У этого совета есть еще и практически полезная сторона - в ненагруженные часы вы будете получать ответы от сервера-источника на порядок быстрее, чем в “час-пик”, что ускорить парсинг информации и поможет избежать перегрузок на второй стороне.
  2. Разбивайте процесс парсинга на максимальное количество независимых процессов.
    Очень часто процесс парсинга является двухуровневым или даже трехуровневым (или еще лучше сказать двухпроходным или трехпроходным), то есть происходит в несколько этапов: сбор ссылок -> парсинг страницы или проход каталога -> сбор ссылок (или прочих параметров) -> парсинг конечных страниц.
    И я в своей работе каждый этап стараюсь реализовать разными скриптами и запускать их в разные промежутки времени, чтобы снизить нагрузку на конечный сервер.
    Это очень удобно и в практическом плане позволяет разделить логику работы скрипта, что несомненно улучшает контроль за процессом и позволяет сделать этапы сбора информации независимыми.
    Конечно же минусом такого разбиения является увеличение времени разработки. Но поверьте, если проект крупный, то затраченное на этой стадии время окупится вам с лихвой.
  3. Ставьте паузы между запросами.
    Это важный момент (и парсеры поисковиков знают о чем я говорю :)). И вам не стоит его игнорировать.
    Если ваш парсинг предполагает обработку большого объема информации, то вам стоит добавить между запросами небольшие паузы, которые помогут разгрузить удаленный сервер. В противном случае вы можете забить пул запросов и сайт-источник может плавно умереть. И это поверьте мне это очень плохо, потому что тогда ваши действия могут трактовать как (D)DoS-атаку, а это уже уголовно наказуемо.
    В своей работе работе я, в основном, использую паузы длиной 100-500 мск.
  4. Используйте весь возможный инструментарий для снижения объемов передаваемой информации.
    При возможности (если это позволяет сервер-источник) используйте Content-Range в своих HTTP запросах (у curl для этого есть опция CURLOPT_RANGE). Это позволит вам сэкономить как свой траффик, так и траффик сервера-источника.
    К моему удивлению, Яндекс чего-то не захотел обрабатывать данный HTTP запрос.

Это основные правила, которых, как я считаю, должен придерживаться каждый профи и в основе которых лежит уважение к работе других.

И на последок хочу напомнить, что ваш парсер/граббер в определенный промежуток времени создает нагрузку на порядок больше, чем броузер обычного пользователя. Ведь у парсера не тратится время на рендеринг, парсер не подгружает картинки (если вы ему этого не сказали) и поэтому парсер “листает” страницы сайта-источника на порядок быстрее, чем пользователь. Поэтому не стоит наращивать скорости, потому что вы можете просто “завалить” сервер-источник.

Дополнительные ссылки:

4 шага к правильному сбору и обработке информации

Данная статья призвана помочь начинающим программистам (или даже их менеджерам), которые всерьез решили заняться сбором и обработкой информации.

Для работы над любым удачным проектом по сбору и обработке информации нужно:

  1. Определить все значимые параметры собираемой информации.
    Это очень важный этап, который все непонятно почему пытаются пройти как можно быстрее (наверное хотят побыстрее заработать).
    Пример.
    Заказчик попросил вас собрать базу компаний и вы без особых размышлений кинулись в бой.
    Но тут не стоит спешить. Надо уточнить:

    • по какому региональному признаку отбирать компании?
    • каким видом деятельности должны заниматься отбираемые компании?
    • какой юридической формы собственности надо отбирать предприятия?

    Нужно собрать как можно больше значимых признаков.

    Тут я привел очень простой пример, но на практике даже небольшое уточнение поможет сделать вашу работу быстрее и лучше.

  2. Найти источник информации
    На данном этапе следует произвести детальный поиск источника (источников) информации, который максимально удовлетворил бы всем значимым параметрам, которые вы определили в пункте 1. И поверьте мне, это не так уж и просто, как может показаться на первый взгляд. Поэтому я советую вам не концентрироваться на поиске какого-то одного идеального источника, а составить какую-то небольшую таблицу вариантов, из которых вы потом сможете выбрать самый лучший.
  3. Определить форму представления информации
    Если вам надо собирать все подряд и как попало, то этот этап вы можете смело откинуть.
    В противном случае стоит определить какие параметры вам стоит собирать, а какие не стоит.
    Например, очень часто у меня появляются заказы на сбор базы данных людей. Например, IT специалистов. Источником для такой информации выступают сайты поиска работы и профессиональные сайты. Но на том же сайте поиска работы в IT специалисты попадают даже наборщики текстов, которые, понятное дело, не нужны моему заказчику. Поэтому на основе данных, полученных в пункте 1, я составляю список совпадений и исключений, который и использую при сборе и анализе информации.
  4. Выбрать средства для сбора информации
    Для меня это очень просто – настроил парсер (хотя мне больше нравится слово паук) и в бой.
    А если у вас нет соответствующих навыков, то вы можете заказать подобную услугу у профессионалов, либо прибегнуть к каким-то программным средствам, которые уже далеко не редкость.Тут главное подобрать что-то достаточно гибкое и быстрое. Скорости стоит уделить особое внимание, потому что порой приходится собирать базы в миллионы записей и промедления даже в доли секунды на таких объемах будут значимыми.

Вот и все. Надеюсь, что мне удалось дать вам понимание процесса качественного сбора и анализа информации.

Если у вас будут вопросы, заказы или предложения – свяжитесь со мной.

Удачи!

Google limits

Данную статью я назвал Google Limits, потому что в ней я хочу рассказать о некоторых ограничениях поиска в Гугл:

  1. Запрос не должен превышать 32х слов (раньше было 10);
  2. Количество запросов с одного IP не должно превышать 25 000 в сутки.

По поводу первого числа у меня нет сомнений, а вот по поводу второго они все-таки возникают. Хотя на практике еще не приходилось подходить к барьеру в 25 000 запросов.

Надо будет как-то на эксперименте проверить.