Cheerio: SyntaxError: Malformed attribute selector: object global? - javascript

Here is my code:
var request = require('request'),
cheerio = require('cheerio'),
async = require('async');
function updateCars(){
function getReviews(body){
var $ = cheerio.load(body);
var year = $(this).find(".field-item").text();
}
async.series([
....
function(callback) {
request(site+path, function(err, resp, body){
if(!err && resp.statusCode == 200){
var $ = cheerio.load(body);
$(".views-row").each(getReviews(body));
}
});
}
]);
}
When I run it in the node console, I get the follwing error:
SyntaxError: Malformed attribute selector: object global]
How can I fix that?

The error...
SyntaxError: Malformed attribute selector: object global]
Is actually spot on. Since there's only a snippet of the offending code posted here, it's not entirely clear where this is happening, but it's definitely a clerical error in an attribute selector - and most likely it's this...
Answer:
$('div[id^=foo_bar'); // <-- missing the closing ]
The above example is an error you normally (or whoever coded the site you are scraping) wouldn't notice because jQuery normally quietly handles this mistake...
Proof jQuery Handles It:
var fooBars = $('a[id^="foo_bar"'); //<-- missing closing ]
$('#results').append("See... jQuery don't care about your closing ']' -" + fooBars.length)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<a id="foo_bar_1">1</a>
<a id="foo_bar_2">2</a>
<a id="foo_bar_3">3</a>
<a id="foo_bim_4">4</a>
<a id="foo_bar_5">5</a>
<div id="results"></div>
Explanation:
The error is actually Sizzle yelling at you, from somewhere beneath cheerio. While jQuery is utilizing the pure javascript implementation...
var fooBar = document.querySelectorAll('a[id="foo_bar"'); // <-- missing
alert(fooBar.length); // works!
Cheerio is using Sizzle, which does not like the "malformed" attribute (used to be a problem in IE 7-9 as well)...
Like jQuery, [Cheerios] primary method for selecting elements in the
document, but unlike jQuery it's built on top of the CSSSelect
library, which implements most of the Sizzle selectors.

Related

MongoDB script fails to load, but code works in Mongo shell

I have the following script (script.js):
categoricalVars = db.frekvencija_ctg.find().toArray();
​
db.ctg.find().forEach(e => {
db.emb_ctg.insert({ ...e, frekvencija: categoricalVars });
});
When I try to load it in Mongo shell via load("script.js"), I get the following error:
[js] SyntaxError: illegal character :
If I run these expressions in Mongo shell one by one with copy/paste, they work and I get desired result. What is wrong in script?
Seems like you're using an old version of node that doesn't support fancy syntax. Either udgrade node or use old school syntax like :
var categoricalVars = db.frekvencija_ctg.find().toArray();
​
db.ctg.find().forEach(function(e){
db.emb_ctg.insert(Object.assign({},e, {frekvencija: categoricalVars }));
});
I have got this error before and I have resolved this by removing the braces from the arrow function passed to the forEach() method.
Try changing your script to something like this
categoricalVars = db.frekvencija_ctg.find().toArray();
​
db.ctg.find().forEach(function(e){
var obj = {...e};
obj.frekvencija = categoricalVars;
db.emb_ctg.insert(obj);
});

I get: SyntaxError: missing ) after argument list, but I can't see anything missing

I have tried everything and noticed that the function will only work if I delete all arguments after #item.Host.
I occasionally get
SyntaxError: '' string literal contains an unescaped line break
if I try to tinker with arguments order:
<a href="#" onclick="sideBarMenu('#item.Type', '#item.TimeUtc.ToLongTimeString()', '#item.Host', '#item.Message', '#item.Source', '#item.User', '#item.AllXml')">
function sideBarMenu(type, time, host, message, source, user, xml) {
document.getElementById("sidebar2").style.right = ("-10px")
document.getElementById("side-bar-icon").classList.add("rotate")
document.getElementsByClassName("card-header")[0].innerHTML = type;
document.getElementsByClassName("time-for-logs")[0].innerHTML = time;
document.getElementsByClassName("card-host")[0].innerHTML = host;
document.getElementsByClassName("card-message")[0].innerHTML = message;
document.getElementsByClassName("card-source")[0].innerHTML = source;
document.getElementsByClassName("card-user")[0].innerHTML = user;
document.getElementsByClassName("card-text")[0].innerHTML = xml;
}
Code should pass all the values to the JS function without any error.
To solve my issue I had to use C# Utility to encode my JS
many of you have pointed my in to right direction, even that I haven't include a lot of code.
solution was to wrap my value like this:
'#HttpUtility.JavaScriptStringEncode(item.Type)'

Node.js VM and string concatenation

