Обновить, когда элемент изменяется на странице - PullRequest
0 голосов
/ 18 октября 2018

Я пытаюсь удалить элемент на веб-сайте и отобразить его на локальном хосте с помощью Puppeteer (1).Но когда этот элемент изменяется, я хотел бы обновить данные, не открывая новый браузер / страницу с помощью Puppeteer, и только при изменении элемента (2).

Для моего примера я использую www.timeanddate.com и элементвремя (часы и минуты).На данный момент работает только первая часть.У меня нет решения для второго.

Пожалуйста, найдите ниже мой код.

app.js

var app = require('express')();
var server = require('http').createServer(app);
var io = require('socket.io').listen(server);
var puppeteer = require('puppeteer');

app.get('/', function(req, res) { 
    res.render('main.ejs');
});

server.listen(8080);

let scrape = async () => {
    var browser = await puppeteer.launch({headless: true});
    var page = await browser.newPage();
    await page.goto('https://www.timeanddate.com/worldclock/personal.html');
    await page.waitFor(300);
    //await page.click('#mpo > div > div > div > div.modal-body > div.form-submit-row > button.submit.round.modal-privacy__btn');

    var result = await page.evaluate(() => {
        return document.getElementsByClassName('c-city__hrMin')[0].innerText;
    });

    return result;
};

io.sockets.on('connection', function (socket) {
    scrape().then((value) => { // it tooks time, a few seconds while page is loading.
        console.log(value);
        socket.emit('refresh', value);
    });
});

main.ejs

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title>What time is it?</title>
        <style>
            a {text-decoration: none; color: black;}
        </style>
    </head>

    <body>
        <h1>Welcome !</h1>

        <div id="time">loading</div>

        <script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
        <script src="/socket.io/socket.io.js"></script>
        <script>
            var socket = io.connect('http://localhost:8080');

            socket.on('refresh', function (value) {
                $('#time').html(value);
            });         
        </script>
    </body>
</html>

Я пробую Fiverr, но ужасный опыт.Я надеюсь, что здесь будет лучше:)

Спасибо за помощь.

1 Ответ

0 голосов
/ 18 октября 2018

Вы хотите создать событие при изменении данных.Есть несколько способов сделать это, например,

  • Попробуйте получить новые данные с интервалом
  • Ищите изменения и отправляйте их из браузера

Обновление кода Читаемость

Я буду обсуждать оба из них.Но сначала давайте разделим код для лучшего удобства использования.Это совершенно необязательно, но вы должны это сделать.

/**
 * Scraper
 * Use this instead of scrape variable
 */
let browser, page;
const scraper = {
  async open() {
    browser = await puppeteer.launch({ headless: true });
    page = await browser.newPage();
    const url = "https://www.timeanddate.com/worldclock/personal.html";
    await page.goto(url);
    await page.waitFor(300);
  },
  async getTime() {
    return page.evaluate(() => {
      return document.querySelector(".c-city__digitalClock").innerText; // time with seconds 5:43:22am
    });
  }
};

Мы можем добавить другие методы к этому объекту позже, если потребуется.Это не лучший формат, но это поможет нам лучше понять код.

Метод 1. Установите интервал

Давайте изменим соединение, нам просто нужно открыть страницу один рази опрашивать новые данные через некоторый интервал.

/**
 * Socket Connection Monitor
 */
io.sockets.on("connection", async function(socket) {
  // open the page once
  await scraper.open();

  // start the interval loop
  setInterval(async () => {

    // get the time every second
    const time = await scraper.getTime();

    // emit the updated time
    socket.emit("refresh", time);
  }, 1000); // how many millisecond we want
});

Метод 2. Добавление событий в сам браузер.

Это расширенный и намного более сложный, но очень точный.

Вы можете добавить это внутри scraper объекта.

// <-- Pass the socket so it can use it
async runEvents(socket) {
    // Create a Shadow event tracker on puppeteer
    await page.exposeFunction("emitter", (...data) => {
      socket.emit(...data)
    });
    await page.evaluate(function observeDom() {
      // expose the observer which will watch
      //More Details https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver
      // select the target node
      var target = document.querySelector(".c-city__digitalClock");
      // create an observer instance
      var observer = new MutationObserver(function(mutations) {
        // Do something on change
        emitter("refresh", target.innerText); // <-- trigger the event whenever there is a change
      });

      // configuration of the observer:
      var config = { childList: true, subtree: true };
      // pass in the target node, as well as the observer options
      observer.observe(target, config);
    });
  }

И тогда ваше соединение будет выглядеть,

io.sockets.on("connection", async function(socket) {
  await scraper.open();
  await scraper.runEvents(socket); // <-- Pass the socket
});

Как это работает,

  • Когда сокет открыт,
  • Открываем браузер и страницу
  • Запускаем события.
    • Мы устанавливаем пользовательское событие, которое будет запускаться socket.emit с любыми данными, которые он получает
    • Мы выставляем пользовательское событие на page.
    • Мы наблюдаем элемент domс тех пор,
    • Когда есть небольшое изменение, мы запускаем пользовательское событие, которое мы сделали

Вот визуальная разница между этими двумя:

(я использовал интервал 500 мс, а это 60 кадров в секунду, поэтому анимация не улавливает все, но она есть, ссылка на репо .)

enter image description here

Разница

Разница между setInterval и событием, setInterval будет проверять через определенное время, в то время как наблюдатель будет непрерывно наблюдать изменения и запускатькогда есть изменения.

Что выбрать:

  • Если вам нравится простота, используйте setInterval версию.
  • Если вам нужна точность, переходите сobserver версия.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...