scraping a table with node.js doesnt show any result - javascript

I am trying to scrape data from here with Node.js, however, nothing is showing up when I run js file with node.js.
I tried using this code with the Wikipedia table and it worked.
When I am using the same function in the console, I do get the list I need, but it doesn't work in node.
Here is my code:
const request = require("request-promise");
const cheerio = require("cheerio");
async function main() {
const result = await request.get("https://www.electionguide.org/elections/?inst=&cont=&yr=2021");
const $ = cheerio.load(result);
$("#datagrid > tbody > tr > td > a").each((index, element) => {
console.log($(element).text());
});
}
main();

The data table body is filled by the javascript which run after loading the page, So Either you have to use selenium which loads the page first and then after certain timeout period, did the scraping or instead of scraping the data from html, try executing the javascript code in some way.
<script>
$('#datagrid').dataTable({
"aaSorting": [[ 3, "desc" ]],
"sPaginationType": "full_numbers",
"aLengthMenu": [10, 30, 50, 100, 200, 300],
"iDisplayLength": 30,
"bPaginate": true,
"bProcessing": true,
"bServerSide": true,
"sDom": '<"top"lfip>rt<"bottom"ip<"clear">',
"oSearch": {"sSearch": "2021"},
"sAjaxSource": '/ajax/election/',
"aoColumns": [
{ "bSortable": false, "sClass": "my_class",
"mRender": function ( data, type, full ) {
if(data.match(/<img/g))
{
return data;
}
else
{
return '<img src="'+data+'" style="width:30px;">';
}
}},
{ "sClass": "my_class",
"mRender": function ( data, type, full ) {
try {
if(data.match(/href/g))
return data;
} catch (err) {
return ''+data[0]+'';
}
}},
{ "bSortable": false,
"mRender": function ( data, type, full ) {
try {
if(data.match(/href/g))
return data;
} catch (err) {
if(data[0]==null)
{
return 'Referendum';
}
else
{
return ''+data[0]+'';
}
}
}},
{ "asSorting": [ "desc", "asc" ], "sClass": "my_class" },
{ "sClass": "my_class" }
]});
$('.dataTables_filter input').attr("placeholder", "Search Elections...");
</script>

Related

Send jquery datatable column value to Javascript Function (Asp.Net MVC)

