Czy mogę używać jQuery z Node.js?

574

Czy można używać selektorów jQuery / manipulacji DOM po stronie serwera przy użyciu Node.js?

Jan
źródło
3
Zastanawiam się: po co korzystać po stronie serwera, skoro można to zrobić po stronie klienta?
Inanc Gumus
31
Być może możesz chcieć utworzyć skrobak internetowy, który w regularnych odstępach czasu usuwa określone informacje i przechowuje wyniki w bazie danych? Nie byłoby to tak praktyczne ze strony klienta.
Trevor
2
Powinieneś także spojrzeć na phantomjs, które pozwalają emulować stronę przeglądarki za pomocą silnika V8.
Dimitri Kopriwa
2
Manipulacja DOM @deeperx DOM po stronie serwera może być użyteczna podczas tworzenia przeszukiwacza. Zobacz tę odpowiedź .
Lucio Paiva,
TAK - spójrz na tę odpowiedź - wolę to niż używanie cheerio, ponieważ masz pełną moc selektora jQuery.
monika mevenkamp

Odpowiedzi:

563

Aktualizacja (27 czerwca-18) : Wygląda na to, że nastąpiła poważna aktualizacja, jsdomktóra powoduje, że pierwotna odpowiedź nie działa. Znalazłem odpowiedź, która wyjaśnia, jak korzystać jsdomteraz. Skopiowałem odpowiedni kod poniżej.

var jsdom = require("jsdom");
const { JSDOM } = jsdom;
const { window } = new JSDOM();
const { document } = (new JSDOM('')).window;
global.document = document;

var $ = jQuery = require('jquery')(window);

Uwaga: Oryginalna odpowiedź nie wspomina, że ​​będziesz musiał zainstalować jsdom również za pomocąnpm install jsdom

Aktualizacja (pod koniec 2013 r.) : Oficjalny zespół jQuery ostatecznie przejął zarządzanie jquerypakietem na npm:

npm install jquery

Następnie:

require("jsdom").env("", function (err, window) {
    if (err) {
        console.error(err);
        return;
    }
    var $ = require("jquery")(window);
});

Philippe Rathé
źródło
43
Czy można używać jQuery ajax z node.js z tym modułem npm?
ajsie
22
Nie instaluje się w systemie Windows (bez znaczącej pracy), w takim przypadku poleciłbym moduł Cheerio: matthewmueller.github.com/cheerio
Simon East
7
+1 za pokazanie gdzie zdobyć npm :) większość ludzi ma zły nawyk po prostu wymieniać rzeczy tak, jakby to miało być dane (zdrowy rozsądek)
Val
12
To zwraca require("...").env is not a function.
Banderi
4
@Banderi to samo ze mną, jakiś pomysł? błąd:TypeError: require(...).env is not a function
coderInrRain
58

Tak, możesz, korzystając z utworzonej przeze mnie biblioteki o nazwie nodeQuery

var Express = require('express')
    , dnode = require('dnode')
    , nQuery = require('nodeQuery')
    , express = Express.createServer();

var app = function ($) {
    $.on('ready', function () {
        // do some stuff to the dom in real-time
        $('body').append('Hello World');
        $('body').append('<input type="text" />');
        $('input').live('click', function () {
            console.log('input clicked');
            // ...
        });
    });
};

nQuery
    .use(app);

express
    .use(nQuery.middleware)
    .use(Express.static(__dirname + '/public'))
    .listen(3000);

