Puppeter delete node inside element - javascript

I want to scrape a page with some news inside.
Here it's an HTML simplified version of what I have :
<info id="random_number" class="news">
<div class="author">
Name of author
</div>
<div class="news-body">
<blockquote>...<blockquote>
Here it's the news text
</div>
</info>
<info id="random_number" class="news">
<div class="author">
Name of author
</div>
<div class="news-body">
Here it's the news text
</div>
</info>
I want to get the author and text body of each news, without the blockquote part.
So I wrote this code :
let newsPage = await newsPage.$$("info.news");
for (var news of newsPage){ // Loop through each element
let author = await news.$eval('.author', s => s.textContent.trim());
let textBody = await news.$eval('.news-body', s => s.textContent.trim());
console.log('Author :'+ author);
console.log('TextBody :'+ textBody);
}
It works well, but I don't know how to remove the blockquote part of the "news-body" part, before getting the text, how can I do this ?
EDIT : Sometimes there is blockquote exist, sometime not.

You can use optional chaining with ChildNode.remove(). Also you may consider innerText more readable.
let textMessage = await comment.$eval('.news-body', (element) => {
element.querySelector('blockquote')?.remove();
return element.innerText.trim();
});

Related

Click to change image is changing the wrong one

So I'm working on a website that has a lot of movies, and people can choose what movies are they favorite, and for that, I have a star image that can be clicked and when clicked that image will change to another one
Like this:
To this:
The problem I have is that the only image that change is the first one, When I click, for example on the star next to the Ratatouille movie, it will change the first star
This is the HTML:
const getMovieHtml = (movie) => `<div class="movie">
<h2>${movie.title}</h2>
<img onclick="bottonclick()" id="estrelinhas" src="./icons/empty-star.png" alt="estrela vazia" width=40>
<div class="content">
<img src="${movie.posterUrl}" alt="${movie.title}" />
<div class="text">
<p>${movie.summary}</p>
<div class="year">${movie.year}</div>
<div><strong>Directors:</strong> ${movie.director}</div>
<div><strong>Actors:</strong> ${movie.actors}</div>
</div>
</div>
</div>`;
And this is the arrow function I used to make the star change:
const bottonclick = () => {
if (document.getElementById("estrelinhas").src.includes("empty-star.png")) {
document.getElementById("estrelinhas").src = "./icons/filled-star.png";
} else {
document.getElementById("estrelinhas").src = "./icons/empty-star.png";
}
};
ID attributes of HTML elements should be unique. If you don't have unique ID's the code doesn't know which star to update. Read more about IDs here: https://www.w3schools.com/html/html_id.asp
To fix this, a solution would be to use a unique identifier for each image, so that when you click "favourite" it knows which star to reference.
Assuming for example that the movie.posterURL is unique you can use that as the ID, however the data from wherever you are getting the movie from might already have a unique identifier that you could pass to the id attribute of the image instead
Your code could look something like this:
const getMovieHtml = (movie) => `<div class="movie">
<h2>${movie.title}</h2>
<img onclick="bottonclick(e)" id="${movie.posterUrl}" src="./icons/empty-star.png" alt="estrela vazia" width=40>
<div class="content">
<img src="${movie.posterUrl}" alt="${movie.title}" />
<div class="text">
<p>${movie.summary}</p>
<div class="year">${movie.year}</div>
<div><strong>Directors:</strong> ${movie.director}</div>
<div><strong>Actors:</strong> ${movie.actors}</div>
</div>
</div>
</div>`;
const buttonClick = (e) => {
const star = document.getElementById(e.target.id);
if (star.src.includes("empty-star.png")) {
star.src = "./icons/filled-star.png";
} else {
star.src = "./icons/empty-star.png";
}
}
beacuse you getElementById, so you not take all containers,
but you get 1, first,
change getElementById for querySelectorAll and give there some id,
to localizate in DOM ,
buttonClick(e)
and in
function buttonClick(e) {
e.target.value/id/or something
}

