From ff702d74aa9ad20f14fd90a58466c4dc7a76039e Mon Sep 17 00:00:00 2001 From: GabiZar Date: Thu, 5 Mar 2026 21:58:07 +0100 Subject: [PATCH] Improve images scrapping from bing and show images on the client --- main.js | 30 +++++++++++++++++++++++++++--- public/index.html | 11 +++++++++-- public/script.js | 15 ++++++++++----- public/style.css | 27 +++++++++++++++++++++++++++ 4 files changed, 73 insertions(+), 10 deletions(-) diff --git a/main.js b/main.js index 8fc39ce..adbf07a 100644 --- a/main.js +++ b/main.js @@ -12,21 +12,45 @@ app.listen(PORT, () => { app.get("/api/getImagesURL", async (req, res) => { try { - const { q, offset = 0, count = 100 } = req.query; + let { q, offset = 1, count = 1000, smart = true } = req.query; + offset = Number(offset); + count = Number(count); + smart = smart === "true"; if (!q) { return res.status(400).send("Missing 'q' parameter"); } let imagesUrls = []; + let noNewCount = 0; do { - const url = `https://www.bing.com/images/async?q=${encodeURIComponent(q)}&offset=${offset}&count=30`; + const url = `https://www.bing.com/images/async?q=${encodeURIComponent(q)}&first=${String(offset)}`; const response = await fetch(url); const html = await response.text(); const urls = extractImageUrls(html); + offset += urls.length; + let newImageCount = 0; for (const url of urls) { - imagesUrls.push(url); + if (!imagesUrls.includes(url)) { + if (smart == true) { + try { + const response = await fetch(url, { method: "HEAD" }); + const contentType = response.headers.get("content-type"); + if (contentType && contentType.startsWith("image/")) { + imagesUrls.push(url); + newImageCount += 1; + } + } catch {} + } else { + imagesUrls.push(url); + newImageCount += 1; + } + } + } + noNewCount = newImageCount == 0 ? noNewCount + 1 : 0; + if (noNewCount > 32) { + break; } } while (imagesUrls.length < count); diff --git a/public/index.html b/public/index.html index 6f2ad3a..171ad14 100644 --- a/public/index.html +++ b/public/index.html @@ -1,7 +1,7 @@ - Ma Web App + Images Scrapper JS @@ -11,7 +11,7 @@

Images Scrapper JS

-
+
@@ -19,10 +19,17 @@
+
+ + diff --git a/public/script.js b/public/script.js index c0b4d7d..7bfb3d6 100644 --- a/public/script.js +++ b/public/script.js @@ -1,7 +1,8 @@ const starsNumber = 1000; const searchInput = document.getElementById("search-input"); const searchForm = document.getElementById("search-form"); - +const imagesDiv = document.getElementById("images-div"); +const imageTemplate = document.getElementById("image-template"); let imagesUrls = []; starsCanvas(starsNumber); @@ -81,16 +82,20 @@ function starsCanvas(number) { animate(); } -async function getImagesURL(query, offset = 0, count = 100) { - const url = `/api/getImagesURL?q=${encodeURIComponent(query)}&offset=${offset}&count=${count}`; +async function getImagesURL(query, offset, count, smart) { + const url = `/api/getImagesURL?q=${encodeURIComponent(query)}&offset=${offset}&count=${count}&smart=${smart}`; const response = await fetch(url); const data = await response.json(); + for (const url of data) { imagesUrls.push(url); + const imageTemplateCopy = imageTemplate.content.cloneNode(true); + imageTemplateCopy.getElementById("image").src = url; + imagesDiv.append(imageTemplateCopy); } - console.log(imagesUrls); } async function search() { - await getImagesURL(searchInput.value); + imagesDiv.replaceChildren(); + await getImagesURL(searchInput.value, 1, 1000, true); } diff --git a/public/style.css b/public/style.css index 9bd61e5..f9f1254 100644 --- a/public/style.css +++ b/public/style.css @@ -98,3 +98,30 @@ body { position: fixed; z-index: -1; } + +.images-div { + display: grid; + grid-template-columns: repeat(auto-fill, 150px); + gap: 20px; + justify-content: center; + margin-top: 50px; +} + +.image-box { + width: 150px; + height: 150px; + border-radius: 16px; + overflow: hidden; + transition: transform 0.2s; +} + +.image-box:hover { + transform: scale(3); + border-radius: 8px; +} + +.image-box img { + width: 100%; + height: 100%; + object-fit: cover; +}