Browse Source

initial commit

master
mxmehl 3 years ago
commit
920f6f44ff
3 changed files with 403 additions and 0 deletions
  1. +2
    -0
      .gitignore
  2. +15
    -0
      config.php.sample
  3. +386
    -0
      index.php

+ 2
- 0
.gitignore View File

@@ -0,0 +1,2 @@
config.php
angebote.json*

+ 15
- 0
config.php.sample View File

@@ -0,0 +1,15 @@
;<?php
;die(); // For further security
;/*

[general]
# "url" has to contain page indicator (/P-x/). This is not existent on the first search result page but can be added manually
url = "https://www.immobilienscout24.de/Suche/S-2/P-1/Wohnung-Miete/Nordrhein-Westfalen/Koeln/70_6_118_39_20_101_2_50_11_56_120/2,00-3,00/-80,00/EURO--900,00/-/-/false/-/-/true/-/-/true"
db = "angebote.json"

[mail]
to = "to@example.com"
from = "from@example.com"

;*/
;?>

+ 386
- 0
index.php View File

@@ -0,0 +1,386 @@
<?php

$config = parse_ini_file("config.php", true);
$db = $config['general']['db'];
$queryurl = $config['general']['url'];

// make backup of database
$db_bak = $db . ".bak_" . date('Y-m-d');
if (! file_exists($db_bak)) {
copy($db, $db_bak);
}

// Called via CLI or web?
if (defined('STDIN')) {
$do = $argv[1];
} else {
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$do = isset($_POST['do']) ? $_POST['do'] : false;
} else {
$do = isset($_GET['do']) ? $_GET['do'] : false;
}
}

// define action via "do" parameter
if ($do === "download") {
immo_download($db);
} else if ($do === "update") {
immo_update($db);
} else if ($do === "show" || $do == "") {
immo_show($db);
} else {
echo "No valid do action defined";
}

/////////////////////
/// do = DOWNLOAD ///
/////////////////////
function immo_download($db) {
global $data;
global $queryurl;
global $config;
read_db($db);
$site = xsite($queryurl); // load and transform URL (page 1) to queryable $site
// get amount of available pages
$searchPages = $site->query('//div[@id="pageSelection"]/select');
$pages = $searchPages->item(0)->childNodes->length;
// create a dynamic url in which the current page number can be set in
$queryurldyn = str_replace("/P-1/", "/P-%page%/", $queryurl);
// loop through available pages
for ($page = 1; $page <= $pages; $page++) {
$queryurlcur = str_replace("%page%", $page, $queryurldyn);
echo "Current search page: " . $queryurlcur . "<br />\n";
$site = xsite($queryurlcur); // load and transform URL of current page
// get all links to expose pages
$searchResult = $site->query('//a[@class="result-list-entry__brand-title-container"]/@href');

// loop through web search results
foreach($searchResult as $result){
global $data;
$new = "y"; // is the search entry new?
// extract ID of link
preg_match("/\d+$/",$result->textContent, $matches);
$id = $matches[0];
$id = (int)$id; // convert to int value
$total = count($data);
for ($row = 0; $row < $total; $row++) {
if ($id === $data[$row]['id']) {
$new = "n"; // entry isn't new anymore
}
}
if ($new === "y") { // entry is new
// load and transform expose URL
$site = xsite("https://www.immobilienscout24.de/expose/" . $id);
// description
$searchResult = $site->query('//h1[@id="expose-title"]');
$desc = trim($searchResult->item(0)->nodeValue);
$desc = mb_convert_encoding($desc, 'UTF-8', 'UTF-8'); // remove/replace invalid characters
$descs = substr($desc, 0, 15);
$descs = mb_convert_encoding($descs, 'UTF-8', 'UTF-8');
// flat available from
$searchResult = $site->query('//dd[@class="is24qa-bezugsfrei-ab grid-item three-fifths"]');
$bezug = trim($searchResult->item(0)->nodeValue);
// warm rent
$searchResult = $site->query('//dd[@class="is24qa-gesamtmiete grid-item three-fifths font-bold"]');
$mietew = trim($searchResult->item(0)->nodeValue);
// cold rent
$searchResult = $site->query('//dd[@class="is24qa-kaltmiete grid-item three-fifths"]');
$mietek = trim($searchResult->item(0)->nodeValue);
// rooms
$searchResult = $site->query('//dd[@class="is24qa-zimmer grid-item three-fifths"]');
$zimmer = trim($searchResult->item(0)->nodeValue);
// size
$searchResult = $site->query('//dd[@class="is24qa-wohnflaeche-ca grid-item three-fifths"]');
$qm = trim($searchResult->item(0)->nodeValue);
// location
$searchResult = $site->query('//div[@class="address-block"]');
$ort = trim($searchResult->item(0)->nodeValue);
$ort = str_replace("(zur Karte) ", "", $ort);
$ort = str_replace("Die vollständige Adresse der Immobilie erhalten Sie vom Anbieter.", "", $ort);
// append new array entry
$data[] = array("id" => $id,
"date" => date('d.m. H:i'),
"desc" => $desc,
"descs" => $descs,
"bezug" => $bezug,
"mietew" => $mietew,
"mietek" => $mietek,
"ort" => $ort,
"zimmer" => $zimmer,
"qm" => $qm,
"rating" => 0,
"status" => "NEU",
"note" => "");
// send mail for new item
$mailcontent = "*" . $desc . "* \r\n\r\n" .
"Bezug: " . $bezug . "\r\n" .
"Miete: " . $mietew . "/" . $mietek . "\r\n" .
"Größe: " . $qm . "\r\n" .
"Zimmer: " . $zimmer . "\r\n" .
"Ort: " . $ort . "\r\n" .
"Link: https://www.immobilienscout24.de/expose/" . $id . "\r\n\r\n" .
"Übersicht: https://" . $_SERVER["SERVER_NAME"] . $_SERVER["PHP_SELF"];
mail($config['mail']['to'], "Neues Wohnungsinserat: " . $descs . "...", $mailcontent, "From: " . $config['mail']['from'] . "\r\nMIME-Version: 1.0\r\nContent-Type: text/plain; charset=UTF-8");
echo $id . " is new and has been downloaded.<br />\n";
} else { // entry is old
echo $id . " already exists.<br />\n";
}
} // END foreach &searchResult
} // END for loop through pages

echo "<p><a href='.'>Back to overview</a></p>\n";
write_db($db, $data);
}