Excluding inner tags from string using Regex

I have the following text:
If there would be more <div>matches<div>in</div> string</div>, you will merge them to one
How do I make a JS regex that will produce the following text?
If there would be more <div>matches in string</div>, you will merge them to one
As you can see, the additional <div> tag has been removed.
I would use a DOMParser to parseFromString into the more fluent HTMLDocument interface to solve this problem. You are not going to solve it well with regex.
const htmlDocument = new DOMParser().parseFromString("this <div>has <div>nested</div> divs</div>");
htmlDocument.body.childNodes; // NodeList(2): [ #text, div ]
From there, the algorithm depends on exactly what you want to do. Solving the problem exactly as you described to us isn't too tricky: recursively walk the DOM tree; remember whether you've seen a tag yet; if so, exclude the node and merge its children into the parent's children.
In code:
const simpleExampleHtml = `<div>Hello, this is <p>a paragraph</p> and <div>some <div><div><div>very deeply</div></div> nested</div> divs</div> that should be eliminated</div>`
// Parse into an HTML document
const doc = new DOMParser().parseFromString(exampleHtml, "text/html").body;
// Process a node, removing any tags that have already been seen
const processNode = (node, seenTags = []) => {
// If this is a text node, return it
if (node.nodeName === "#text") {
return node.cloneNode()
}
// If this node has been seen, return its children
if (seenTags.includes(node.tagName)) {
// flatMap flattens, in case the same node is repeatedly nested
// note that this is a newer JS feature and lacks IE11 support: https://caniuse.com/?search=flatMap
return Array.from(node.childNodes).flatMap(child => processNode(child, seenTags))
}
// If this node has not been seen, process its children and return it
const newChildren = Array.from(node.childNodes).flatMap(child => processNode(child, [...seenTags, node.tagName]))
// Clone the node so we don't mutate the original
const newNode = node.cloneNode()
// We can't directly assign to node.childNodes - append every child instead
newChildren.forEach(child => newNode.appendChild(child))
return newNode
}
// resultBody is an HTML <body> Node with the desired result as its childNodes
const resultBody = processNode(doc);
const resultText = resultBody.innerHTML
// <div>Hello, this is <p>a paragraph</p> and some very deeply nested divs that should be eliminated</div>
But make sure you know EXACTLY what you want to do!
There's lots of potential complications you could face with data that's more complex than your example. Here are some examples where the simple approach may not give you the desired result.
<!-- nodes where nested identical children are meaningful -->
<ul>
<li>Nested list below</li>
<li>
<ul>
<li>Nested list item</li>
</ul>
</li>
</ul>
<!-- nested nodes with classes or IDs -->
<span>A span with <span class="some-class">nested spans <span id="DeeplyNested" class="another-class>with classes and IDs</span></span></span>
<!-- places where divs are essential to the layout -->
<div class="form-container">
<form>
<div class="form-row">
<label for="username">Username</label>
<input type="text" name="username" />
</div>
<div class="form-row"
<label for="password">Password</label>
<input type="text" name="password" />
</div>
</form>
</div>
Simple approach without using Regex by using p element of html and get its first div content as innerText(exclude any html tags) and affect it to p, finally get content but this time with innerHTML:
let text = 'If there would be more <div>mathces <div>in</div> string</div>, you will merge them to one';
const p = document.createElement('p');
p.innerHTML = text;
p.querySelector('div').innerText = p.querySelector('div').innerText;
console.log(p.innerHTML);

How to render a large amount of html after hitting search button?

