Amascrap – amazon price scraper

Amazon price scraper - извличане и проследяване на цени
Amascrap е програма тип “web scraper”, която извлича и логва цени от Amazon.co.uk. Програмата е базирана на PHP, HTML, Javascript (jQuery). Вградил съм Traktor на цените, за да имат някаква проследяемост във времето. Скриптовете могат да се използват и като Web-сайт.

Програмата я написах за мен, защото често ми се налага да пазарувам от Amazon.co.uk. Забелязах, че в сайта доста продукти си сменят цените през няколко дни и има значение, дали ще си купиш нещо с 10 паунда по-ниска цена. Все пак съм си българче :). Traktora позволява да следиш, през колко време някой продукт си сменя цената, което си е идеална статистика. Помогна ми да разбера, че някои продукти имат абсолютно точен цикъл на смяна на цената. Особено добре се вижда преди или след празници.
Не съм писал демон за автоматичен ъпдейт, за това цените трябва да се ъпдейтват ръчно. При много продукти и ъпдейт на всички се получава лаг, който няма как да се избегне. Все пак нямам достъп до базата данни на Амазон, нит ползвам API. Чист и класически Web-скрапер с XPath и cURL под PHP.
За GUI използвах PHP Desktop с MSIE (не ме целете с камъни, просто Chrome вдигна много мегабайтите).

Кратък видео урок, как се работи с програмата:

Програмата с сорс-кода може да се изтегли от тук:
Amascrap v.0.04 – Ъпдейт на 13.06.2016. Оправени са проблеми при сваляне на данните през HTTPS.

Laravel – root dir post-request

Има един досаден бъг в Laravel 4.2. Не иска да обработва post-заявка, насочена към root-адреса. Говоря за това:

1
2
3
Route::post('/',function(){
 // ...
});

В такива случаи Laravel сеправи на чук и просто рефрешва страницата.
Открих 2 трики-метода за заобикаляне на бъг-а:
1. Поставя се шпация, ако формата е насочена към текущата страница:

1
{{Form::open(array('url'=>' ','method'=>'post'))}}

2. Пишем точно към кой адрес е насочена формата:

1
{{Form::open(array('url'=>'/index.php','method'=>'post'))}}

Извличане на цветове от картинка с php

Имам една идея за автоматична смяна на цветната схема на Bootstrap-базиран сайт. За целта ми трябва просто извличане на цветовете от картинка с php-скрипт.
За базови цветове създавам проста картинка с квадратчета, като тази:
php extract color from image
За да извлека цветовете от отделните квадратчета използвам php-функцията imagecolorat, която взима цвета на пиксел при зададени кооординати. Координатната система е нулирана в горния ляв ъгъл:
imagecolorat - coordinates
Примерен скрипт в който използвам извличане цвета на пиксел, който се намира горе-долу по средата на всеки правоъгълник:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?php
// $rgb е array
function rgb2hex($rgb) {
   $hex = "#";
   $hex .= str_pad(dechex($rgb[0]), 2, "0", STR_PAD_LEFT);
   $hex .= str_pad(dechex($rgb[1]), 2, "0", STR_PAD_LEFT);
   $hex .= str_pad(dechex($rgb[2]), 2, "0", STR_PAD_LEFT);
 
   return $hex;
}
 
function get_color_from_pixel($img, $x, $y){
    $im = imagecreatefrompng($img);
    $rgb = imagecolorat($im, $x, $y);
    $r = ($rgb >> 16) & 0xFF;
    $g = ($rgb >> 8) & 0xFF;
    $b = $rgb & 0xFF;
 
    return rgb2hex(array($r, $g, $b));
}
 
// ===================================================
// EXAMPLE
 
$image = "image.png";
$y = 24;
$x_ar = array(33, 103, 177, 244, 315, 385, 454, 526, 593);
 
foreach ($x_ar as $x) {
    $colors[] = get_color_from_pixel($image, $x, $y);
}
print_r($colors);
?>

Резултат:

1
2
3
4
5
6
7
8
9
10
11
12
Array
(
    [0] => #36261c
    [1] => #d5c187
    [2] => #6ecddf
    [3] => #827b3a
    [4] => #2a7d94
    [5] => #9db079
    [6] => #82796d
    [7] => #a7c6da
    [8] => #d54c06
)

Изтегляне на скрипта и картинката: PHP-get_colors_from_image.zip

PHP рекурсивно обхождане на дървовидна база данни

Много често се налага да се работи с дървовидни бази данни. С тях могат да се изграждат структури с дъщерни елементи, като например дървовидни менюта за сайт с категория, подкатегория, секция.
Ето едно примерно обхождане на подобна база данни с рекурсия:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<?php
$arr = array(
    // $id, $parent_id, $name
    array(1, 0, "edno"),
    array(2, 0, "dve"),
    array(3, 1, "edno-edno"),
    array(4, 3, "edno-edno-edno"),
    array(5, 1, "edno-dve"),
    array(6, 2, "dve-edno"),
    array(6, 1, "edno-tri")
);
 