dnode(nQuery.middleware).listen(express);
Thomas Blobaum
źródło
20
Zauważ, że nodeQuery zmienia stronę użytkownika w czasie rzeczywistym, więc jest jeszcze fajniejszy, niż można się spodziewać.
alessioalex,
Szukałem czegoś takiego, kiedy natknąłem się tutaj ... Właśnie spojrzałem na pakiety nQuery i węzłów jquery, a nQuery zostało zaktualizowane rok temu, gdzie wczoraj była jquery ... Czy nQuery nie jest już rozwijany? i czy jquery wpływa na stronę klienta, podobnie jak nQuery? Czy ktoś może próbował ich obu?
Logan,
2
@Logan nQuery to po prostu jquery. różnica polega na tym, że kod jest uruchamiany na serwerze i zamiast dostarczać kod jquery do przeglądarki, uruchamia kod na serwerze i zdalnie wykonuje manipulację domem na podłączonych przeglądarkach. Zauważ też, że nQuery był projektem eksperymentalnym i chociaż przyjmuję żądania ściągania w celu naprawy błędów, nigdy nie został stworzony do żadnego konkretnego celu lub projektu, więc nie miał wielu zobowiązań
Thomas Blobaum
@ThomasBlobaum nie działa dla mnie, błąd: , express = Express.createServer();i TypeError: Express.createServer is not a functionjakiś pomysł?
coderInrRain
@ThomasBlobaum wygląda na to, że nie masz najnowszej wersji Express. Spróbuj npm install --save expressw wierszu polecenia.
gilbert-v
55

W momencie pisania jest również utrzymane Cheerio .

Szybka, elastyczna i oszczędna implementacja podstawowego jQuery zaprojektowanego specjalnie dla serwera.

Alfred
źródło
2
+1 dla Cheerio. Z drugiej strony jsdom jest bardzo bolesny w uruchamianiu w systemie Windows.
Simon East
1
Czy Cheerio może używać odroczonych zdarzeń i wywołań ajax?
Hoffmann
6
nie obsługuje wielu selektorów takich jak:gt(1)
chovy
1
Z mojego doświadczenia wynika, że ​​ten działa najlepiej. Jest o wiele szybszy niż JSDOM.
Jason Prawn
1
@Hoffmann, spędziłem sekundę, aby sprawdzić dokumenty dla ciebie. Nie. Cheerio ma tylko metody związane z DOM.
Denis,
39

Za pomocą jsdom możesz teraz. Wystarczy spojrzeć na ich przykład jquery w katalogu przykładów.

Benjamin Coe
źródło
jedną wadą jQueryify () jsdom jest to, że uruchamia wszystkie skrypty strony.
narysowany
i nie działa w systemie Windows bez wielu bólów głowy
Jason Goemaat
1
w 2016 roku nie potrzebujesz jsdom - patrz moja odpowiedź: stackoverflow.com/a/40656811/3391783
low_rents
34

Prosty robot wykorzystujący Cheerio

To jest moja formuła na stworzenie prostego robota w Node.js. Jest to główny powód, dla którego chcesz wykonywać manipulacje DOM po stronie serwera i prawdopodobnie jest to powód, dla którego tu trafiłeś.

Najpierw użyj, requestaby pobrać stronę do przeanalizowania. Po zakończeniu pobierania obsłuż go cheerioi rozpocznij manipulację DOM, tak jak przy użyciu jQuery.

Przykład roboczy:

var
    request = require('request'),
    cheerio = require('cheerio');

function parse(url) {
    request(url, function (error, response, body) {
        var
            $ = cheerio.load(body);

        $('.question-summary .question-hyperlink').each(function () {
            console.info($(this).text());
        });
    })
}

parse('http://stackoverflow.com/');

Ten przykład wydrukuje w konsoli wszystkie najważniejsze pytania wyświetlane na stronie głównej SO. Właśnie dlatego uwielbiam Node.js i jego społeczność. Nie może być łatwiej :-)

Zainstaluj zależności:

npm cheerio żądanie instalacji

I uruchom (zakładając, że powyższy skrypt znajduje się w pliku crawler.js ):

węzeł crawler.js


Kodowanie

Niektóre strony będą zawierać treści w języku innym niż angielski w pewnym kodowaniu i konieczne będzie ich odkodowanie UTF-8. Na przykład strona w portugalskim języku brazylijskim (lub innym języku pochodzenia łacińskiego) prawdopodobnie będzie zakodowana w ISO-8859-1(inaczej „latin1”). Kiedy potrzebne jest dekodowanie, mówię, requestaby nie interpretować treści w żaden sposób i zamiast tego używaćiconv-lite do wykonania zadania.