I am building a recipe search app but I am not sure how to render the big chunk of html representing the 30 recipes I want to have displayed. These recipe card obviously have to change based on what kind of meal I search for. How do I Implement the html into my Js so I can make it change based on the meal type?
I tried to do it with insertAdjecentHTML but since it doesn't replaces the old page with the recipe on but rather ads on to it. It didn't worked:
Nevertheless here is the code:
// recipe card markup
const renderRecipe = () => {
const markup = `
<div class="recipe-results__card">
<div class="recipe-results--img-container">
<img
src="${data.data.hits.recipe.image}"
alt="${data.data.hits.recipe.label}"
class="recipe-results__img"
/>
</div>
<p class="recipe-results__categories">
${limitCategories}
</p>
<h2 class="recipe-results__name">
${data.data.hits.recipe.label}
</h2>
</div>
`;
DOM.recipeGrid.insertAdjacentHTML("beforeend", markup);
};
// fn to display the markup for every search res
export const renderResults = recipes => {
recipes.forEach(renderRecipe);
};
concatenate (push to an array) the HTML so you have ONE update
You can use innerHTML instead of insertAdjacent to replace the content
let html = [];
data.data.hits.forEach(recipe => {
html.push(`
<div class="recipe-results__card">
<div class="recipe-results--img-container">
<img
src="${recipe.image}"
alt="${recipe.label}"
class="recipe-results__img"
/>
</div>
<p class="recipe-results__categories">
${limitCategories}
</p>
<h2 class="recipe-results__name">
${recipe.label}
</h2>
</div>
`) });
document.getElementById("recipeGrid").innerHTML = html.join("");

Selecting a childnode by inner text from a NodeList