function recurse($arr, $pid, $space = '') {
    $output = '<ul>';
 
    foreach ($arr as $key => $ar) {
 
        if ($ar[1] == $pid) {
 
            $output .= "<li>" . $ar[2] . "\n";
            // iztrivane na obhodenite elementi
            $pid_temp = $ar[0];
            unset($arr[$key]);
 
            if ($children = recurse($arr, $pid_temp, $space . '_')) {
                if ($children != '<ul></ul>')
                    $output .= $children;
            }
            $output .= "</li>";
        }
    }
 
    return $output . "</ul>";
}
 
echo recurse($arr, 0, '');

В резултат се получи една чудесна списъчна структура:
Дървовидно обхождане с рекурсия

Netbeans дебъгване на PHP-код с Xdebug

Не знам защо до сега не съм използвал възможностите за дебъгване на PHP. Може би от глупост, щото едва ли не ми се е налагало. Е, да но вече като знам, че е добре да се дебъгва, едва ли ще пропусна да използвам тази благинка.
Нямам по-читав редактор за PHP, освен портабъл версия на Netbeans 7.4. Няма инсталирана и чиста Java (необходима, за да работи IDE-то), за това ще използвам портабъл версия – OpenJDKPortable_7_Update_9_b02_Development_Test_1.paf.exe.
Портабъл версиите понякога се държат много идиотски. А защо не използвам инсталатори е една друга тема. И за да работи всичко както трябва се наложи да направя простотията да инсталирам 3-те “инструмента” в следните директории:
NetBeans 7.4: C:\installed\soft\NetBeans_PHP_7.4_Portable
OpenJDK 7: C:\installed\soft\CommonFiles\java
PHP 5.4.23: C:\installed\soft\php

След стартиране на NetBeans, видях, че всичко е наред, само дето не му работеше дебъгването. Това се оправя по следния начин:
1. Download на php_xdebug-2.2.5-5.4-vc9-nts.dll от тук
2. Записва се в директорията: C:\installed\soft\php\ext
3. Редактира се файла php.ini, като в края му се добавя:
zend_extension='C:\installed\soft\php\ext\php_xdebug-2.2.5-5.4-vc9-nts.dll'
xdebug.remote_enable=on
xdebug.remote_handler=dbgp
xdebug.remote_host=localhost
xdebug.remote_port=9000

И почва да се пие бира и да се дебъгва неистово.

Guest Blogging Articles – система за гест-статии

Article-X е проста система за писане на статии от гост-потребители. Системата я написах така, че да наподобява малко CMS. Може да се настройва.
Article-X - guest blogging system
Подробности и видео урок как се ползва могат да се намерят тук:
Aricle-X – Guest Blogging System
Фронт-демо на системата тук.

PHP-file UTF-8 encoding

Попаднах на стар хостинг (с php 5.2.3), който прецаква енкодинга при ъплауд на php-файлове. Изключително досаден проблем. Пробвах да вкарвам разни дивотии в .htaccess, но нищо не помогна. Ей такива неща опитах:

AddDefaultCharset utf-8
AddCharset utf-8 .php
DefaultLanguage en-US

Единствения шанс, който ми остана беше да накарам интерпретатора да каже на сървара, че файла трябва да се излъчи в UTF-8 encoding. По-долния код се поставя преди рендването на съдържанието:

<?php header('Content-Type: text/html; charset=utf-8'); ?>

Доста удобно за моя стил на програмиране :).

Apache and PHP Server Session not working

Това е един прост трик, който задължително трябва да знаете, ако ви се прецакват PHP-сесиите на локалния компютър. При мен се получи при 2 различни версии на XAMPP. Задължително тествайте сайта, като в адресната лента не пишете “localhost” или “127.0.0.1”, а пишете iP-то, което имате в мрежата ви.
Това може да се види, като се изкара един промпт и в него пишете:

ipconfig /all

… или командата “ifconfig”, ако ползвате Linux.

PHP image change order – смяна на подредбата на картинки

Искаше ми се да подобря някои галерии които съм правил за разни сайтове. Не знам как до сега не съм се сетил да вкарам нещо толкова полезно и толкова дребно, като кодиране, като смяната на подредбата или последователността (change order).
PHP picture change order
Ще покжа прост пример, като ще използвам обикновена текстова база данни със следното съдържание:

a=>edno
b=>dve
c=>tri
d=>chetiri
e=>pet

И php скрипта:

<?php
$act = $_GET['act'];
$id = $_GET['id'];
 
$x=0;
 
