Сводка приложения
Это приложение должно уведомлять пользователя, когда НОВЫЙ автомобиль был опубликован на Facebook MarketPlace. Пользователь получит электронное письмо с уведомлением о них и включит ссылку, по которой можно щелкнуть мышью, чтобы перейти на страницу с таблицей транспортных средств.
Прогресс
До сих пор я добился большого прогресса: 1007 *
- Я заполнил страницу с результатами, как показано здесь (таблица пуста, только заголовки и нижние колонтитулы)
![App](https://i.stack.imgur.com/B13kv.png)
Код PHP работает для отправки пользователю электронного письма при публикации нового автомобиля:
<?php
$subject = 'New Vehicles Found - MPB';
$headers = "From: bot@mpb.com\r\n";
$headers .= "Reply-To: bot@mpb.com\r\n";
$headers .= "CC: admin@gmail.com.com\r\n";
$headers .= "MIME-Version: 1.0\r\n";
$headers .= "Content-Type: text/html; charset=ISO-8859-1\r\n";
$message = '<html><body>';
$message .= '<h1>MarketPlace Bot Found Vehicles</h1>';
$message .= '<p><a href="http://john.123globalelectronicsllc.com/mpb/results.html">Click here to see new vehicles</a>';
$message .= '</body></html>';
$to = 'test@gmail.com,admin@gmail.com';
if (mail($to, $subject, $message, $headers)) {
echo 'Your message has been sent.';
} else {
echo 'There was a problem sending the email.';
}
?>
Сценарий NODE JS до этого момента будет использовать Puppeteer для очистки данных, необходимых со страницы результатов поиска. Следующий код не работает так, как мне нужно, по причине, указанной в следующем разделе.
// CRON JOB THIS FOR EVERY TEN MINUTES
const puppeteer = require('puppeteer');
/* InitScraper
*
* @desc: Get Vehicle Listings From FaceBook MarketPlace
* @param: string searchTerm The complete URL including search term
* @example: getItems('')
*/
const getItems = async searchTerm => {
if(searchTerm == ''){
/* Define Jeep Wrangler as default */
var searchTerm = "Jeep Wrangler";
}
/* Configure Puppeteer */
const browser = await puppeteer.launch({
headless: true,
defaultViewport: null
});
/* Create New Puppeteer Page */
const page = await browser.newPage();
/* Go to page */
await page.goto(`https://facebook.com/marketplace/tampa/search/?query=${encodeURI(searchTerm)}`);
/* Find Listing Container */
const itemList = await page.waitForSelector('div > div > span > div > a[tabindex="0"]')
.then(() => page.evaluate(() => {
const itemArray = [];
// Define Selector To Find Vehicle Listings
const itemNodeList = document.querySelectorAll('div > div > span > div > a[tabindex="0"]');
// Loop through listing, get TITLE, PRICE, URL, IMAGE
itemNodeList.forEach(item => {
/* Properties of A Listing */
const itemTitle = item.querySelector('div > div > span > div > a > div > div > div > span > div > span > div[class="l9j0dhe7 stjgntxs ni8dbmo4"').innerText;
const itemPrice = item.querySelector('div > div > span > div > a > div > div > div > div > span[class="oi732d6d ik7dh3pa d2edcug0 qv66sw1b c1et5uql a8c37x1j s89635nw ew0dbk1b a5q79mjw g1cxx5fr lrazzd5p oo9gr5id"').innerText;
const itemURL = `https://facebook.com/${item.getAttribute('href')}`;
const itemImg = item.querySelector('div > div > span > div > a > div > div > div > div > div > div > img').getAttribute('src');
/* Unique Item Number [ADDED] */
const itemNum = getItemNumber(itemURL);
/* Add Vehicle To Array */
itemArray.push({
itemNum,
itemTitle,
itemPrice,
itemURL,
itemImg
});
});
return itemArray;
}))
/* Selector Not Found - Log Error To Console */
.catch(() => console.log("Selector error."));
/*--------------------------*/
/* Create / Save Screenshot */
/*--------------------------*/
await page.screenshot({
path: 'screenshot.png'
});
return itemList;
}
/* InitScraper
*
* @desc: Initialize page, scrape MarketPlace and save the
* results to JSON file.
*/
const initScraper = async () => {
const items = await getItems('');
/* Sort by Price */
items.sort(function (a, b) {
return a.itemPrice - b.itemPrice
});
/* Save results to JSON file */
fs.writeFile("marketplacebot.json", JSON.stringify(items), function (err) {
if (err) throw err;
console.log("Saved!");
});
console.log(items);
}
/* Get Item Number From URL String
*
* @desc This function extracts the item number from a Facebook URL
* @param string url The FaceBook MarketPlace Listing URL
* @return string itemNum The item number
*/
const getItemNumber = function(url){
var itemNum = 0;
var re = /(\d{10,})/ig;
var itemNum = url.match(re)[0];
return itemNum;
}
// Away we go...
initScraper();
ПРОБЛЕМА
Если задание CRON выполняется каждые десять минут, как я отделил бы данные, собранные, когда скрипт Node выполняется? В первый раз пользователь получит все списки. Но после этого каждые десять минут мне как-то приходится показывать только новые.
Я записываю все списки в файл JSON, на рынке. json
Так или иначе, Мне нужно получить новые списки, загрузить старые JSON файлы и показать только те, которых нет на рынке. json, верно? Если так, то как в мире это может быть сделано? Я не являюсь автором Узла, кстати.
Спасибо за любую помощь.
С уважением,
Джон