Скрипт узла не закончится / не закончится
Я новичок в node.js и пытаюсь понять, почему мой сценарий не заканчивается. Все будет работать правильно, но это не закончится. Я думаю, что это как-то связано с обещаниями, которые я написал. При запуске из командной строки после того, как записан последний оператор done, сценарий не завершается (я должен вручную убить процесс). Я не могу понять, что я делаю неправильно с обещаниями и / или вызовом функции. Любая помощь будет принята с благодарностью.
var jquery = require('jquery');
const Nightmare = require('nightmare');
const Xvfb = require('xvfb')
const createCsvWriter = require('csv-writer').createArrayCsvWriter;
const fs = require('fs');
const jsdom = require("jsdom");
const addressFull = {"addr1": "123 Anywhere Ave", "city": "Hello", "region": "NY", "postal_code": "00000", "country": "US"};
const latLongFull = {"latitude": "xx.xxxxx", "longitude": "-xx.xxxxxxx"};
nightmare = Nightmare();
const startURL = "https://www.example.com";
function getInventory(sURL){
nightmare.goto(sURL)
.wait(2000)
.evaluate(function(){
totals = [];
items = {}
totalCars = $('.total-found .count').text()
carsOnPage = $('.hidden-xs .used-vehicle').size()
items['carTotal'] = totalCars
items['onPage'] = carsOnPage
var pageCalc = (totalCars / carsOnPage)
items['tPages'] = Math.ceil(pageCalc)
totals.push(items)
return totals
})
.then(result => {
var totalCars = '';
var totalPages = '';
for (item in result){
totalPages = result[item].tPages
totalCars = result[item].carTotal
}
counter = 0;
let links = [];
let returnLinks = '';
newURL = '';
for (i = 0; i < totalPages; i++){
if (i == 0){
newURL = sURL;
} else {
counter = i + 1;
newURL = sURL + "#action=im_ajax_call&perform=get_results&_post_id=5&page=" + counter + "&show_all_filters=false";
}
links.push(newURL);
}
return links;
})
.then(results => {
var arrayLinks = results;
arrayLinks.reduce(function(accumulator, url){
return accumulator.then(function(newResults){
return nightmare.goto(url)
.wait(5000)
.evaluate(() => {
const gigs = [];
$(".hidden-xs .used-vehicle").each(function() {
item = {};
item["year"] = $(this).attr("data-year");
item["make"] = $(this).attr("data-make");
item["model"] = $(this).attr("data-model");
item["body"] = $(this).attr("data-body");
item["color"] = $(this).attr("data-ext-color");
item["trim"] = $(this).attr("data-trim");
item["mileage"] = $(this).attr("data-mileage");
item["transmission"] = $(this).attr("data-transmission");
item["vin"] = $(this).find(".vehicle-overview").attr("id");
item["title"] = $(this).find(".vehicle-overview h2 a").text();
item["link"] = $(this).find(".vehicle-overview h2 a").attr("href");
item["price"] = $(this).find(".vehicle-content .price").text();
gigs.push(item);
});
return gigs;
})
.then(detail => {
for (gig in detail) {
try {
var carVin = detail[gig].vin;
var carTitle = detail[gig].title;
var carDescrip = detail[gig].year + " " + detail[gig].make + " " + detail[gig].model;
var carURL = detail[gig].link;
var carMake = detail[gig].make;
var carModel = detail[gig].model;
var carYear = detail[gig].year;
var carMileageFull = detail[gig].mileage;
var carMileage = carMileageFull.replace(',', '');
var carTransmission = detail[gig].transmission;
var carBody = detail[gig].body;
var bodyType = '';
/*
"CONVERTIBLE", "COUPE", "CROSSOVER", "HATCHBACK", "MINIVAN", "TRUCK", "SUV", "SEDAN", "VAN", "WAGON", "OTHER".
*/
switch (carBody){
case '2dr Car' :
bodyType = 'COUPE';
break;
case '4dr Car' :
bodyType = 'SEDAN';
break;
case 'Sport Utility' :
bodyType = 'SUV';
break;
}
var carPriceFull = detail[gig].price;
var carPriceFull = carPriceFull.replace('$', '');
var carPriceFull = carPriceFull.replace('*', '');
var carPriceFull = carPriceFull.replace(',', '');
var carPrice = carPriceFull.trim();
var dealerAddress = "{addr1: '"+ addressFull.addr1 +"', city: '"+ addressFull.city +"', region: '"+ addressFull.region +"', postal_code: '"+ addressFull.postal_code +"', country: '"+ addressFull.country +"'}";
var dealerLat = latLongFull.latitude;
var dealerLong = latLongFull.longitude;
var carColor = detail[gig].color;
arrSetup = [carVin, carTitle, carDescrip, carURL, carMake, carModel, carYear, carMileage, 'MI', '', '', 'AUTOMATIC', 'GASOLINE', bodyType, 'Other', carVin, 'OTHER', carPrice + " USD", dealerAddress, carColor, carPrice + " USD", 'AVAILABLE', 'USED', dealerLat, dealerLong];
newResults.push(arrSetup);
}
catch(error){
returnString += error;
}
}
return newResults;
})
.catch(error => {
throw new Error(error);
});
});
}, Promise.resolve([]))
.then(function(finalCall){
/*
We need to get the 3rd image on every vdp in the array. We will need to create a loop, go to the page, get the image and properly insert it into the proper array index
*/
finalCall.reduce(function(accumulator, resultArray){
return accumulator.then(function(finalResults){
var vdp = resultArray[3];
return nightmare.goto(vdp)
.wait(500)
.evaluate(() => {
var thirdIMG = $('.gallery-thumbs .owl-item:nth-of-type(3) img').attr('src');
return thirdIMG;
})
.then(imgResult => {
// 9
resultArray.splice(9, 1, imgResult);
console.log(resultArray);
finalResults.push(resultArray);
return finalResults;
})
.catch(error => {
throw new Error(error);
});
});
}, Promise.resolve([]))
.then(finalInsert => {
const csvWriter = createCsvWriter({
header: ["vehicle_id", "title", "description", "url", "make", "model", "year", "mileage.value", "mileage.unit", "image[0].url", "image[0].tag[0]", "transmission", "fuel_type", "body_style", "drivetrain", "vin", "condition", "price", "address", "exterior_color", "sale_price", "availability", "state_of_vehicle", "latitude", "longitude"],
path: 'client-name.csv'
});
var records = finalInsert;
console.log(records)
csvWriter.writeRecords(records)
nightmare.end() console.log('Done')
})
});
})
.catch(function(error){
return error;
})
}
getInventory(startURL);
1 ответ
Вы разместили подобный вопрос здесь, и я помню, что я указал вам несколько ссылок относительно обещания.
Пункт 1
Код, который вы скопировали, вставил и пытался исправить, недействителен. Например, эта строка ниже действительно недействительна.
nightmare.end() console.log('Done')
})
Либо, он не должен работать правильно. Или вы не передаете правильный код.
Пункт 2
Ваш код не имеет модульного кода. Вы должны написать отдельные функции для каждой задачи, а затем объединить их. Отвечая на ваш предыдущий вопрос, я поделился правильным кодом цепочки.
Вы должны определенно разделить код на несколько функций. Здесь я делюсь несколько модульной и фиксированной версией вашего кода. Читайте, пытайтесь понять и сделать все остальное.
Я исправил некоторые синтаксические ошибки, исправил код и добавил обещания.
const jquery = require("jquery");
const Nightmare = require("nightmare");
const Xvfb = require("xvfb");
const createCsvWriter = require("csv-writer").createArrayCsvWriter;
const fs = require("fs");
const jsdom = require("jsdom");
const addressFull = {
addr1: "123 Anywhere Ave",
city: "Hello",
region: "NY",
postal_code: "00000",
country: "US"
};
const latLongFull = { latitude: "xx.xxxxx", longitude: "-xx.xxxxxxx" };
const nightmare = Nightmare();
const startURL = "https://www.example.com";
const formatLinks = result => {
return new Promise((resolve, reject) => {
let totalCars = "";
let totalPages = "";
for (item in result) {
totalPages = result[item].tPages;
totalCars = result[item].carTotal;
}
counter = 0;
let links = [];
let returnLinks = "";
newURL = "";
for (i = 0; i < totalPages; i++) {
if (i == 0) {
newURL = sURL;
} else {
counter = i + 1;
newURL =
`${sURL}#action=im_ajax_call&perform=get_results&_post_id=5&page=${counter}&show_all_filters=false`;
}
links.push(newURL);
}
resolve(links);
});
};
const formatCarData = detail => {
return new Promise((resolve, reject) => {
for (gig in detail) {
try {
const carVin = detail[gig].vin;
const carTitle = detail[gig].title;
const carDescrip =
`${detail[gig].year} ${detail[gig].make} ${detail[gig].model}`;
const carURL = detail[gig].link;
const carMake = detail[gig].make;
const carModel = detail[gig].model;
const carYear = detail[gig].year;
const carMileageFull = detail[gig].mileage;
const carMileage = carMileageFull.replace(",", "");
const carTransmission = detail[gig].transmission;
const carBody = detail[gig].body;
let bodyType = "";
switch (carBody) {
case "2dr Car":
bodyType = "COUPE";
break;
case "4dr Car":
bodyType = "SEDAN";
break;
case "Sport Utility":
bodyType = "SUV";
break;
}
var carPriceFull = detail[gig].price;
var carPriceFull = carPriceFull.replace("$", "");
var carPriceFull = carPriceFull.replace("*", "");
var carPriceFull = carPriceFull.replace(",", "");
const carPrice = carPriceFull.trim();
const dealerAddress =
`{addr1: '${addressFull.addr1}', city: '${addressFull.city}', region: '${addressFull.region}', postal_code: '${addressFull.postal_code}', country: '${addressFull.country}'}`;
const dealerLat = latLongFull.latitude;
const dealerLong = latLongFull.longitude;
const carColor = detail[gig].color;
arrSetup = [
carVin,
carTitle,
carDescrip,
carURL,
carMake,
carModel,
carYear,
carMileage,
"MI",
"",
"",
"AUTOMATIC",
"GASOLINE",
bodyType,
"Other",
carVin,
"OTHER",
`${carPrice} USD`,
dealerAddress,
carColor,
`${carPrice} USD`,
"AVAILABLE",
"USED",
dealerLat,
dealerLong
];
newResults.push(arrSetup);
} catch (error) {
returnString += error;
}
}
resolve(newResults);
});
};
function getInventory(sURL) {
nightmare
.goto(sURL)
.wait(2000)
.evaluate(() => {
totals = [];
items = {};
totalCars = $(".total-found .count").text();
carsOnPage = $(".hidden-xs .used-vehicle").size();
items["carTotal"] = totalCars;
items["onPage"] = carsOnPage;
const pageCalc = totalCars / carsOnPage;
items["tPages"] = Math.ceil(pageCalc);
totals.push(items);
return totals;
})
.then(formatLinks)
.then(results => {
const arrayLinks = results;
arrayLinks
.reduce((accumulator, url) => accumulator.then(newResults => nightmare
.goto(url)
.wait(5000)
.evaluate(() => {
const gigs = [];
$(".hidden-xs .used-vehicle").each(function() {
item = {};
item["year"] = $(this).attr("data-year");
item["make"] = $(this).attr("data-make");
item["model"] = $(this).attr("data-model");
item["body"] = $(this).attr("data-body");
item["color"] = $(this).attr("data-ext-color");
item["trim"] = $(this).attr("data-trim");
item["mileage"] = $(this).attr("data-mileage");
item["transmission"] = $(this).attr("data-transmission");
item["vin"] = $(this)
.find(".vehicle-overview")
.attr("id");
item["title"] = $(this)
.find(".vehicle-overview h2 a")
.text();
item["link"] = $(this)
.find(".vehicle-overview h2 a")
.attr("href");
item["price"] = $(this)
.find(".vehicle-content .price")
.text();
gigs.push(item);
});
return gigs;
})
.then(formatCarData)
.catch(error => {
throw new Error(error);
})), Promise.resolve([]))
.then(finalCall => {
finalCall
.reduce((accumulator, resultArray) => accumulator.then(finalResults => {
const vdp = resultArray[3];
return nightmare
.goto(vdp)
.wait(500)
.evaluate(() => {
const thirdIMG = $(
".gallery-thumbs .owl-item:nth-of-type(3) img"
).attr("src");
return thirdIMG;
})
.then(imgResult => {
// 9
resultArray.splice(9, 1, imgResult);
console.log(resultArray);
finalResults.push(resultArray);
return finalResults;
})
.catch(error => {
throw new Error(error);
});
}), Promise.resolve([]))
.then(finalInsert => {
const csvWriter = createCsvWriter({
header: [
"vehicle_id",
"title",
"description",
"url",
"make",
"model",
"year",
"mileage.value",
"mileage.unit",
"image[0].url",
"image[0].tag[0]",
"transmission",
"fuel_type",
"body_style",
"drivetrain",
"vin",
"condition",
"price",
"address",
"exterior_color",
"sale_price",
"availability",
"state_of_vehicle",
"latitude",
"longitude"
],
path: "client-name.csv"
});
const records = finalInsert;
console.log(records);
csvWriter.writeRecords(records);
nightmare.end();
console.log("Done");
});
});
})
.catch(error => error);
}
getInventory(startURL);
Пункт 3
У вас запущен экземпляр, который рекурсивно посещает несколько сайтов. Вы должны обязательно использовать Nightmare({show: true})
в вашем коде. Таким образом, вы можете знать, что происходит. Может быть, процесс не зависает, скорее это просто просмотр тысячи страниц.
Примечание: извините за мой высокомерный тон, но вы написали и приняли свой собственный ответ как лучший ответ, который работал только для того времени. И вот вы снова задаете тот же вопрос. Вам определенно следует стараться правильно читать ответы, потому что люди тратят время на их написание. Не просто скопируйте код вставки без понимания, вы узнаете намного больше таким образом.