How do I place a conditional within a . foreach() in Javascript?

Asked

Viewed 140 times

1

I’m making a Scrapping on a website that organizes items with a tag <a>, however I am getting several values with null.

How can I place a parole to avoid these values null on the return?

const result = await page.evaluate(() => {
    const medicines = []
    document.querySelectorAll('div > div > div > div > div > a')
            .forEach(
                medicine => if(medicine.getAttribute('title')!== null){
                    medicines.push(medicine.getAttribute('title'))
                    }
                )
    return medicines
  })
  • 2

    It has many forms, but why not use one for Is it really that much easier to do this? It’s not your fault, it’s that there are people teaching wrong around, but this code has not gained any doing so, on the contrary, there is only problem.

3 answers

1

Just for the record, you don’t necessarily need to forEach or reduce, because you can go through the elements found by querySelectorAll with a for..of:

const medicines = [];
for (const a of document.querySelectorAll('div > div > div > div > div > a')) {
    if (a.getAttribute('title') !== null) {
        medicines.push(a.getAttribute('title'));
    }
}
console.log(medicines); // ["title1", "title2", ""]
<div><div><div><div><div>
  <a title="title1"></a>
  <a href="semtitle.html"></a>
  <a title="title2"></a>
  <a href="#title-vazio" title=""></a>
</div></div></div></div></div>

Although in this case he’s also considering the latter <a>, that has the attribute title, but its value is an empty string. It is unclear whether to include it or not, but if it is not, you can switch to if (a.getAttribute('title')) (for empty strings are considered false, then if the title is empty, will not enter the if).

Another alternative to disregard the title empty is to put this condition on the selector itself:

const medicines = [];
// pegar somente tags "a" que tem title e o valor não é vazio
for (const a of document.querySelectorAll('div > div > div > div > div > a[title]:not([title=""])')) {
    medicines.push(a.getAttribute('title'));
}
console.log(medicines); // ["title1", "title2"]
<div><div><div><div><div>
  <a title="title1"></a>
  <a href="semtitle.html"></a>
  <a title="title2"></a>
  <a href="#title-vazio" title=""></a>
</div></div></div></div></div>


I also put a semicolon at the end of the lines. It may seem "freshness", but this avoids some bizarre situations which may occur if you don’t use them (see more about this here).

1


There is no way to use a condition if right after the operator =>.

When you declare a arrow function without opening the scope using keys, you need to declare an expression with a return. As if no return, it is not a valid code.

Solutions would be:

Open the scope -

document.querySelectorAll('div > div > div > div > div > a')
    .forEach(medicine => {
        if(medicine.getAttribute('title') !== null ) {
            medicines.push(medicine.getAttribute('title'))
        }
    })

Use an expression -

document.querySelectorAll('div > div > div > div > div > a')
    .forEach(medicine => medicine.getAttribute('title') !== null && medicines.push(medicine.getAttribute('title')))

This second example works because logical conditions and and or work with "short-circuit". If the first expression of the condition is false followed by a &&, the second expression will not be executed, because at this point it is already clear that the result of the condition will be false.

1

The best way to do this is by using a .reduce. That way you can check every iteration if the medicine exists and join it to the array or not.

A suggestion would be:

const result = await page.evaluate(() => {
  const anchors = [...document.querySelectorAll('div > div > div > div > div > a')];
  return anchors.reduce((arr, anchor) => {
    const medicine = anchor.getAttribute('title');
    return medicine ? arr.concat(medicine) : arr;
  }, [])
});

Another alternative would be to correct the syntax error you have in your code. You cannot have a if directly in this way after =>. But you could do it like this:

const result = await page.evaluate(() => {
  const medicines = []
  document.querySelectorAll('div > div > div > div > div > a')
    .forEach(
      medicine => medicine.getAttribute('title') && medicines.push(medicine.getAttribute('title'))
    )
  return medicines;
})

Browser other questions tagged

You are not signed in. Login or sign up in order to post.