How can one parse HTML server-side with Meteor? - meteor

I want to be able to scrape links out of an HTML page that I am fetching with the Meteor.http method. Would be ideal to use jQuery on the server-side but I don't think this works.

Consider using cheerio its just like jquery but more for scraping. I have tried to answer this before so I hope I do a better job this time.
its an npm module so first step install it (inside your project dir) with terminal:
meteor add http
cd .meteor
npm install cheerio
So now the code:
You need to use this in your server js/or equivalent
var cheerio = __meteor_bootstrap__.require('cheerio');
Meteor.methods({
last_action: function() {
$ = cheerio.load(Meteor.http.get("https://github.com/meteor/meteor").content);
return $('.commit-title').text().trim()
}
})
If you run this from your client side js, you will see the last action on meteors github branch:
Meteor.call("last_action",function(err,result){ console.log(result) } );
I got this as of today/feb 23rd
which the same as on github.com/meteor/meteor

Use cheerio, as Akshat suggests, but I would recommend a different way of using it, as of now, for Meteor 0.8.0.
First, install npm for Meteor:
$ mrt add npm
Then modify packages.json to (of course you can have different version of cheerio, or other node packages as well):
{
"cheerio": "0.15.0"
}
In server.js (or any other file, in server-side code) start:
var cheerio = Meteor.require('cheerio');
The use cheerio in a way you like.
Upon running $ meteor it will automatically install cheerio.

Related

How to call a Meteor method from the command line

