экспорт в CSV по окончании выполнения - PullRequest
1 голос
/ 12 июля 2020

Исходный код, очищающий первую страницу данных, работает, но затем я создал al oop, который нажимает кнопку «загрузить еще», а затем очищает данные до тех пор, пока не исчезнет кнопка «загрузить еще». В конце моего прогона он ничего не экспортирует. Мой код для экспорта в CSV неверен? Где я ошибаюсь?

const puppeteer = require('puppeteer');
const jsonexport = require('jsonexport');

(async () => {
  const browser = await puppeteer.launch({ headless: false }); // default is true
  const page = await browser.newPage();
  await page.goto('https://www.bodybuilding.com/exercises/finder', {
    waitUntil: 'domcontentloaded',
  });

  //load more CSS to be targeted
  const LoadMoreButton =
    '#js-ex-content > #js-ex-category-body > .ExCategory-results > .ExLoadMore > .bb-flat-btn';

  do {
// clicking load more button and waiting 1sec
    await page.click(LoadMoreButton);
    await page.waitFor(1000);

    const loadMore = true;


    const rowsCounts = await page.$eval(
      '.ExCategory-results > .ExResult-row',
      (rows) => rows.length
    );

    //scraping the data
    const exerciseNames = [];
    for (let i = 2; i < rowsCounts + 1; i++) {
      const exerciseName = await page.$eval(
        `.ExCategory-results > .ExResult-row:nth-child(${i}) > .ExResult-cell > .ExHeading > a`,
        (el) => el.innerText
      );
      exerciseNames.push(exerciseName);
    }

    console.log({exerciseNames});
  } while (10000);

  const allData = [
    {
      exercise: exerciseNames,
    },
  ];
// exporting data to CSV
  const options = [exercise];
  //json export error part
  jsonexport(allData, options, function (err, csv) {
    if (err) return console.error(err);
    console.log(csv);
  });

  await browser.close();
})().catch((e) => {
  console.error(e);
});

Изменить: Это то, что у меня есть на данный момент для экспорта и записи в файл CSV. Я получаю 3 заголовка, но пишутся только упражнения и больше ничего. Console.log показывает упражнения, целевую группу мышц и оборудование, которое экспортируется. Я пытаюсь получить его там, где это 3 заголовка (имя, оборудование и целевая мышца), а затем каждая строка заполняется внутри него. Пример: приседания, штанга, ноги - они будут в одном ряду, но каждая в своей ячейке.

Текущий код экспорта:

 const allData = [
    {
      exercise: exerciseNames,
      muscleGroup: muscleTargets,
      equipment: equipmentTypes,
    },
  ];

  var ws = fs.createWriteStream('test1.csv');


  csv.write(allData, { headers: true, delimiter: ',' }).pipe(ws);

  //json export error part
  jsonexport(allData, function (err, csv) {
    if (err) return console.error(err);
    console.log(csv);
  });

введите описание изображения здесь

Редактировать 2 На данный момент это весь мой код. Он выводит предварительно заполненную информацию allData, но не более новых данных

 const puppeteer = require('puppeteer');
const jsonexport = require('jsonexport');
const fs = require('fs');