/////////////////
/// do = SHOW ///
/////////////////
function immo_show($db) {
global $data;
global $queryurl;
read_db($db);
$hide = isset($_GET['hide']) ? $_GET['hide'] : "yes";
?>

<!DOCTYPE html>
<html lang="de-DE">
<head>
<title>Immobilienscout Search Helper</title>
<meta charset="UTF-8" />
<style type="text/css">
table {
border-collapse: collapse;
}
table, th, td {
border: 1px solid orange;
}
th, td {
padding: 3px 2px;
}
tr:nth-child(even) {
background-color: #f2f2f2
}
tr:hover {background-color: #FFECBA}
textarea, input, select {
vertical-align: middle;
height: 3em;
}
input[type="submit"] {
border: 1px solid #888;
height: 20px;
padding: 0;
width: 2em;
}
a.btn {
background-color: #98b879;
color: #fff;
font-weight: 700;
padding: 10px;
text-decoration: none;
text-transform: uppercase;
}
#message {
background-color: #FFE990;
margin-bottom: 8px;
padding-left: 20px;
}
</style>
</head>
<body>
<div id="message">
<?php
session_start();
if ( ! empty($_SESSION['message'])) {
echo $_SESSION['message'];
$_SESSION['message'] = NULL;
}
?>
</div>
<table>
<tr>
<th>Datum</th>
<th>Beschreibung</th>
<th>Status</th>
<th>Bezug</th>
<th>Miete warm (kalt)</th>
<th>Zi</th>
<th>Größe</th>
<th>Ort</th>
<th style="min-width:140px">Notiz</th>
<th style="min-width:140px">Status ändern</th>
</tr>
<?php
// Sort for date descending when displaying
foreach ($data as $key => $row) {
$date[$key] = $row['date'];
$id[$key] = $row['id'];
}
array_multisort($date, SORT_DESC, $id, SORT_DESC, $data);
$total = count($data);
for ($row = 0; $row < $total; $row++) {
$id = $data[$row]['id'];
$date = $data[$row]['date'];
$desc = $data[$row]['desc'];
$descs = $data[$row]['descs'];
$bezug = $data[$row]['bezug'];
$mietew = $data[$row]['mietew'];
$mietek = $data[$row]['mietek'];
$zimmer = $data[$row]['zimmer'];
$qm = $data[$row]['qm'];
$ort = $data[$row]['ort'];
$status = $data[$row]['status'];
$note = $data[$row]['note'];
$link = "https://www.immobilienscout24.de/expose/" . $id;
if ($status !== "del" || $hide === "no") {
echo "<tr>";
echo "<td>" . $date . "</td>";
echo "<td><span title='" . $desc . "'><em><a target='_blank' href='" . $link . "'>" . $descs . "...</a></em></span></td>";
echo "<td>" . $status . "</td>";
echo "<td>" . $bezug . "</td>";
echo "<td>" . $mietew . " (<em>" . $mietek . "</em>)" . "</td>";
echo "<td>" . $zimmer . "</td>";
echo "<td>" . $qm . "</td>";
echo "<td><a target='_blank' href='https://www.openstreetmap.org/search?query=" . $ort . "'>" . $ort . "</a></td>";
echo "<td>";
?>
<form action="" method="POST">
<input name="do" value="update" type="hidden" />
<input name="id" value="<?php echo $id; ?>" type="hidden" />
<textarea name="note" rows="1" cols="14"><?php echo $note; ?></textarea>
<input type="submit" value="OK">
</form>
<?php
echo "</td>";
echo "<td>";
?>
<form action="" method="POST">
<input name="do" value="update" type="hidden" />
<input name="id" value="<?php echo $id; ?>" type="hidden" />
<select name="status">
<option value="del">löschen</option>
<option value="alt">alt</option>
<option value="NEU">NEU</option>
<option value="kontaktiert">kontaktiert</option>
<option value="abgelehnt">abgelehnt</option>
<option value="termin">termin</option>
</select>
<input type="submit" value="OK">
</form>
<?php
echo "</td>";
echo "</tr>\n";
}
}
?>
</table>
<p>Letztes Update: <?php echo date('d.m.Y H:i:s', filemtime($db)); ?></p>
<p>Gelöschte Inserate <a href="?hide=no">einblenden</a> / <a href=".">ausblenden</a></p>
<p>Suchlink: <a target="_blank" href="<?php echo $queryurl; ?>">Klick</a></p>
<p><a class="btn" href="?do=download">Update</a></p>
</body>
</html>

<?php
}

