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

Проектиране на мебели в Blender 3D – ръководство и видео урок

RENDERED етажерка
Ще се опитам да напиша един урок за просто проектиране, моделиране и програмиране на мебели в Blender. Програмата поддържа езика за програмиране Python, който разполага с безкрайни възможност за създаване и управление на обекти. Ще се постарая да се изразявам максимално простичко и ясно.

Необходими инструменти:
1. Молив
2. Лист хартия
3. Blender 3D – по възможност версия 2.67 или по-нова

Първо да скицираме някакъв по-простичък обект (мебел), който искаме да проектираме. Аз ще създам проста етажерка за окачване на стена. За да улесня максимално процеса, моята етажерка ще е от 4 детайла – 2 еднакви по размер страници + 2 една по размер елемента, които ще са гръб и под. Ето как изглежда моята етажерка:
Схема на етажерка
Сега е време да се сблъскаме с назъбения интерфейс на моделера Blender. Програмата е малко плашеща за нови потребители. Но има голямо комюнити и много уроци, които помагат за овладяването и. Лично аз много харесвам тази програма и използвам предимно базовите и фукнции, които често ми олесняват живота. Нека да започнем със забавата.
Стартираме програмата и натискаме Delete бутона от клавиатурата, за да изтрием куба, който се зарежда под дефолт.
Blender 3D interface
Старайте се да не кликате никъде с мишката, докато не разберете каква е логиката на програмата. Кликовете с мишока са:
– Левия клик поставя 3Д-курсора в точката на кликане
– десния клик върху обект го селектира
– Скролирането в 3D фрейма зумва
– Натиснат среден бутон върти 3Д-фрейма
– среден бутон + задържан Shift мести 3Д-фрейма

Има и доста допълнителни команди, но за тях по-късно.

Сега, докато не сме почнали с експериментите, нека разгледаме координатната система. Намира се долу в ляво:
Blender координатна система
Сега да помислим как да си разположим елементите от нашата етажерка:
Проектиране на етажерка
Важно е да се отбележи, че ще използваме метричната система. Това трябва да му го кажем на Blender, иначе ще прави глупости. За целта правим следните настройки:
Елементите, които трябва да създадем в 3Д са:
– 2 броя страници: 18x240x222mm
– 2 броя плоскости за гръб и под: 850x222x18mm
Тези елементи по-късно ще ги добавим в нашия програмен код. Размерите на всеки елемент могат да се групират в масив. Примерно такъв:
stranici=[0.018, 0.240, 0.222]
gryb=[0.850, 0.222, 0.018]
dyno=[0.850, 0.018, 0.222]

Можем да ги създадем по поне 10 начина, но аз ще ви покажа един много нестандартен подход, който често се оказва най-оптимален и бърз вариант. Ще използвам много просто програмиране на Python. За целта трябва да отворим редактора за въвеждане на Python скриптове. Това също може да стане по много начини, но аз ще използвам предефинираните полета на Blender:
Кликнете бутона Choose Screen layout и изберете Scripting
Blender scripting
Кликнете на бутона +New
Blender new script
!!! Супер важно: Старайте се курсора на мишката винаги да е във фрейма в който работите. Примерно, ако искате да въвеждате текст в текстовия редактор, курсора ви трябва да е в този прозорец (фрейм).
В текстовия редактор пейстнете следния код:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import bpy
 
strani=[0.018, 0.240, 0.222]
gryb=[0.850, 0.222, 0.018]
dyno=[0.850, 0.018, 0.222]
 
# създаваме 2-те страници. Те лежат в едно направление
# и можем да използваме цикъл
for x in range(2): # изпълни 2 пъти
    bpy.ops.mesh.primitive_cube_add(radius=1)
    bpy.context.object.dimensions=strani
 
# създаваме гръб
bpy.ops.mesh.primitive_cube_add(radius=1)
bpy.context.object.dimensions=gryb
 
# създаваме пода
bpy.ops.mesh.primitive_cube_add(radius=1)
bpy.context.object.dimensions=dyno

Прозореца със скрипта трябва да изглежда така:
Blender Python script
Командите:

1
2
bpy.ops.mesh.primitive_cube_add
bpy.context.object.dimensions

са въведени в API-интерфейса на Blender. Всяка версия на програмата има документация в която са описани всички команди, които могат да се изпълняват от програмата. Как лесно да разберем коя команда как се ползва ще опиша някой друг път.

Сега трябва да изпълним кода. Натискаме Text->Run Script:
Blender run script
От тук насетне следва местене и рендване в Blender. Действията, които съм извършил в програмата, могат да се видят в по-долното видео:

Vim Editor – Видео урок

Преди доста време бях правил видео за редактора Vim. Направих го за мен, а и заради едни приятели от форум, който посещавах.
Скоро ми се наложи пак да ползвам Vim editor на едно Linux дистро и бях малко като пате в кълчища. За това качвам урока, та другият път да изкарам един бърз курс, ако ми се наложи.

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

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

Bootstrap 3 dropdown login form example

Търсих си неразкрасена логин форма за Bootstrap 3. Трябваше да я набутам в бутон на на nav-панела. Не намерих нищо свястно, ам тя работата е елементарна. Ще покажа 2 различни примера.
Bootstrap login form - dropdown, popover
BS3 Login form с popover и html код разположен някъде в страницата:
Javascript – поставя се най-долу в кода на страницата

1
2
3
4
5
6
7
$('button[data-toggle=popover]').popover({ 
    html : true,
    //trigger: "click", // може да се смени
    content: function() {
      return $('#popover_content_wrapper').html();
    }
});

HTML-кода:

1
2
3
4
5
6
7
8
9
10
11
12
<div id="popover_content_wrapper" style="display: none">
  <form action="" role="form">
    <div class="form-group">
      <label for="user">User</label>
      <input type="text" class="form-control" id="user" placeholder="User" />
      <label for="password">Password</label>
      <input type="password" class="form-control" id="password" placeholder="Password" />
    </div>
      <button type="submit" class="btn btn-default">Sign in</button>
 
  </form>
</div>

BS3 Login form с dropdown:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<li>
 
  <div class="dropdown">
    <button type="button" class="btn btn-default navbar-btn" data-toggle="dropdown">Login</button>
 
    <div class="dropdown-menu" style="padding: 10px; background: #ddd">
      <form action="" role="form">
        <div class="form-group">
          <label for="user">User</label>
          <input type="text" class="form-control" id="user" placeholder="User" />
          <label for="password">Password</label>
          <input type="password" class="form-control" id="password" placeholder="Password" />
        </div>
        <button type="submit" class="btn btn-default">Sign in</button>
      </form>
    </div>
  </div>
 
</li>

Пример с 2-те форми може да се види тук:
Bootstrap 3 dropdown login form example

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

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

CSS – Attribute Selectors

CSS – Attribute Selectors

CSS разполага с няколко “странни” символа, които в други езици са известни като wildcards. Тези символи представляват селектори на текст и могат да съвпадат с части от текста.

  • [att^=val] – започва с “val”
  • [att$=val] – завършва с “val”
  • [att*=val] – съдържа “val”

Атрибут селекторите могат да се използват за всякакви атрибути на таговете, като класове (.class1, class2…) или идентификатори(#id1, id2…), href, title, name и т.н.

Примери за прилагане на стилове с атрибут селектора “започва с”:
begin with css selector
The “begins with” CSS selector – DEMO

Примери за прилагане на стилове с атрибут селектора “завършва с”:
ends with css selector
The “ends with” CSS selector – DEMO

Примери за прилагане на стилове с атрибут селектора “съдържа”:
contains css selector
The “contains” CSS selector – DEMO