(async () => {
  const browser = await puppeteer.launch({ headless: false }); // default is true
  const page = await browser.newPage();
  await page.goto('https://www.bodybuilding.com/exercises/finder', {
    waitUntil: 'domcontentloaded',
  });

  const loadMore = true;

  const rowsCounts = await page.$$eval(
    '.ExCategory-results > .ExResult-row',
    (rows) => rows.length
  );
  let allData = [];
  for (let i = 2; i < rowsCounts + 1; i++) {
    const exerciseName = await page.$eval(
      `.ExCategory-results > .ExResult-row:nth-child(${i}) > .ExResult-cell > .ExHeading > a`,
      (el) => el.innerText
    );
    const muscleGroupName = await page.$eval(
      `.ExCategory-results > .ExResult-row:nth-child(${i}) > .ExResult-cell > .ExResult-muscleTargeted > a`,
      (el) => el.innerHTML
    );
    const equipmentName = await page.$eval(
      `.ExCategory-results > .ExResult-row:nth-child(${i}) > .ExResult-cell > .ExResult-equipmentType > a`,
      (el) => el.innerHTML
    );

    let obj = {
      exercise: exerciseName,
      muscleGroup: muscleGroupName,
      equipment: equipmentName,
    };
    allData.push(obj);
  }
  console.log(allData);

  async function fn() {
    const allData = [
      {
        exercise: 'Rickshaw Carry',
        muscleGroup: 'Forearms',
        equipment: 'Other',
      },
      {
        exercise: 'Single-Leg Press',
        muscleGroup: 'Quadriceps',
        equipment: 'Machine',
      },
      {
        exercise: 'Landmine twist',
        muscleGroup: 'Forearms',
        equipment: 'Other',
      },
      {
        exercise: 'Weighted pull-up',
        muscleGroup: 'Forearms',
        equipment: 'Other',
      },
    ];

    // json export error part
    jsonexport(allData, function (err, csv) {
      if (err) return console.error(err);
      console.log(csv);
      fs.writeFileSync('output.csv', csv);
    });
  }
  fn();

  await browser.close();
})().catch((e) => {
  console.error(e);
});

1 Ответ

1 голос
/ 12 июля 2020

Я вижу здесь две проблемы.

I.) Одна из них связана с объявлением options:

const options = [exercise]; // ❌

Вы пытаетесь получить доступ к exercise свойство объекта allData без соответствующей записи. Если вам действительно нужно извлечь его в новый массив, вы можете сделать это, перейдя внутрь первого элемента массива allData с индексом [0], а затем используя точечную нотацию для доступа к exercise property.

const options = [allData[0].exercise]; // ✅

Примечание: Я предлагаю оставить параметры просто allData[0].exercise (без оберточного массива), поскольку ваш объект allData уже является массивом, я не вижу выгода от увеличения глубины структуры.

II.) Вторая проблема связана с использованием пакета jsonexport npm. Я полагаю, вы оставили allData случайно в этой строке:

jsonexport(allData, options, function (err, csv) // ❌

Здесь вам нужен только options (поскольку согласно docs вы можете указать только один объект в качестве входных данных ):

jsonexport(options, function (err, csv) // ✅

Изменить

Основываясь на вашем обновленном ответе, ваша проблема может быть решена, если вы немного реструктурируете свой объект allData, чтобы jsonexport правильно распознал каждый столбец и строку.

const jsonexport = require('jsonexport')
const fs = require('fs')

async function fn() {
  const allData = [
    {
      exercise: 'Rickshaw Carry',
      muscleGroup: 'Forearms',
      equipment: 'Other'
    },
    {
      exercise: 'Single-Leg Press',
      muscleGroup: 'Quadriceps',
      equipment: 'Machine'
    },
    {
      exercise: 'Landmine twist',
      muscleGroup: 'Forearms',
      equipment: 'Other'
    },
    {
      exercise: 'Weighted pull-up',
      muscleGroup: 'Forearms',
      equipment: 'Other'
    }
  ]

  // json export error part
  jsonexport(allData, function (err, csv) {
    if (err) return console.error(err)
    console.log(csv)
    fs.writeFileSync('output.csv', csv)
  })
}
fn()

Чтобы получить такую ​​структуру, вы должны расширить allData на каждой итерации следующим образом:

let allData = []
for (let i = 2; i < rowsCounts; i++) {
  const exerciseName = await page.$eval(`...row:nth-child(${i})...`,
    el => el.textContent.trim())
  const muscleGroupName = await page.$eval(`...row:nth-child(${i})...`,
    el => el.textContent.trim())
  const equipmentName = await page.$eval(`...row:nth-child(${i})...`,
    el => el.textContent.trim())

  let obj = {
    exercise: exerciseName,
    muscleGroup: muscleGroupName,
    equipment: equipmentName
  }
  allData.push(obj)
}
console.log(allData)
...