I have a Meteor app and want to call a server method from the command line, so that I can write a bash script to perform scheduled operations.
Is there any way to either call a method directly, or submit a form which will then trigger server-side code?
I've tried using curl to call a method, but either it's not possible or I'm missing something basic. This doesn't work:
curl "http://localhost:3000/Meteor.call('myMethod')"
nor does:
curl -s -d "http://localhost:3000/imports/api/test.js" > out.html
where test.js:
var test = function(){
console.log('hello');
}
I thought of using a form but I can't think how to create a submit event because the Meteor client uses template events that then call server methods.
I'll be very grateful for any help! This feels like it should be a simple thing but has me stumped.
Edit: I've also tried phantomjs and slimerjs as run through casperjs.
phantomjs is no longer maintained and generates an error:
TypeError: Attempting to change the setter of an unconfigurable property.
https://github.com/casperjs/casperjs/issues/1935
slimerjs errors with Firefox 60 and I can't figure out how to 'downgrade' back to the supported 59, and the option to disable automatic updates of Firefox no longer seems to exist. The error is:
c is undefined
https://github.com/laurentj/slimerjs/issues/694
You could make use of the node ddp package to call the Meteor method in an own js file that you created with a specific script. From there you can pipe all outs to wherever you want.
Let's assume the following Meteor method:
Meteor.methods({
'myMethod'() {
console.log("hello console")
return "hello result"
}
})
The upcoming steps will let you call this method from another shell, assuming your Meteor application is running.
1. Install ddp in your global npm directory
$ meteor npm install -g ddp
2. Create the script to call your method in your test directory
$ mkdir -p ddptest
$ cd ddptest
$ touch ddptest.js
Place the ddp script code into the file with the editor or command of your choice.
(The follwing code is freely taken from the package's readme. Feel free to configure to your needs.)
ddptest/ddptest.js
var DDPClient = require(process.env.DDP_PATH);
var ddpclient = new DDPClient({
// All properties optional, defaults shown
host : "localhost",
port : 3000,
ssl : false,
autoReconnect : true,
autoReconnectTimer : 500,
maintainCollections : true,
ddpVersion : '1', // ['1', 'pre2', 'pre1'] available
// uses the SockJs protocol to create the connection
// this still uses websockets, but allows to get the benefits
// from projects like meteorhacks:cluster
// (for load balancing and service discovery)
// do not use `path` option when you are using useSockJs
useSockJs: true,
// Use a full url instead of a set of `host`, `port` and `ssl`
// do not set `useSockJs` option if `url` is used
url: 'wss://example.com/websocket'
});
ddpclient.connect(function(error, wasReconnect) {
// If autoReconnect is true, this callback will be invoked each time
// a server connection is re-established
if (error) {
console.log('DDP connection error!');
console.error(error)
return;
}
if (wasReconnect) {
console.log('Reestablishment of a connection.');
}
console.log('connected!');
setTimeout(function () {
/*
* Call a Meteor Method
*/
ddpclient.call(
'myMethod', // namyMethodme of Meteor Method being called
['foo', 'bar'], // parameters to send to Meteor Method
function (err, result) { // callback which returns the method call results
console.log('called function, result: ' + result);
ddpclient.close();
},
function () { // callback which fires when server has finished
console.log('updated'); // sending any updated documents as a result of
console.log(ddpclient.collections.posts); // calling this method
}
);
}, 3000);
});
The code assumes that your app runs on localhost:3000, note that there is no conncection close on errors or undesired behavior.
As you can see at the top, the file imports your globally installed ddp package. Now in order to get it's path without using additional tools, just pass an environment variable (process.env.DDP_PATH) and let your shell handle the path resolving.
In order to get the installation path you can use npm root with the global flag.
Finally call your script via:
$ DDP_PATH=$(meteor npm root -g)/ddp meteor node ddptest.js
Which will give you the following output:
connected!
updated
undefined
called function, result: hello result
And logs hello console to the open session that is running your meteor app.
Edit: A note on using this in production
If you want to use this script in production you have to use the shell commands without the meteor command but using your installation of node and npm.
If you get in trouble with paths use process.execPath to find your node binary and npm root -g to find your global npm modules.
You can check out this documentation: Command Line | meteor shell.
While your meteor app is running, you can execute meteor shell to start an interactive console. In the console, you can do Meteor.call(...).
So if you want to write a script with using meteor shell, you might need to pipe the script file for meteor shell. Like,
$ meteor shell < script_file
See also the answer of "How can I pipe a command into the meteor shell?"

Iron router: Error: Couldn't find a template named "/" or "". Are you sure you defined it?

I have trouble setting up a simple iron:router example: (docs, sample app)
meteor create testapp
cd testapp
home.html:
<template name="Home">
<h1>Welcome</h1>
home
</template>
router.js:
Router.route('/', function () {
this.render('Home'); // Also tried 'home'
});
Starting the server:
meteor
Then I get (client side):
Exception from Tracker recompute function: Error: Couldn't find a template named "/" or "". Are you sure you defined it?
at null._render (http://localhost:3000/packages/iron_dynamic-template.js?32038885cb1dad7957291ffebfffcb7f8cd57d20:239:17)
at doRender (http://localhost:3000/packages/blaze.js?88aac5d3c26b7576ac55bb3afc5324f465757709:1853:25)
...
What am I doing wrong ?
Note: I get the exact same error if I clone the example application (basic.html and basic.js).
meteor list
autopublish 1.0.1 Publish the entire database to all clients
insecure 1.0.1 Allow all database writes by default
iron:router 0.9.4 Routing specifically designed for Meteor
meteor-platform 1.1.2 Include a standard set of Meteor packages in your app
Also:
meteor --version
Meteor 0.9.4 <- Why all standard packages and meteor platform are > 1.0 and this is 0.9.4 ?
Currently, there are two versions of iron:router.
iron:router#0.9.4 is the one added by default when you type meteor add iron:router, this version is the latest in the "legacy" branch of iron:router that came up more than one year ago, it's the one that everyone is probably still using, although they should definitely update to...
iron:router#1.0.0-preX with X = 4 as of 20/10/2014, which is a complete rewrite of the package intended to be backward compatible, but introducing a new, nicer and polished API. This version will likely be set as default when meteor hits 1.0.0 later this year. The problem is that github page of iron:router shows this particular branch (1.0.0-pre4) along with examples that people believe are usable with 0.9.4.
This means that you are most likely using the wrong version of iron router, remove it with meteor remove iron:router and meteor add iron:router#1.0.0-pre4 instead.
Recommended reading to learn about the latest iron:router syntax :
http://eventedmind.github.io/iron-router/
Sometimes the guide is not completely up-to-date with the pre-release version, if you want to keep up with the latest stuff take a look at github issues.

Reactive Code without mongodb in Meteor and using NPM packages with Meteor

I am playing around with Meteor and I am trying, to connect the serverside of the application to another server S.
Therefore I want to open an TLS client socket and push the received data to the client, every time the server S transmits data.
Now I have two questions:
Can I require node packages in the usual way (e.g. var Candle = require('candle');)?
Is it possible, to create reactive code without writing the received data to a collection, which is stored in the mongodb database?
In other words, I just want to push the data to all clients, without saving it on the server.
1
To require a npm package, you need to install npm package via mrt add npm.
Then you add packages.json file with the list of necessary packages, for example:
{
"candle": "0.4.0",
"oauth": "0.9.11"
}
Afterwards, you can require the package with Meteor.require('candle');.
2
To create a reactive code you use Dependencies – see the documentation. Basically, you create a dep:
var dep = new Deps.Dependency();
mark the functions that should be recalculated when the dep is changed:
Templates.example.something = function() {
dep.depend();
...
}
And then change it when necessary:
dep.changed();
I can only answer your first question.
In order to integrate npm packages, you should add npm package via meteorite and create a packages.json file as documented here: https://github.com/arunoda/meteor-npm
Then you can load npm modules as follows:
var Candle = Meteor.require('candle');

Meteor cannot find module "module"

I'm trying to install the Spooky module in meteor (this one is in my public folder: app/public/node_modules).
I've read answers in this post and added the following code in server/server.js
Meteor.startup ->
path = Npm.require 'path'
fs = Npm.require 'fs'
base = path.resolve '.'
isBundle = fs.existsSync base + '/bundle'
modulePath = base + (if isBundle then '/bundle/static' else '/public') + '/node_modules'
spooky = Npm.require modulePath + '/spooky'
But when I'm running meteor I get:
Error: Cannot find module '/Users/mac/Documents/websites/app/.meteor/local/build/programs/server/public/node_modules/spooky'
You need to create a smart package to use Npm modules in your app. Alternatively you can use meteor-npm.
You can't use Npm.require on its own for non standard npm modules like spooky.
If you use meteor-npm you can install it with meteorite: mrt add npm
Then use Meteor.require("spooky") instead, after you have added the module to your packages.json. You can have a look here for more details: http://meteorhacks.com/complete-npm-integration-for-meteor.html.
The official way to do it is to make your own smart package to wrap the npm module in. There is an example of such a package: https://github.com/avital/meteor-xml2js-npm-demo
The example uses xml2js as the npm module, but you could swap the names around so its spooky instead.
Then you can add this package into your /packages folder (say with the name spooky), and add it to your meteor project with meteor add spooky.
The packages on atmosphere.meteor.com have more examples of this, they pretty much do the same thing (e.g stripe (https://atmosphere.meteor.com/package/stripe)).
The article Akshat linked to has been updated:
cd project
meteor add meteorhacks:npm
Edit project/packages.json:
{
"redis": "0.8.2",
"github": "0.1.8"
}
Use those npm modules:
var Github = Meteor.npmRequire('github');
var github = new Github();
github.gists.getFromUser({user: 'arunoda'}, function(err, gists) {
console.log(gists);
});

Meteor: EJSON is not defined

I'm trying to use a private JSON file to add some simple template documents to the mongo collection if it is empty:
if (Passions.find().count() === 0) {
mockPassions = JSON.parse(Assets.getText("mockups/passions.json"));
_.each(mockPassions.passions, function(passion) {
return Passions.insert(passion);
});
}
I'm getting the error:
ReferenceError: EJSON is not defined
Does anyone have any clue? I'm using Meteor 0.6.5.
Thanks
You need to bring EJSON up to the global namespace via
meteor add ejson
In meteor 0.6.5 unless you explicitly tell it to, packages are namespaced into package
Considering Latest Meteor 1.6, you can follow below steps:
A. First Approach [Independent of the meteor restart/stop/start]
Edit .meteor/packages file and add 'ejson' to end of the file
B. Second Approach
Stop Server if already running by pressing ctrl+c
Run command meteor add ejson
Restart Server using command meteor

Resources