///////////////////
/// do = UPDATE ///
///////////////////
function immo_update($db) {
global $data;
read_db($db);
$id = isset($_POST['id']) ? $_POST['id'] : false;
$status = isset($_POST['status']) ? $_POST['status'] : "NONE";
$note = isset($_POST['note']) ? $_POST['note'] : "NONE";

$key = array_search($id, array_column($data, 'id'));
if (strlen($key) === 0) {
echo $id . " does not exist.<br />";
echo "<br />";
echo "<a href='.'>Back to overview</a>\n";
} else {
session_start(); // start Sessions
if ($status != "NONE") {
$data[$key]['status'] = $status;
save_return_page("Changed status of " . $id . " to \"". $status . "\".");
}
if ($note != "NONE") {
$data[$key]['note'] = $note;
save_return_page("Changed note of " . $id . " to \"". $note . "\".");
}
}
}

////////////////////////
/// HELPER FUNCTIONS ///
////////////////////////
// load database from file and decode it to array $data
function read_db($db) {
global $data; // declare $data a global variable to access it outside this function
if (! file_exists($db)) {
touch($db);
}
$file = file_get_contents($db, true);
$data = json_decode($file, true);
unset($file);
}

// Encode $data array and write database to file
function write_db($db, $data) {
// encode and write file
$encoded = json_encode($data, JSON_PRETTY_PRINT);
file_put_contents($db, $encoded, LOCK_EX);
}

// load URL and transform it to a XPath-searchable document
function xsite($url) {
libxml_use_internal_errors(true); // suppress errors
$dl = file_get_contents($url);
$site = new DOMDocument();
$site->loadHTML($dl);
$xpathvar = new Domxpath($site);
return $xpathvar;
}

// save database, put message to session, and load refering page which shows the message
function save_return_page($output) {
global $db;
global $data;
write_db($db, $data);
$_SESSION['message'] = "Update: " . $output;
header('Location: ' . $_SERVER['HTTP_REFERER']);
exit;
}
?>

Loading…
Cancel
Save