Przykład roboczy:

var
    request = require('request'),
    iconv = require('iconv-lite'),
    cheerio = require('cheerio');

var
    PAGE_ENCODING = 'utf-8'; // change to match page encoding

function parse(url) {
    request({
        url: url,
        encoding: null  // do not interpret content yet
    }, function (error, response, body) {
        var
            $ = cheerio.load(iconv.decode(body, PAGE_ENCODING));

        $('.question-summary .question-hyperlink').each(function () {
            console.info($(this).text());
        });
    })
}

parse('http://stackoverflow.com/');

Przed uruchomieniem zainstaluj zależności:

npm żądanie instalacji iconv-lite cheerio

A potem w końcu:

węzeł crawler.js


Poniższe linki

Następnym krokiem będzie skorzystanie z linków. Powiedz, że chcesz wyświetlić listę wszystkich plakatów z każdego górnego pytania w SO. Najpierw musisz wymienić wszystkie najważniejsze pytania (przykład powyżej), a następnie wprowadzić każdy link, analizując stronę każdego pytania, aby uzyskać listę zaangażowanych użytkowników.

Kiedy zaczniesz podążać za linkami, możesz zacząć piekło zwrotne . Aby tego uniknąć, powinieneś użyć obietnic, przyszłości lub cokolwiek innego. Zawsze trzymam asynchronię w pasku narzędzi. Oto pełny przykład robota używającego asynchronizacji:

var
    url = require('url'),
    request = require('request'),
    async = require('async'),
    cheerio = require('cheerio');

var
    baseUrl = 'http://stackoverflow.com/';

// Gets a page and returns a callback with a $ object
function getPage(url, parseFn) {
    request({
        url: url
    }, function (error, response, body) {
        parseFn(cheerio.load(body))
    });
}

getPage(baseUrl, function ($) {
    var
        questions;

    // Get list of questions
    questions = $('.question-summary .question-hyperlink').map(function () {
        return {
            title: $(this).text(),
            url: url.resolve(baseUrl, $(this).attr('href'))
        };
    }).get().slice(0, 5); // limit to the top 5 questions

    // For each question
    async.map(questions, function (question, questionDone) {

        getPage(question.url, function ($$) {

            // Get list of users
            question.users = $$('.post-signature .user-details a').map(function () {
                return $$(this).text();
            }).get();

            questionDone(null, question);
        });

    }, function (err, questionsWithPosters) {

        // This function is called by async when all questions have been parsed

        questionsWithPosters.forEach(function (question) {

            // Prints each question along with its user list
            console.info(question.title);
            question.users.forEach(function (user) {
                console.info('\t%s', user);
            });
        });
    });
});

Przed uruchomieniem:

npm żądanie instalacji asynchroniczne cheerio

Uruchom test:

węzeł crawler.js

Przykładowe dane wyjściowe:

Is it possible to pause a Docker image build?
    conradk
    Thomasleveil
PHP Image Crop Issue
    Elyor
    Houston Molinar
Add two object in rails
    user1670773
    Makoto
    max
Asymmetric encryption discrepancy - Android vs Java
    Cookie Monster
    Wand Maker
Objective-C: Adding 10 seconds to timer in SpriteKit
    Christian K Rider

I to jest podstawa, którą powinieneś wiedzieć, aby zacząć tworzyć własne roboty :-)


Wykorzystane biblioteki

Lucio Paiva
źródło
22

w 2016 roku sprawy są znacznie łatwiejsze. zainstaluj jquery w node.js za pomocą konsoli:

npm install jquery

powiąż go ze zmienną $(na przykład - jestem do tego przyzwyczajony) w kodzie node.js:

var $ = require("jquery");

robić coś:

$.ajax({
    url: 'gimme_json.php',
    dataType: 'json',
    method: 'GET',
    data: { "now" : true }
});

działa również dla gulp, ponieważ jest oparty na node.js.

low_rents
źródło
Jakiej wersji węzła używasz? Na Macu, Node 6.10.2, jquery 2.2.4, var $ = require("jquery"); $.ajax // undefined (Na razie głosowanie negatywne).
AJP
@AJP i jesteś pewien, że zrobiłeś npm install jquerypierwszy?
low_rents
1
Tak. > console.log(require("jquery").toString());daje mi funkcję fabryczną: function ( w ) { if ( !w.document ) { throw new Error( "jQuery requires a window with a document" ); } return factory( w ); } musiałem użyć powyższej odpowiedzi z jsdom: stackoverflow.com/a/4129032/539490
AJP
@AJP ok, to dziwne.
low_rents
Dostaję dokładnie taką samą funkcję fabryczną jak @AJP. Jakiej wersji jquery użyłeś, @low_rents?
Boris Burkov
18

Uważam, że odpowiedź na to pytanie brzmi: tak.
https://github.com/tmpvar/jsdom

var navigator = { userAgent: "node-js" };  
var jQuery = require("./node-jquery").jQueryInit(window, navigator);
rdzah
źródło
9
Przykro mi informować, że uruchomienie jQuery na jsdom wymaga więcej pracy. Skwierczenie jednak działa! Naprawdę chcę zachować jsdom tak lekki, jak to możliwe, więc dodanie pełnej emulacji przeglądarki, takiej jak env.js, nie jest w tej chwili tak naprawdę priorytetem.
tmpvar
nieważne, znalazłem zmodyfikowaną kopię dołączoną do jsdom.
zremisował
FYI węzeł-jquery jest teraz przestarzałe na rzecz jquery
Ruslan López
1
ReferenceError: okno nie jest zdefiniowane
Bonn
17

npm install jquery --save # Uwaga WSZYSTKIE DOLNE

npm install jsdom --save

const jsdom = require("jsdom");
const dom = new jsdom.JSDOM(`<!DOCTYPE html>`);
var $ = require("jquery")(dom.window);


$.getJSON('https://api.github.com/users/nhambayi',function(data) {
  console.log(data);
});
Noah
źródło
to jest zgrabna odpowiedź! proszę głosować za tym
datdinhquoc
8

Moduł jQuery można zainstalować za pomocą:

npm install jquery

Przykład:

var $ = require('jquery');
var http = require('http');

var options = {
    host: 'jquery.com',
    port: 80,
    path: '/'
};

var html = '';
http.get(options, function(res) {
res.on('data', function(data) {
    // collect the data chunks to the variable named "html"
    html += data;
}).on('end', function() {
    // the whole of webpage data has been collected. parsing time!
    var title = $(html).find('title').text();
    console.log(title);
 });
});

Referencje jQuery w Node.js **:

SUNDARRAJAN K
źródło
2
Nie działa dla mnie ... C: \ ... \\ node_modules \ jquery \ dist \ jquery.js: 31 wyrzuć nowy błąd („jQuery wymaga okna z dokumentem”); ^ Błąd: jQuery wymaga okna z dokumentem w module.exports (C: \ ... \ WebContent \ resources \ js \ node_modules \ jquery \ dist \ jquery.js: 31: 12)
Jose Manuel Gomez Alvarez
var jsdom = wymagany („jsdom”); var window = jsdom.jsdom (). defaultView; jsdom.jQueryify (okno, „ code.jquery.com/jquery.js ”, funkcja () {var $ = okno. $; $ („body”). prepend („<h1> tytuł </h1>”) ; console.log ($ („h1”). html ());});
SUNDARRAJAN K
7

Musisz otworzyć okno za pomocą nowego API JSDOM.

const jsdom = require("jsdom");
const { window } = new jsdom.JSDOM(`...`);
var $ = require("jquery")(window);
UnchartedWorks
źródło
.JSDOM ( ...) powinien być .JSDOM („<! DOCTYPE html>”) dla obsługi HTML5?
datdinhquoc
2