if( isset($act) && ($act == 'up' || $act == 'down')){
	$arf = file("db.txt");
	foreach($arf as $line){
		list($k, $v) = preg_split('/=>/', rtrim($line));
		$input[$k] = $v;
		if($k == $id){
			$xp = $x;
		}
		$x++;
	}
	$inkey = array_keys($input);
	$inval = array_values($input);
	if($act == 'up'){
		$prevord = array_slice($inval, $xp-1, 1);
		$previd = array_slice($inkey, $xp-1, 1);
		$curord = array_slice($inval, $xp, 1);
 
		$prevord = $prevord[0];
		$previd = $previd[0];
		$curord = $curord[0];
		$curid = $id;
 
		$input[$previd] = $curord;
		$input[$curid] = $prevord;
 
		foreach ($input as $key => $val){
			$write .= $key."=>".$val."\r\n";
		}
		file_put_contents("db.txt", $write);
		header("Location:sortar.php");
		exit;
	} else {
		$nextord = array_slice($inval, $xp+1, 1);
		$nextid = array_slice($inkey, $xp+1, 1);
		$curord = array_slice($inval, $xp, 1);
 
		$nextord = $nextord[0];
		$nextid = $nextid[0];
		$curord = $curord[0];
		$curid = $id; // c
 
		$input[$nextid] = $curord;
		$input[$curid] = $nextord;
 
		foreach ($input as $key => $val){
			$write .= $key."=>".$val."\r\n";
		}
		file_put_contents("db.txt", $write);
		header("Location:sortar.php");
		exit;
	}
}
 
 
 
 
$arf = file("db.txt");
foreach($arf as $line){
	list($k, $v) = preg_split('/=>/', rtrim($line));
	$input[$k] = $v;
}
 
$inkey = array_keys($input);
$inval = array_values($input);
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<style type="text/css">
body {background: #ededed;}
table {border-collapse:separate; border-spacing:5px; }
table tr td {border: 1px solid #fff;}
table tr td:first-child {background: #ddd;}
table tr td:first-child a {text-decoration: none; color: blue; font-weight: bold; font-size: 24px;}
</style>
</head>
 
<body>
	<table>
	<?php
	for($x=0; $x<count($inval);$x++){ ?>
		<tr>
		<?php if($x==0){ ?>
			<td><a href="sortar.php?act=down&id=<?php echo $inkey[$x]; ?>" >\/</a></td>
			<td><img src="img/<?php echo $inval[$x]; ?>.jpg"></td><td><?php echo $inkey[$x]; ?></td>
		<?php } elseif($x==(count($inval)-1)){ ?>
			<td><a href="sortar.php?act=up&id=<?php echo $inkey[$x]; ?>" >/\</a></td>
			<td><img src="img/<?php echo $inval[$x]; ?>.jpg"></td><td><?php echo $inkey[$x]; ?></td>
		<?php } else { ?>
			<td><a href="sortar.php?act=up&id=<?php echo $inkey[$x]; ?>" >/\</a>
			<a href="sortar.php?act=down&id=<?php echo $inkey[$x]; ?>" >\/</a></td>
			<td><img src="img/<?php echo $inval[$x]; ?>.jpg"></td><td><?php echo $inkey[$x]; ?></td>
		<?php } ?>
		</tr> <?php
	}?>
	</table>	
</body>
</html>

Демо може да се види тук: PHP change order images

PHP XPath command line graber – for Windows and Linux

Написах скромно скриптче на PHP за прилагане на XPath изрази през командния ред. Скрипта изисква инсталиран Lynx или, ако се ползва под Windows трябва да се постави Lynx в същата директория. Готиното на това програмче е, че не се интересува дали има грешки в страницата.

<?php
if ($argc != 3 || in_array($argv[1], array('--help', '-help', '-h', '-?'))) {
?>
 
This is a XPath extractor.
 
  REQUIRES:
  "lynx" to be installed!
 
  USAGE:
  <?php echo $argv[0]; ?> <site> <xpath>
 
  EXAMPLE:
  <?php echo $argv[0]; ?> http://site.com/some_page.html "//a[contains(@href,\"?rec\") and not(contains(@href,\"comment\"))]/@href"
  --------------------
 
  With the --help, -help, -h,
  or -? options, you can get this help.
 
<?php
} else {
$site=$argv[1];
function get_cont($url){
$c = `lynx -source $url`;
return $c;
}
$html = get_cont($site);
$dom = new DOMDocument();
@$dom->loadHTML($html);
$xpath = new DOMXPath($dom);
$hrefs = $xpath->evaluate($argv[2]);
for ($i = 0; $i < $hrefs->length; $i++) {
	$bb = $hrefs->item($i)->nodeValue;
	print "$bb\n";
}
}
?>

Начин на употреба:

php xpath.php site.com/some_page.html "//a[contains(@href,\"?rec\") and not(contains(@href,\"comment\"))]/@href"

Остава да успея и да го компилирам :). За сега съм пробвал с Bambalam compiler, Roadsend, phc и още няколко по-незнайни емдера и компилатора, но … дърво от всякъде. Все пак, ако си имате инсталиран php и Lynx си работи идеално.
Lynx за Winblowz може да се ползва от тук: Lynx for Windows
Причината да използвам конзолния браузер Lynx е, че много сайтове използват gzip компресия на страниците, за да се зареждат по-бързо. Така не ми се налага да правя еквилибристики от сорта на:

wget -O - somesite.com | gunzip -c