First part [solved]
Given this HTML
<div id="search_filters">
<section class="facet clearfix"><p>something</p><ul>...</ul></section>
<section class="facet clearfix"><p>something1</p><ul>...</ul></section>
<section class="facet clearfix"><p>something2</p><ul>...</ul></section>
<section class="facet clearfix"><p>something3</p><ul>...</ul></section>
<section class="facet clearfix"><p>something4</p><ul>...</ul></section>
</div>
I can select all the section with
const select = document.querySelectorAll('section[class^="facet clearfix"]');
The result is a nodelist with 5 children.
What I'm trying to accomplish is to select only the section containing the "something3" string.
This is my first attempt:
`const xpathResult = document.evaluate( //section[p[contains(.,'something3')]],
select, null, XPathResult.ANY_TYPE, null );
How can I filter the selection to select only the node I need?
Second part:
Sorry for keeping update the question but it seems this is a problem out of my actual skill..
Now that i get the Node i need to work in what i've to do it's to set a custom order of the li in the sections:
<ul id="" class="collapse">
<li>
<label>
<span>
<input>
<span>
<a> TEXT
</a>
</span>
</input>
</span>
</label>
</li>
<li>..</li>
Assuming there are n with n different texts and i've a custom orders to follow i think the best way to go it would be look at the innertex and matching with an array where i set the correct order.
var sorOrder = ['text2','text1','text4','text3']
I think this approach should lead you to the solution.
Giving your HTML
<div id="search_filters">
<section class="facet clearfix"><p>something</p><ul>...</ul></section>
<section class="facet clearfix"><p>something1</p><ul>...</ul></section>
<section class="facet clearfix"><p>something2</p><ul>...</ul></section>
<section class="facet clearfix"><p>something3</p><ul>...</ul></section>
<section class="facet clearfix"><p>something4</p><ul>...</ul></section>
</div>
I would write this js
const needle = "something3";
const selection = document.querySelectorAll('section.facet.clearfix');
let i = -1;
console.info("SELECTION", selection);
let targetIndex;
while(++i < selection.length){
if(selection[i].innerHTML.indexOf(needle) > -1){
targetIndex = i;
}
}
console.info("targetIndex", targetIndex);
console.info("TARGET", selection[targetIndex]);
Then you can play and swap elements around without removing them from the DOM.
PS. Since you know the CSS classes for the elements you don't need to use the ^* (start with) selector. I also improved that.
PART 2: ordering children li based on content
const ul = selection[targetIndex].querySelector("ul"); // Find the <ul>
const lis = ul.querySelectorAll("li"); // Find all the <li>
const sortOrder = ['text2', 'text1', 'text4', 'text3'];
i = -1; // We already declared this above
while(++i < sortOrder.length){
const li = [...lis].find((li) => li.innerHTML.indexOf(sortOrder[i]) > -1);
!!li && ul.appendChild(li);
}
This will move the elements you want (only the one listed in sortOrder) in the order you need, based on the content and the position in sortOrder.
Codepen Here
In order to use a higher order function like filter on your nodelist, you have to change it to an array. You can do this by destructering:
var select = document.querySelectorAll('section[class^="facet clearfix"]');
const filtered = [...select].filter(section => section.children[0].innerText == "something3")
This answer explains the magic behind it better.
You can get that list filtered as:
DOM Elements:
Array.from(document.querySelectorAll('section[class^="facet clearfix"]')).filter(_ => _.querySelector('p').innerText === "something3")
HTML Strings:
Array.from(document.querySelectorAll('section[class^="facet clearfix"]')).filter(_ => _.querySelector('p').innerText === "something3").map(_ => _.outerHTML)
:)

Unable to grab an image with cheerio/node.js

My problem is pretty straightforward. I am trying to console log the URL of an image from the amazon link bellow. Either from a more precise selection
So I've spent the majority of the time attempting t select the id/class of the link but seem to only get the as close as #imgTagWrapperId which returns a lot of redundant information. In theory I should be able to grab the links with regex narrowing things down, but for the life of me I can only seem to replace the text i return and not simply grab it. Alternatively I have as stated attempted to grab the img src itself, only to return a nonsensical string of code. When I view page source the same ball of text appears there but not when I inspect elements directly.
const request = require('request');
const cheerio = require('cheerio');
request(`http://amazon.com/dp/B079H6RLKQ`, (error,response,html) =>{
if (!error && response.statusCode ==200) {
const $ = cheerio.load(html);
const productTitle = $("#productTitle").text().replace(/\s\s+/g, '');
const prodImg = $(`#imgTagWrapperId`).html();
console.log(productTitle);
console.log(prodImg);
} else {
console.log(error);
}
})
This current code returns the product title faithfully but returns this for the prodImg output:
<img alt="Samsung Galaxy S9 G960U 64GB Unlocked 4G LTE Phone w/ 12MP Camera - Midnight Black" src="
data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAoHBwgHBgoICAgLCgoLDhgQDg0NDh0VFhEYIx8lJCIfIiEmKzcvJik0KSEiMEExNDk7Pj4+JS5ESUM8SDc9Pjv/2wBDAQoLCw4NDhwQEBw7KCIoOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozv/wAARCAEsARYDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL
...(this nonsense goes on for a mile) ....
" data-old-hires="https://images-na.ssl-images-amazon.com/images/I/81%2Bh9mpyQmL._SL1500_.jpg" class="a-dynamic-image a-stretch-horizontal" id="landingImage" data-a-dynamic-image="{"https://images-na.ssl-images-amazon.com/images/I/81%2Bh9mpyQmL._SX522_.jpg":[564,522],"https://images-na.ssl-images-amazon.com/images/I/81%2Bh9mpyQmL._SX342_.jpg":[369,342],"https://images-na.ssl-images-amazon.com/images/I/81%2Bh9mpyQmL._SX679_.jpg":[733,679],"https://images-na.ssl-images-amazon.com/images/I/81%2Bh9mpyQmL._SX425_.jpg":[459,425],"https://images-na.ssl-images-amazon.com/images/I/81%2Bh9mpyQmL._SX466_.jpg":[503,466],"https://images-na.ssl-images-amazon.com/images/I/81%2Bh9mpyQmL._SX569_.jpg":[615,569],"https://images-na.ssl-images-amazon.com/images/I/81%2Bh9mpyQmL._SX385_.jpg":[416,385]}" style="max-width:679px;max-height:733px;">
</div>
Thank you in advance for any help and guidance with this. I Have exhausted all other usual sources and am ready to be called an idiot.
EDIT:
Someone wanted the html for before and after selection, Ill oblige but it might be better to just view the page source in the link and ctrl+ f. Wall of text bellow.
<div class="variationUnavailable unavailableExp">
<div class="inner">
<div class="a-box a-alert a-alert-error" aria-live="assertive" role="alert"><div class="a-box-inner a-alert-container"><h4 class="a-alert-heading">Image Unavailable</h4><i class="a-icon a-icon-alert"></i><div class="a-alert-content">
<span class="a-text-bold">
Image not available for<br/>Color:
<span class="unvailableVariation"></span>
</span>
</div></div></div>
</div>
</div>
<!-- Append onload function to stretch image on load to avoid flicker when transitioning from low res image from Mason to large image variant in desktop -->
<!-- any change in onload function requires a corresponding change in Mason to allow it pass in /mason/amazon-family/gp/product/features/embed-features.mi -->
<!-- and /mason/amazon-family/gp/product/features/embed-landing-image.mi -->
<ul class="a-unordered-list a-nostyle a-horizontal list maintain-height">
<span id="imageBlockEDPOverlay"></span>
<li class="image item itemNo0 selected maintain-height"><span class="a-list-item">
<span class="a-declarative" data-action="main-image-click" data-main-image-click="{}">
<div id="imgTagWrapperId" class="imgTagWrapper">
<img alt="Samsung Galaxy S9 G960U 64GB Unlocked 4G LTE Phone w/ 12MP Camera - Midnight Black" src="
data:image/jpeg;base64,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
" data-old-hires="https://images-na.ssl-images-amazon.com/images/I/81%2Bh9mpyQmL._SL1500_.jpg" class="a-dynamic-image a-stretch-horizontal" id="landingImage" data-a-dynamic-image="{"https://images-na.ssl-images-amazon.com/images/I/81%2Bh9mpyQmL._SX522_.jpg":[564,522],"https://images-na.ssl-images-amazon.com/images/I/81%2Bh9mpyQmL._SX342_.jpg":[369,342],"https://images-na.ssl-images-amazon.com/images/I/81%2Bh9mpyQmL._SX679_.jpg":[733,679],"https://images-na.ssl-images-amazon.com/images/I/81%2Bh9mpyQmL._SX425_.jpg":[459,425],"https://images-na.ssl-images-amazon.com/images/I/81%2Bh9mpyQmL._SX466_.jpg":[503,466],"https://images-na.ssl-images-amazon.com/images/I/81%2Bh9mpyQmL._SX569_.jpg":[615,569],"https://images-na.ssl-images-amazon.com/images/I/81%2Bh9mpyQmL._SX385_.jpg":[416,385]}" style="max-width:679px;max-height:733px;">
</div>
</span>
</span></li>
<li class="mainImageTemplate template"><span class="a-list-item">
<span class="a-declarative" data-action="main-image-click" data-main-image-click="{}">
<div class="imgTagWrapper">
<span class="placeHolder"></span>
</div>
</span>
</span></li>
Thanks to Rishi Raj for giving a quickfix solution. $('#landingImage').attr('data-old-hires'). I was also adding a unnecessary .html() to the const which had gotten in the way. Thanks again everyone!
Couldn't you simply target the image directly and get the url with .attr('src')?
const request = require('request');
const cheerio = require('cheerio');
request('http://amazon.com/dp/B079H6RLKQ', (error,response,html) => {
if (!error && response.statusCode === 200) {
const $ = cheerio.load(html);
const productTitle = $('#productTitle').text().replace(/\s\s+/g, '');
const prodImg = $('#landingImage').attr('data-old-hires');
console.log(productTitle);
console.log(prodImg);
} else {
console.log(error);
}
});

Categories