OSTRZEŻENIE

To rozwiązanie, o którym wspomniał Golo Roden, jest nieprawidłowe . Jest to tylko szybka poprawka, aby pomóc ludziom uruchomić ich rzeczywisty kod jQuery za pomocą struktury aplikacji Node, ale nie jest to filozofia Node, ponieważ jQuery nadal działa po stronie klienta, a nie po stronie serwera. Przepraszam za udzielenie złej odpowiedzi.


Możesz także wyrenderować Jade z węzłem i umieścić w nim swój kod jQuery. Oto kod pliku jadeit:

!!! 5
html(lang="en")
  head
    title Holamundo!
    script(type='text/javascript', src='http://code.jquery.com/jquery-1.9.1.js')
  body
    h1#headTitle Hello, World
    p#content This is an example of Jade.
    script
      $('#headTitle').click(function() {
        $(this).hide();
      });
      $('#content').click(function() {
        $(this).hide();
      });
Timbergus
źródło
4
Zagłosowano, ponieważ w pytaniu wyraźnie stwierdzono, że chodzi o jQuery po stronie serwera. Po prostu osadzając jQuery w jadeitowym pliku, jQuery jest nadal uruchamiany po stronie klienta. Dlatego ta odpowiedź nie pomaga: - /
Golo Roden
2
Ok, bardzo dziękuję. Rozumiem to. Spróbuję wyjaśnić to w odpowiedzi, aby nie mylić osób, które ją czytają. Jeszcze raz dziękuję za pomoc Golo.
Timbergus
2
Nie ma za co :-). I nieważne: wszyscy popełniamy błędy, więc nie martw się :-)
Golo Roden
2

Mój działający kod to:

npm install jquery

i wtedy:

global.jQuery   = require('jquery');
global.$        = global.jQuery;

lub jeśli okno jest obecne, to:

typeof window !== "undefined" ? window : this;
window.jQuery   = require('jquery');
window.$        = window.jQuery;
rzymski
źródło
1

Moduł jsdom jest doskonałym narzędziem. Ale jeśli chcesz ocenić całe strony i zrobić trochę funky po stronie serwera, sugeruję uruchomienie ich we własnym kontekście:

vm.runInContext

Tak więc rzeczy takie jak require/ CommonJSon site nie wysadzą samego procesu węzła.

Dokumentację można znaleźć tutaj . Twoje zdrowie!

Jakub Oboza
źródło
1

Począwszy od jsdom v10, funkcja .env () jest przestarzała. Zrobiłem to jak poniżej po wypróbowaniu wielu rzeczy, które wymagają jquery:

var jsdom = require('jsdom');
const { JSDOM } = jsdom;
const { window } = new JSDOM();
const { document } = (new JSDOM('')).window;
global.document = document;

var $ = jQuery = require('jquery')(window);

Mam nadzieję, że pomoże to Tobie lub każdemu, kto napotkał tego rodzaju problemy.

Plabon Dutta
źródło
TypeError: JSDOM is not a constructor
Nathan Hawks,
Jeśli korzystasz z jQuery po stronie węzła, najpierw zainstaluj jquery i jsdom przy użyciu npm install. Następnie dodaj powyższe wiersze do pliku, w którym próbujesz użyć selektora jquery. Na przykład użyłem $.each. Właśnie zamieściłem te linie, a potem zrobiłem to tak: $.each(errors, function (ind,error) { res.send(error.msg);console.log(error.msg); }); Mam nadzieję, że to pomaga !!
Plabon Dutta
Jakoś jsdom postanowił w ogóle nie instalować. Chyba wciąż zastanawiam się nad npm. Dzięki @
Nathan Hawks,
0

Żadne z tych rozwiązań nie pomogło mi w mojej aplikacji Electron.

Moje rozwiązanie (obejście):

npm install jquery

W twoim index.jspliku:

var jQuery = $ = require('jquery');

W swoich .jsplikach napisz swoje funkcje jQuery w następujący sposób:

jQuery(document).ready(function() {
Elio Osés
źródło
-1

Nie. Przeniesienie środowiska przeglądarki do węzła będzie dość dużym wysiłkiem.

Innym podejściem, które obecnie badam pod kątem testów jednostkowych, jest stworzenie „próbnej” wersji jQuery, która zapewnia wywołania zwrotne przy każdym wywołaniu selektora.

W ten sposób możesz jednostkowo przetestować wtyczki jQuery bez posiadania DOM. Nadal będziesz musiał przetestować w prawdziwych przeglądarkach, aby sprawdzić, czy Twój kod działa na wolności, ale jeśli odkryjesz specyficzne problemy z przeglądarką, możesz łatwo „wyśmiewać” je w testach jednostkowych.

Pchnę coś na github.com/felixge, gdy będzie gotowe do pokazania.

Felix Geisendörfer
źródło
Podoba mi się ten pomysł ... powinien być łatwy do zrobienia.
Sudhir Jonathan
-1

Możesz użyć Electron , pozwala on na hybrydowe przeglądarki i nodejs.

Wcześniej próbowałem używać canvas2d w nodejs, ale w końcu się poddałem. Nie jest obsługiwany przez domyślny nodejs i jest zbyt trudny do zainstalowania (wiele wielu ... zależności). Dopóki nie użyję Electron, mogę z łatwością używać całego mojego poprzedniego kodu przeglądarki, nawet WebGL, i przekazać wartość wyniku (np. Wynik obrazu base64 obrazu) do kodu nodejs.

gonnavis
źródło
-9

Nie żebym o tym wiedział. DOM jest sprawą po stronie klienta (jQuery nie analizuje HTML, ale DOM).

Oto niektóre bieżące projekty Node.js:

https://github.com/ry/node/wiki ( https://github.com/nodejs/node )

A djangode SimonW jest całkiem fajny ...

Nosredna
źródło
Chciałbym, żeby to było możliwe. Próbowałem już dołączyć jquery do projektu node.js i oczywiście nie działało. jQuery jest oparty na dokumencie / oknie. Rhino jest w stanie uruchomić stronę jQuery po stronie serwera: ejohn.org/blog/bringing-the-browser-to-the-server. Będę szukał więcej parserów. Może jest taki, który nie zależy od przeglądarki.
Jan
@John: jedynym powodem, dla którego jQuery może działać na Rhino, jest ten projekt: github.com/jeresig/env-js/blob/master/src/env.js Symuluje niewielką część DOM i środowiska wykonawczego JavaScript. Opiera się na Java apis, więc nie jest to konieczne dla Node.js (który używa V8 / C ++).
Crescent Fresh
2
@Nosredna Chociaż mogło to być prawdą, kiedy to napisałeś, to oczywiście nie jest już prawdą. Sugeruję, aby usunąć swoją odpowiedź teraz.
Keith Pinson
-18

Alternatywą jest użycie Underscore.js . Powinien dostarczać to, czego mogłeś chcieć po stronie serwera od JQuery.

John Wright
źródło
10
Możesz wytłumaczyć? jQuery zapewnia mnóstwo interfejsów API do manipulacji / przeszukiwania / filtrowania DOM. Podkreślenie wygląda jak ogólne narzędzia biblioteczne, które nie mają nic wspólnego z DOM.
Peter Lyons,
1
To samo tutaj, nie widzę, jak to jest istotne, oba są uzupełnieniami, a nie alternatywami
Yi Jiang
2
Ta odpowiedź nie jest całkowicie błędna. jQuery i Underscore nakładają się: oba zapewniają funkcje takie jak forEach.
tuomassalo
8
-1 Mają funkcję nakładania się, ale podkreślenie nie zastępuje jQuery.
Sam
2
Pytanie dotyczy jednak manipulacji / selektorów DOM.
mikermcneil