I am binding data to jquery datatable in asp.net mvc, i have an anchor tag in one of the columns of the grid where i am accessing / reading row data and sending that data to a javascript function. The problem which i am facing is, i am able read and send row values to the function which are numbers for example ProductID="1" or CategoryID="3" , but if i try to send ProductName="Chai" to the javscript function i get an error in the console, and if i remove the parameter "ProductName" everything works fine and the javascript function also gets triggered.
Following the console error:
"Index:1 Uncaught ReferenceError: Chai is not defined
at HTMLAnchorElement.onclick (Index:1)"
Following is my Code:
var BindDataTable = function (response) {
$("#tbProduct").DataTable({
"aaData": response,
"aoColumns": [
{ "mData": "ProductID" },
{ "mData": "ProductName" },
{ "mData": "SupplierID" },
{ "mData": "SupplierName" },
{ "mData": "SupplierCountry" },
{ "mData": "CategoryID" },
{ "mData": "CategoryName" },
{ "mData": "QuantityPerUnit" },
{ "mData": "UnitPrice" },
{
"render": function (data, type, full, meta) {
return '<i class="glyphicon glyphicon-pencil"></i>'
}
}
],
"columnDefs": [
{
"targets": [2],
"visible": false,
"searchable": false
},
{
"targets": [5],
"visible": false,
"searchable": false
}
],
"aaSorting": []
});
}
var EditProduct = function (ProductID, SuppID, CatID,PrdName) {
var url = "/Product/EditProduct?ProductID=" + ProductID + "&SuppID=" + SuppID + "&CatID=" + CatID;
$("#myModalBodyDiv1").load(url, function () {
$("#myModal1").modal("show");
})
}
Error:
My suggestion is that instead of playing around with that much string concatenations, what you can do is pass single object to your function and then use the required fields which needs to be passed as ajax call:
"render": function (data, type, full, meta) {
return '<i class="glyphicon glyphicon-pencil"></i>'
}
and in your js function use it :
var EditProduct = function (product) {
var url = "/Product/EditProduct?ProductID=" + product.ProductID+ "&SuppID=" + product.SupplierID + "&CatID=" + productCategoryID + "&ProdName=" + product.Prooductname ;
You can use the following approach in for passing string arguments to a JavaScript function:
<a onclick="javaScriptFunction(#p.ID, '#p.FileName');">#p.FileName</a>
function javaScriptFunction(id, fileName) {
...
}

Make edit link on datatable with multiple column values and global search on single/custom column(s)

How to create an edit link with function having multiple parameter from the data columns returned from ajax.
I read about the render callback but it only gets one column value & I need 2.
I need something like the following pseudo code.
"columnDefs": [ {
"targets": [0,1],
"data": "0,1",
"render": function ( data, type, full, meta ) {
return ``
}
} ]
As I'm disabling global search on all column except one. I cannot use the above code that use targets property. I don't know how to achieve this, please guide.
Edit: Complete code
var datatable = $('#datatable').DataTable({
"ajax": "/get_data/",
"processing": true,
"serverSide": true,
"deferRender": true,
"columnDefs": [
{ "searchable": false, "targets": [ 0,2,3,4,5,6,7,8,9,10,11 ] }
]
});
You can access row data using full variable, for example full[0] or full[1].
However instead of generating links in HTML, I would retrieve row data in a click handler as shown below:
$('#example').DataTable({
"columnDefs": [
{
"targets": [0, 1],
"render": function ( data, type, full, meta ) {
return 'Edit';
}
}
],
// ... other options ...
});
$('#example').on('click', '.btn-edit', function(){
// Get row data
var data = $('#example').DataTable().row($(this).closest('tr')).data();
edit(data[0], data[1]);
});
I needed Edit link on first column, so I followed #Gyrocode.com answer and it works great.
I also wanted to use the global search for searching but only on one column. Datatable ColumnDef Documentation gave me the clue so I ended up doing as follows.
Here The complete code:
var datatable = $('#datatable').DataTable({
"ajax": "/get_data/",
"processing": true,
"serverSide": true,
"deferRender": true,
"columnDefs": [
{
"targets": 0,
"render": function ( data, type, full, meta ) {
return 'Edit';
}
},
{ targets: 1, searchable: true },
{ targets: '_all', searchable: false }
]
});

Format currencies when dataTable is created

var oTable = $('#table').dataTable({
"bJQueryUI": true,
"aaData": jsonList,
"bPaginate": true,
"aoColumns": [
{
"mDataProp": null,
"sClass": "control center",
"sDefaultContent": '<img src="http://i.imgur.com/SD7Dz.png">'
},
{ "mDataProp": "ente" },
{ "mDataProp": "cup" },
{ "mDataProp": "decreto" },
{ "mDataProp": "data" },
{ "mDataProp": "importoImpegno" }, //this is a currency
{ "mDataProp": "finanziato" }, //this is a currency
{ "mDataProp": "importoPagato" }, //this is a currency
{ "mDataProp": "importoInPagamento" } //this is a currency
],
"aoColumnDefs": [
{ "sClass": "currency", "aTargets": [ 5, 6, 7, 8 ]}
],
"oLanguage": {
"sInfo": "_TOTAL_ entries"
},
"aaSorting": [[1, 'asc']]
});
As you can see, I add .currency class only to the column where is a currency.
I need to format this currencies (3235 to 3.235,00 for example) and I have already the function to do that.
function currencyFormatIT(num) {
if(num != null && num != "") {
num = parseFloat(num);
num = num
.toFixed(2)
.replace(".", ",")
.replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1.");
}
else {
num = "";
}
return num;
}
I tried to use this method so:
$("table.myTable > tbody td.currency").each(function(){
$(this).html(currencyFormatIT($(this).html()));
$(this).css("text-align", "right");
});
But, it's work only with the row that appears in the first page of datatable:
From the second page to onwards not:
If I add this code:
$(document).on("click", "td.currency", function(){
alert($(this).html());
});
works for all td of all page!!
1) Why?
2) If I want to call the currencyFormatIT() function like callback function (maybe in the code where I create the dataTable .dataTable({.. how could I do?
You can use the fnDrawCallback function.
var oTable = $('#table').dataTable({
"fnDrawCallback": function (oSettings) {
// Format Currency here
}
}
You can check the documentation for more details about possible callback functions.

DataTables plug-in for jQuery changing data set?

I got a JQuery DataTable initialized with an empty dataset like this:
oTable = $('#accountsDefaultList').DataTable({
"bStateSave": true,
"aaData": accountsDefaultList(),
"aoColumns": [
{
"mData": "id",
"mRender": function (data) {
return '<button class="edit"><i class="fa fa-pencil-square-o"></i></button><button class="delete"><i class="fa fa-trash-o"></i></button>';
}
},
{ "mData": "title" }
],
"sDom": "<'dt-toolbar'<'col-xs-12 col-sm-6 hidden-xs'f><'col-sm-6 col-xs-12 hidden-xs'T<'toolbar'C>>r>" +
"Rt" +
"<'dt-toolbar-footer'<'col-sm-6 col-xs-12 hidden-xs'i><'col-xs-12 col-sm-6'p>>",
"autoWidth": false,
"oTableTools": {
"aButtons": [
"copy",
"xls",
{
"sExtends": "print",
"sMessage": "Generated by Procoor <i>(press Esc to close)</i>"
}
],
"sSwfPath": "javaScript/smartAdmin/plugin/datatables/swf/copy_csv_xls_pdf.swf"
},
"fnStateSave": function (oSettings, oData) {
localStorage.setItem('accountsDefaultList', JSON.stringify(oData));
},
"fnStateLoad": function (oSettings) {
return JSON.parse(localStorage.getItem('accountsDefaultList'));
},
"sPaginationType": "full_numbers",
"preDrawCallback": function () {
// Initialize the responsive datatables helper once.
if (!responsiveHelperaccountsDefaultList) {
responsiveHelperaccountsDefaultList = new ResponsiveDatatablesHelper($('#accountsDefaultList'), breakpointDefinition);
}
},
"rowCallback": function (nRow) {
responsiveHelperaccountsDefaultList.createExpandIcon(nRow);
},
"drawCallback": function (oSettings) {
responsiveHelperaccountsDefaultList.respond();
}
});
I use this to update the dataset with the new data but it doesn't seem to work at all
accountsDefaultList.subscribe(function () {
var data = accountsDefaultList();
oTable.data(data);
});
I tested whether the data is returned and every thing is fine except for the dataset update, i saw suggestions like using fnClearTable and fnAddData but those do not even exist in the datatables api.

Get DataTables cell value to use in html link

I thought to be a simple thing, but!
Using DataTables, I would like to have the first column of the table hidden and use that cell data in an HTML image link in the next column cell.
html link using "User_ID", http://somepage.php?UID=data0
I have looked at fnGetData() and mRender and I just confused now.
MY CODE:
"aoColumns": [
{ "mData": "User_ID",
"bVisible": false, "bSearchable": false, "bSortable": false
},
{ "mData": null,
"bSearchable": false, "bSortable": false,
"sClass": "center",
"sDefaultContent": '<img src="images/look.png" width="16">'
},
I always help myself with this trick:
Don't set bVisible to false cause you will not have the data in the row. It's not rendered at all. Use sClass and set display:none. This way the column is invisible to the user, but it is still there.
Then you can use mRender to show a custom cell template:
"aoColumnDefs": [{
"aTargets": [0],
"sClass": "hiddenID"
}, {
"aTargets": [1],
"bSearchable": false,
"bSortable": false,
"sClass": "center",
"mRender": function(data, type, full) {
return 'Click me';
}
}, {
"aTargets": [2],
}, ]
Now the data is there, sortable and filterable.
Look at this Plunker and style.css to understand the concept behind this hack.
You may have a closer look at mData so you can do a callback function and dont have to use the hidden column:
// Using mData as a function to provide different information for
// sorting, filtering and display.
$(document).ready( function() {
var oTable = $('#example').dataTable( {
"aoColumns": [
{ "mData": "User_ID",
"bVisible": true, "bSearchable": false, "bSortable": false
}
],
"aoColumnDefs": [ {
"aTargets": [ 0 ],
"mData": function ( source, type, val ) {
if (type === 'set') {
source.id = val;
// Store the computed dislay and filter values for efficiency
source.id_display = val=="" ? "" : '<img src="images/look.png" width="16">';
source.id_filter = val=="" ? "" : val;
return;
}
else if (type === 'display') {
return source.id_display;
}
else if (type === 'filter') {
return source.id_filter;
}
// 'sort', 'type' and undefined all just use the integer
return source.id;
}
} ]
} );
} );

Categories