Браузер
Автор
Владимир Лучанинов
Мне часто приходится обрабатывать информацию с других сайтов и наконец я решил написать свой компонент Browser.
Функциональные возможности
- Корректно разделяет header и body
- Может кешировать запросы
- Может отправлять POST-запросы
- Может работать через proxy
- Поддерживает cookies
- Может автоматически вводить имя пользователя и пароль
- Автоматически подставляет referer с прошлой страницы (можно установить свой)
- Подставляет нормальный UserAgent, чтобы сайты не думали, что это робот
Использовать компонент, как и все компоненты для CakePHP очень легко.
1. Добавьте в контроллер сверху
var $components = array('Browser');
2. В функции контроллера можно использовать
$body = $this->Browser->get('http://php.southpark.com.ua/');
$header = $this->Browser->header; // необязательно
Перед get, можно настроить параметры
$this->Browser->userAgent = 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)';
$this->Browser->username = 'root';
$this->Browser->password = 'upyachka';
$this->Browser->proxy = '192.168.0.1:3128';
$this->Browser->referer = 'http://php.southpark.com.ua/';
$this->Browser->timeout = 10; // по умолчанию 30 секунд
Правильно было бы написать тест, который проверяет все функции, но я и так молодец, что
написал хоть какой-то тест :) Когда вы пишете свои компоненты, не забывайте писать тесты.
Кстати, корректно разбивать header и body не так просто. В идеале, они должны разделяться
\r\n\r\n. Но на практике мне встечались
\r\n\n\r\n\n и
\n\r\n\r. Вдобавок иногда бывает несколько header, например, при redirect.
Для того, чтобы заработало кеширование, создайте папку
APP/tmp/cache/browser и дайте права на запись в неё.
Чтобы работали cookie, дайте права на запись в папку
APP/tmp. Там будет создан файл
cookie.txt.
Остальные функции – это просто обёртка над
CURL.
app\controllers\components\browser.php
<?
/**
* Эмулятор браузера
*
* @version 1.2 (14 Oct 2007)
*
*/
class BrowserComponent extends Object {
var $handle;
var $header;
var $body;
var $userAgent = 'random';
// если нужно логиниться
var $username = null;
var $password = null;
var $proxy = ''; // 'ip:port'
var $referer = 'http://www.google.com/';
var $timeout = 30;
/**
* Если вы хотите кешировать запросы, то создайте папку APP/tmp/cache/browser
*
* @var unknown_type
*/
var $cacheFolder = null;
var $symbolsNotFile = array( '~', '!', '@', '#', 'http://', '/', "\\", ':', '*', '?', '"', '<', '>', '|');
var $symbolsFile = array('~~', '!!', '@@', '##', '#~', '~!', '~@', '~#', '!~', '!@', '!#', '@~', '@!', '@#'); // ещё можно использовать '#!', '#@'
/**
* Init handle for connection
*
* @param AppController $controller
*/
function startup(&$controller) {
$cacheFolder = APP . 'tmp' . DS . 'cache' . DS . 'browser' . DS;
if (is_dir($cacheFolder)) {
$this->cacheFolder = $cacheFolder;
}
$this->_initUserAgent();
$this->handle = curl_init();
}
function _setHeaderBody($response) {
$regex = '/(.*?)\n[\r\n]*?\n+(.*)/sm';
$this->header = '';
if (!preg_match($regex, $response, $m)) {
$this->body = $response;
} else {
$this->header = $m[1];
$this->body = ltrim($m[2], "\r");
// sometimes there are several headers
while (strpos($this->body, 'HTTP/')==0 && preg_match($regex, $this->body, $m)) {
$this->header .= "\n\n" . $m[1];
$this->body = ltrim($m[2], "\r");
}
}
return true;
}
/**
* Main function
*
* @param string $url
* @param array $postvars
* @return string body
* after execution $this->header is accessible if needed
*/
function get($url, $postvars=null) {
if (!empty($this->cacheFolder) && empty($postvars)) {
$cacheFile = $this->cacheFolder . r($this->symbolsNotFile, $this->symbolsFile, $url).'.txt';
} else {
$cacheFile = null;
}
if (!empty($cacheFile) && file_exists($cacheFile)) {
$response = file_get_contents($cacheFile);
} else {
$this->prepare($url, $postvars);
$response = curl_exec($this->handle);
if (!empty($cacheFile)) {
file_put_contents($cacheFile, $response);
}
}
$this->referer = $url;
$this->_setHeaderBody($response);
return $this->body;
}
/**
* Set default options of curl
*
* @param string $url
* @param array $postvars
*/
function prepare($url, $postvars=false) {
curl_setopt($this->handle, CURLOPT_PROXY, $this->proxy);
curl_setopt($this->handle, CURLOPT_REFERER, $this->referer);
curl_setopt($this->handle, CURLOPT_USERAGENT, $this->userAgent);
curl_setopt($this->handle, CURLOPT_URL, str_replace('&','&',$url));
curl_setopt($this->handle, CURLOPT_HEADER, 1);
curl_setopt($this->handle, CURLOPT_FOLLOWLOCATION,1);
curl_setopt($this->handle, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($this->handle, CURLOPT_TIMEOUT, $this->timeout);
curl_setopt($this->handle, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($this->handle, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($this->handle, CURLOPT_COOKIEJAR, APP.'tmp/cookie.txt');
curl_setopt($this->handle, CURLOPT_COOKIEFILE, APP.'tmp/cookie.txt');
if (!empty($postvars)) {
curl_setopt($this->handle, CURLOPT_POST, 1);
curl_setopt($this->handle, CURLOPT_POSTFIELDS, $postvars);
}
if (!empty($this->username)) {
curl_setopt($this->handle, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
curl_setopt($this->handle, CURLOPT_USERPWD, $this->username.':'.$this->password); // $auth should be [username]:[password]
}
return true;
}
/**
* Close current connection
*
*/
function close() {
curl_close($this->handle);
return true;
}
/**
* Clears cache
*/
function clearCache() {
if (empty($this->cacheFolder)) return false;
$dir = dir($this->cacheFolder);
while (($file = $dir->read()) !== false) {
if (in_array($file, array('', '.', '..'))) continue;
unlink($dir->path . $file);
}
return true;
}
/**
* What browser should be emulated
*
* @return string browser name
*/
function _initUserAgent() {
if ($this->userAgent!='random') return true;
$browsers = array(
'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0)',
'Mozilla/4.0 (compatible; MSIE 6.0; Windows 98)',
'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)',
'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3705)',
'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 2.0.50727; .NET CLR 1.1.4322)',
'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Avant Browser; .NET CLR 2.0.50727)',
'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; en) Opera 9.10',
'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; FunWebProducts)',
'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MRA 4.8 (build 01709); Maxthon; .NET CLR 1.1.4322; .NET CLR 2.0.50727)',
'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ru) Opera 8.50',
'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; ru) Opera 8.54',
'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)',
'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705)',
'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Media Center PC 4.0; .NET CLR 2.0.50727)',
'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)',
'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30)',
'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727; MAXTHON 2.0)',
'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727)',
'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; .NET CLR 1.1.4322; InfoPath.1)',
'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30)',
'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; InfoPath.2; .NET CLR 1.1.4322; MAXTHON 2.0)',
'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; InfoPath.1)',
'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; InfoPath.2)',
'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MRA 4.7 (build 01670); .NET CLR 1.1.4322)',
'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MRA 4.7 (build 01670); InfoPath.1)',
'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MRA 4.8 (build 01709))',
'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MRA 4.8 (build 01709); .NET CLR 1.1.4322)',
'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MRA 4.8 (build 01709); .NET CLR 2.0.50727; InfoPath.2; .NET CLR 1.1.4322; .NET CLR 3.0.04506.30)',
'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MRA 4.8 (build 01709); Maxthon; .NET CLR 2.0.50727; .NET CLR 1.1.4322; .NET CLR 3.0.04506.30)',
'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MyIE2; InfoPath.1)',
'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MyIE2; MRA 4.8 (build 01709); .NET CLR 1.1.4322; InfoPath.1)',
'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.1.4322)',
'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; SV1; .NET CLR 1.1.4322)',
'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)',
'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)',
'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322)',
'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.1)',
'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 2.0.50727)',
'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 2.0.50727; .NET CLR 1.1.4322; InfoPath.1)',
'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Avant Browser; Avant Browser; .NET CLR 1.1.4322)',
'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Maxthon)',
'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Maxthon; Avant Browser; InfoPath.2)',
'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Maxthon; MyIE2; .NET CLR 1.0.3705; .NET CLR 2.0.50727; InfoPath.2)',
'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; MRA 4.6 (build 01425); InfoPath.1)',
'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; MRA 4.8 (build 01709))',
'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; MRA 4.8 (build 01709); .NET CLR 1.1.4322; InfoPath.1)',
'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; MRA 4.8 (build 01709); Avant Browser)',
'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; MRA 4.9 (build 01863); .NET CLR 2.0.50727)',
'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; MyIE2)',
'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; MyIE2; .NET CLR 2.0.50727; InfoPath.1; .NET CLR 1.1.4322; MEGAUPLOAD 1.0)',
'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506; InfoPath.2; .NET CLR 1.1.4322)',
'Mozilla/5.0 (Windows; U; Windows NT 5.1; bg; rv:1.8.1.3) Gecko/20070309 Firefox/2.0.0.3',
'Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.8.0.11) Gecko/20070312 Firefox/1.5.0.11',
'Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.8.1.3) Gecko/20070309 Firefox/2.0.0.3',
'Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.8.1.4) Gecko/20070515 Firefox/2.0.0.4',
'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.8.1.3) Gecko/20070309 Firefox/2.0.0.3',
'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.3) Gecko/20070309 Firefox/2.0.0.3',
'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.4) Gecko/20070515 Firefox/2.0.0.4',
'Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.8.0.11) Gecko/20070312 Firefox/1.5.0.11',
'Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.8.1.3) Gecko/20070309 Firefox/2.0.0.3',
'Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.8.1.4) Gecko/20070515 Firefox/2.0.0.4',
'Mozilla/5.0 (Windows; U; Windows NT 5.1; ru-RU; rv:1.7.12) Gecko/20050919 Firefox/1.0.7',
'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.1) Gecko/20060313 Fedora/1.5.0.1-9 Firefox/1.5.0.1 pango-text',
'Mozilla/5.0 (X11; U; Linux i686; ru; rv:1.8) Gecko/20060112 ASPLinux/1.5-1.2am Firefox/1.5',
'Opera/8.54 (Windows NT 5.1; U; en)',
'Opera/9.00 (Windows NT 5.1; U; ru)',
'Opera/9.01 (Windows NT 5.1; U; ru)',
'Opera/9.02 (Windows NT 5.0; U; ru)',
'Opera/9.02 (Windows NT 5.1; U; ru)',
'Opera/9.02 (Windows NT 5.2; U; en)',
'Opera/9.10 (Windows NT 5.1; U; ru)',
'Opera/9.20 (Windows NT 5.1; U; en)',
'Opera/9.20 (Windows NT 5.1; U; ru)',
'Opera/9.21 (Windows NT 5.1; U; ru)',
);
$this->userAgent = $browsers[array_rand($browsers)];
return true;
}
}
?>