I have an HTML file thats dynamically generated and only has a javascript object commented out. I'm trying to read that file, take the object out as a string, and run it with VM's runInNewContext(). But I run into a few hurdles.
Heres my code:
The file I have to read:
/*
{
"userId": ["2897599"],
"addressId": ["1287124"]
}
*/
The code I'm trying to use:
var startDataMap = body.indexOf('{')
, endDataMap = body.indexOf('}')
, dataMap = body.substring(startDataMap, endDataMap);
var sandbox = {};
try {
vm.runInNewContext(dataMap, sandbox)
} catch (error) {
console.log(error)
};
If I run this it'll kick back an error of:
[SyntaxError: Unexpected token :]
If I run it with a regex (ie with (/\{/) instead of ('{') ) it will execute without an error but it doesnt catch the data.
Question: Why will neither attempt work and how can I get the data I need using VM?
Update:
I took the advice of the answer below and it removed the error and added a tweak or two. Here is the updated code:
var startDataMap = body.indexOf('{')
, endDataMap = body.indexOf('*/', startDataMap)
, dataMap = body.substring(startDataMap, endDataMap);
var sandbox = {};
try {
vm.runInNewContext( '(' + dataMap + ')', sandbox)
} catch (error) {
console.log(error)
};
It removes the error but sandbox is still empty. I checked dataMap and it does have the required data but there is a line of whitespace at the end. Will this throw VM off? If so, how can I get rid of it, or do I need to alter my endDataMap ?
You likely need to add parentheses, so that the string is interpreted as an object instead of a block:
vm.runInNewContext("(" + dataMap + ")", sandbox)
Curly braces that are not in an expression are treated a blocks. By placing the code inside of parentheses, you make it clear that the code should be an object literal, rather than a block.

Having problems structuring Cheerio scraping

I think this may be just basic syntax. I'm coming from Java and very new to Javascript. For example, when I see a $ in all the examples, my mind goes blank.
Code for parsing the HTTP request (which contains a bunch of dog shows) looks like (using the request library):
function parseRequest1(error, response, body) {
// TODO should check for error...
var Cheerio = require('cheerio');
parser = Cheerio.load(body);
var table2 = parser('.qs_table[bgcolor="#71828A"]');
var showList = [];
// skip over a bunch of crap to find the table. Each row with this BG color represents a dog show
var trows = parser('tr[bgcolor="#FFFFFF"]', table2);
trows.each(function(i, tablerow) {
var show = parseShow(tablerow);
if (show) // returns a null if something went wrong
showList.push(show);
});
// then do something with showList...
}
which is called by
Request.get(URL, parseRequest1);
So far, so good. Where I'm stuck is in how to write the parseShow function. I'd like to go something like
function parseShow(tableRow) {
var tds = parser('td', tableRow);
//and then go through the tds scraping info...
}
but I get an error:
TypeError: Object #<Object> has no method 'find'
at new module.exports (C:\Users\Morgan\WebstormProjects\agility\node_modules\cheerio\lib\cheerio.js:76:18)
at exports.load.initialize (C:\Users\Morgan\WebstormProjects\agility\node_modules\cheerio\lib\static.js:19:12)
at parseShow (C:\Users\Morgan\WebstormProjects\agility\routes\akc.js:20:15)
Looking at the stack trace, it looks like Cheerio is creating a new one. How am I supposed to pass the Cheerio parser down to the second function? Right now parser is a global var in the file.
I've tried a bunch of random things like these but they don't work either:
var tds = tableRow('td');
var tds = Cheerio('td', tableRow);
What I'm forced to do instead is a bunch of disgusting, fragile code accessing tableRow.children[1], tableRow.children[3], etc... (the HTML has /r/ns all over creation so many of the children are whitespace)
I know what you mean about the $(..). The $ is just a function name. I think it was chosen as it's short and catches the eye.
Used with Cheerio, and more generally JQuery, it is used with css selectors:
var table2 = $('.qs_table[bgcolor="#71828A"]');
The advantage of this is that table2 is now a selector Object and will have a .find() method which can be called.
In Jquery (I'm not so sure about Cheerio), the selector Object is also a collection, so multiple elements can be matched (or none).
The object model in javascript is a lot more dynamic than Java which can lead to much shorter - if more confusing code.
The code to parse table rows:
$('tr[bgcolor="#FFFFFF"]').each(function(i, tablerow) {
var show = tablerow.text();
if (show) // returns a null if something went wrong
showList.push(show);
});
In your code above parser(..) is used rather than $(..). However once, the object has been loaded with the body you can just keep using it:
parser('tr[bgcolor="#FFFFFF"]').each(function(i, tablerow) {
or to just find the rows of the table you want the following:
parser('.qs_table[bgcolor="#71828A"] tr[bgcolor="#FFFFFF"]').each(function(i, tablerow) {
The selector is css so this will find all tr[bgcolor="#FFFFFF"] elements which are children of the .qs_table[bg="#71828A'] element.

cannot get simple appendChild function working

I am testing javascript code on W3schools' site and I cannot get the appendChild function working.
Hope its not a dumb error.
here it is:
<script type="text/javascript">
function append()
{
var node = document.getElementById(“history”);
node.appendChild(document.createTextNode("text"));
}
window.onload = append;
</script>
<div id="history"></div>
You don't have proper double quotes (I don't know what the others are called):
document.getElementById(“history”);
// ^ ^
This throws the error:
Uncaught SyntaxError: Unexpected token ILLEGAL
It works with:
document.getElementById("history");
DEMO
OT: w3schools is not a good resource for learning (http://w3fools.com/). Better have a look at the Mozilla documentation: https://developer.mozilla.org/en/javascript

Categories