Working version

This commit is contained in:
Lino Silva
2024-10-12 20:44:30 +01:00
parent c499da44e9
commit 81b898a8f1
7 changed files with 1505 additions and 0 deletions
+2
View File
@@ -0,0 +1,2 @@
GHOSTFOLIO_SECURITY_TOKEN=
GHOSTFOLIO_HOST=
+25
View File
@@ -0,0 +1,25 @@
FROM ghcr.io/puppeteer/puppeteer:22
USER root
# Add user so we don't need --no-sandbox.
RUN mkdir -p /home/pptruser/Downloads /app \
&& chown -R pptruser:pptruser /home/pptruser \
&& chown -R pptruser:pptruser /app
# Run everything after as non-privileged user.
USER pptruser
# Install Puppeteer under /node_modules so it's available system-wide
COPY package.json /app/
COPY yarn.lock /app/
RUN cd /app/ && yarn
COPY .env /app/
COPY index.mjs /app/
ARG GHOSTFOLIO_SECURITY_TOKEN
ARG GHOSTFOLIO_HOST
ENV GHOSTFOLIO_SECURITY_TOKEN=$GHOSTFOLIO_SECURITY_TOKEN
ENV GHOSTFOLIO_HOST=$GHOSTFOLIO_HOST
ENTRYPOINT ["/usr/local/bin/node", "/app/index.mjs"]
+9
View File
@@ -0,0 +1,9 @@
services:
scraper:
image: bpi-stock-price-scraper
environment:
- GHOSTFOLIO_SECURITY_TOKEN=${GHOSTFOLIO_SECURITY_TOKEN} # here it is!
- GHOSTFOLIO_HOST=${GHOSTFOLIO_HOST} # here it is!
build:
context: .
dockerfile: Dockerfile
+8
View File
@@ -0,0 +1,8 @@
import globals from "globals";
import pluginJs from "@eslint/js";
export default [
{languageOptions: { globals: globals.browser }},
pluginJs.configs.recommended,
];
+100
View File
@@ -0,0 +1,100 @@
import puppeteer from "puppeteer";
import process from "node:process";
import axios from "axios";
import "dotenv/config";
const contas = {
bpi2040: {
url: "https://www.bancobpi.pt/particulares/poupar-investir/ppr/bpi-destino-ppr-2040",
ghostfolioName: "BPI%20Destino%20PPR%202040",
},
bpi2050: {
url: "https://www.bancobpi.pt/particulares/poupar-investir/ppr/bpi-destino-ppr-2050",
ghostfolioName: "BPI%20Destino%20PPR%202050",
},
};
async function parseLogRocketBlogHome(conta) {
// Launch the browser
const browser = await puppeteer.launch();
// Open a new tab
const page = await browser.newPage();
// Visit the page and wait until network connections are completed
await page.goto(conta.url, { waitUntil: "networkidle2" });
// Interact with the DOM to retrieve the titles
const [price, date] = await page.evaluate(() => {
const spanTags = document.getElementsByTagName("span");
const priceSearchText = "ÚLTIMA COTAÇÃO:";
const dateSearchText = "DATA COTAÇÃO:";
let priceElementFound;
let dateElementFound;
for (let i = 0; i < spanTags.length; i++) {
if (spanTags[i].textContent.trim() == priceSearchText) {
priceElementFound = spanTags[i];
console.log(`Found ${priceSearchText}.`);
if (priceElementFound && dateElementFound) break;
}
if (spanTags[i].textContent.trim() == dateSearchText) {
dateElementFound = spanTags[i];
console.log(`Found ${dateSearchText}.`);
if (priceElementFound && dateElementFound) break;
}
}
return [
priceElementFound.nextSibling.innerHTML,
dateElementFound.nextSibling.innerHTML,
];
});
// Don't forget to close the browser instance to clean up the memory
await browser.close();
const marketPrice = parseFloat(
price.replace("€", "").trim().replace(",", ".")
);
// Print the results
console.log(decodeURIComponent(conta.ghostfolioName));
console.log(`Current price: € ${marketPrice}`);
console.log(`Date: ${date}`);
const bearerTokenResponse = await axios.post(
`${process.env.GHOSTFOLIO_HOST}/api/v1/auth/anonymous`,
{
accessToken: process.env.GHOSTFOLIO_SECURITY_TOKEN,
}
);
const response = await axios
.post(
`${process.env.GHOSTFOLIO_HOST}/api/v1/admin/market-data/MANUAL/${conta.ghostfolioName}`,
{
marketData: [
{
date,
marketPrice,
},
],
},
{
headers: {
Authorization: `Bearer ${bearerTokenResponse.data.authToken}`,
},
}
)
.catch(console.error);
console.log(response.status);
}
await Promise.all([
parseLogRocketBlogHome(contas.bpi2040),
parseLogRocketBlogHome(contas.bpi2050),
]);
process.exit(0);
+18
View File
@@ -0,0 +1,18 @@
{
"name": "bpi-stock-price-scraper",
"version": "1.0.0",
"main": "index.js",
"repository": "ssh://git@10.0.2.28:222/lino-authelia/bpi-stock-price-scraper.git",
"author": "Lino Silva <me@lino.cooking>",
"license": "MIT",
"dependencies": {
"axios": "^1.7.7",
"dotenv": "^16.4.5",
"puppeteer": "^23.5.3"
},
"devDependencies": {
"@eslint/js": "^9.12.0",
"eslint": "^9.12.0",
"globals": "^15.11.0"
}
}
+1343
View File
File diff suppressed because it is too large Load Diff