понедельник, 29 октября 2012 г.

Auto24.ee оповещатель о поступивших к продаже авто

Не так давно мне потребовалось купить автомобиль.
Так как в Эстонии самый популярный сайт по продаже авто - www.auto24.ee, то присматривал я машину приемущественно на нем. Это небольшое лирическо отсутпление. А суть такова, что на этом портале есть функциональность извещения по эмалу о новых поступивших автомобилях на основе параметров поиска, но она оповещает ещеждевно, в 7 утра об этом. Когда я несколько дней подряд получал эти извещения и звонил по хорошим предложениям владельцам, чтобы договориться о том, когда и где можно посмотреть авто, то получал - "извините, а машина уже продана". Это при всем при том, что я звонил в районе 9-10 часов. Т.е. хорошие предложения как горячие пирожки расходятся.

В итоге я психанул, и написал такой вот маленький скриптик, который бегает по крону каждые 5 минут и присылает прямо мне (и жене) на майл новые объявления о продаже.
Телефон соответственно у меня постоянно синхронизируется с гмайлом. Так же была настроена фильтрация сообщених по заголовку с приминением к этим письмам определенного гмайл ярлыка. На телефоне включена сихрнонизация этого ярлыка и оповещения при каждом полученном эмайле (а не одноразовое при поступлении новых сообщений).

В кронджобе запись выглядит вот так:
*/5 * * * * "php /home1/georgeee/[PATH_TO_SCRIPT]/parse.php parse=true"

GET параметры передаются как аргументы к пхп интерпретатуру, а не как мы привыкли через знак вопроса.

<?php
$url_file = 'url.txt';
$site = 'http://rus.auto24.ee';

if (isset($_GET['url'])) {
    $fp = fopen($url_file, 'w+');
    fputs($fp, $_GET['url']);
    fclose($fp);
    die('SAVED');
}

$current_url = file_get_contents($url_file);

function sendmail($mobiles, $current_url) {
    $message = '
<html>
<head>
  <title>Fresh Mobiles</title>
</head>
<body>
  <p>Добавленные машины за последние 5 минут, соответствующие <a href="' . $current_url . '">таким критериями поиска</a>:</p>
  <ul>
';
    foreach ($mobiles as $m) {
        $s = "<a href='" . $m['url'] . "' target='_blank'>";
        $s .= $m['model'];
        $s .= " [{$m['year']}] ";
        $s .= " [{$m['transmission']}] ";
        $s .= " [{$m['price']} EUR]";
        $s .= "</a>";
        $message .= '<li>' . $s . '</li>';
    }
    $message .= '
  </ul>
</body>
</html>
';

    $headers = 'MIME-Version: 1.0' . "\r\n";
    $headers .= 'Content-type: text/html; charset=utf-8' . "\r\n";
    $headers .= 'From: George Zalizko <george.zalizko@gmail.com>' . "\r\n";
    $headers .= 'To: Natalja Zalizko <natalja.zalizko@gmail.com>' . "\r\n";

    mail('george.zalizko@gmail.com', 'auto24 fresh mobiles', $message, $headers);
}

if (isset($_GET['parse'])) {

    $fp = fopen('db.txt', 'a');

    $already_received = file('db.txt', FILE_IGNORE_NEW_LINES);

    $html = file_get_contents($current_url);

    if (strstr($html, '<div class="infoMessage">Не нашли автомобилей</div>') != false) {
        die();
    }

    $table_pos_start = strpos($html, '<table id="usedVehiclesSearchResult" class="section search-list">');
    $table_pos_end = strpos($html, '<div class="paginator">', $table_pos_start);
    $html_table = substr($html, $table_pos_start, $table_pos_end - $table_pos_start);

    $html_table = mb_convert_encoding($html_table, 'utf-8', mb_detect_encoding($html_table));
    $html_table = mb_convert_encoding($html_table, 'html-entities', 'utf-8');

    $dom = new DOMDocument('1.0', 'UTF-8');
    @$dom->loadHTML($html_table);


    /*
      <tr class="result-row item-odd   ">
      <td class="pictures">
      <a href="/kasutatud/auto.php?id=1152848" class="small-image">
      <img src="http://img1.auto24.ee/auto24/72/521/31396521.jpg" alt="" style="width:74px;height:56px;display:block;border:1px solid"></a>
      </td>
      <td class="make_and_model">
      <a href="/kasutatud/auto.php?id=1152848">Opel Omega 2.2 88 кВ</a>
      <div class="commercial"></div>
      <div class="extra">168&nbsp;000&nbsp;км<span>&nbsp;</span>универсал<span>&nbsp;</span>задний привод</div>
      </td>
      <td class="auction_ttl"></td>
      <td class="year">2001</td>
      <td class="fuel">Д</td>
      <td class="transmission">М</td>
      <td class="pictures" style="padding: 0px;"></td>
      <td class="price">2450</td>
      </tr>
     */

    $xpath = new DOMXPath($dom);
    $entries = $xpath->query("//table/tr[@class]");

    $mobiles = array();
    foreach ($entries as $entry) {
        $price = $xpath->query("td[@class='price']", $entry)->item(0)->nodeValue;
        if (empty($price)) {
            continue;
        }
        $year = $xpath->query("td[@class='year']", $entry)->item(0)->nodeValue;
        $transmission = $xpath->query("td[@class='transmission']", $entry)->item(0)->nodeValue;

        $el_make_and_model = $xpath->query("td[@class='make_and_model']/a", $entry)->item(0);
        $make_and_model = $el_make_and_model->nodeValue;

        $url = $el_make_and_model->getAttribute('href');
        if (!in_array($url, $already_received)) {
            $mobiles[] = array(
                'url' => $site . $url,
                'model' => $make_and_model,
                'year' => $year,
                'price' => $price,
                'transmission' => $transmission
            );
            fwrite($fp, $url . "\n");
        }
    }

    if (!empty($mobiles)) {
        sendmail($mobiles, $current_url);
    }
    fclose($fp);
} else {
    ?>
    <form method="GET" action="<?php echo $_SERVER['PHP_SELF']; ?>">
        <p>
            Current url:<br/>
            <a href="<?php echo $current_url; ?>"><?php echo $current_url; ?></a>
        </p>
        <p>
            <input type="text" name="url"/>
            <input type="submit" value="save"/>
        </p>
    </form>
<?php } ?>

Может кому-нить еще пригодится ;-)

пятница, 5 октября 2012 г.

Spring 3.1 + JPA + DBUnit, Gradle, Maven

В этой коротенькой статье-примере я хотел бы поделиться недавно приобретенным опытом, а именно:
  • Относительно новой возможности Spring Framework-a создавать так называемую Java based configuration, используя для этого фактически обычные POJO объекты с вкраплением анатаций от спринга
  • Написание Unit-тестов для тестировании базы данных. Рассмотрится несколько вариантов. Первый - тестирование базы с помощью Spring test context framework-a. Второй вариант - контекст, как в и первом случае, будет создавать SpringJUnit4ClassRunner.class из набора вышеупомянутого фреймворка, но для тестирования будет использоваться библиотека DBUnit.
  • Вначале проект специально был создан с использованием Maven-a, чтобы потом попробовать Gradle. Расскажу о полученных впечатлениях от Gradle и покажу конфигурацию того и другого.