Formatting data in with Cheerio - node.js

I want to get the list of IP from a website and add them into an array. The website shows the data like this:
<tbody><tr role="row" class="odd">
<td>131.108.216.44</td>
<td>47267</td>
<td>BR</td>
<td class="hm">Brazil</td>
<td>elite proxy</td>
<td class="hm">no</td>
<td class="hx">yes</td>
<td class="hm">2 minutes ago</td>
</tr>
<tr role="row" class="even">
<td>85.173.165.36</td>
<td>46330</td>
<td>RU</td>
<td class="hm">Russian Federation</td>
<td>elite proxy</td>
<td class="hm">no</td>
<td class="hx">yes</td>
<td class="hm">2 minutes ago</td>
</tr>
</tbody>
This is actually a very long list with 100's of table but the format is the same.
What I did is :
var c = new Crawler({
maxConnections: 1,
callback: function (error, res, done) {
if (error) {
console.log(error)
} else {
var $ = res.$;
$('tbody>tr>td').each((i, el) => {
const item = $(el)
console.log(item.text());
})
}
done();
}
})
c.queue({
uri: 'https://free-proxy-list.net/'
})
I want to keep the first 10 IPs from the website and add them into an array.

The first 10 would look like this:
let proxies = $('tr[role=row]').map((i, tr) => {
let host = $(tr).find('td:nth-child(1)').text()
let port = $(tr).find('td:nth-child(2)').text()
return `${host}:${port}`
}).get().slice(0, 10)

Related

puppeteer pick a date from the calendar by class name if available

what i want: if there is a green date click on it (the first one or the last), if not keep reloading
you can see the calendar image below
note: the green date has always a class name "activeClass" + title="Book"
const rdvLoop = async () => {
await page.waitForTimeout(1000)
await page.reload()
await page.waitForTimeout(1000)
if ((await page.$("td.activeClass")) !== null ){
await page.waitForSelector('td.activeClass:nth-child(1)')
await page.click("td.activeClass:nth-child(1)")
await page.waitForTimeout(1000)
}
if ((await page.$("td.activeClass")) == null ){
await page.waitForTimeout(1000)
await page.reload()
}
}
rdvLoop()
for (var i = 0; i = 10 ;i++) {
await page.waitForTimeout(1000)
await rdvLoop()
}
this is the website calendar (minimalized)
<div class="datepicker datepicker-dropdown dropdown-menu" >
<div class="datepicker-days" >
<table class=" table-condensed">
<tbody>
<tr>
<td class="day disabled fullcap" title="Slots Full">8</td>
<td class="day disabled fullcap" title="Slots Full">9</td>
<td class="active day disabled fullcap" title="Slots Full">10</td>
<td class="disabled day activeClass" title="Book">11</td>
</tbody>
</table>
</div>
</div>
here is the calendar image from the website

Having trouble accessing table elements

I am trying to test my table but I can't seem the access the table headers? I am testing that 6 exist as seen in the logs below.
TestingLibraryElementError: Unable to find an accessible element with the role "th"
Here are the accessible roles:
import { render, screen } from '#testing-library/react'
import '#testing-library/jest-dom'
import Table from "../Table/Table"
describe('Table', () => {
beforeEach(() => {
render(<Table />)
})
it('should render headers', () => {
screen.logTestingPlaygroundURL()
expect(screen.getAllByRole('th')).toHaveLength(6)
})
})
<table class="sc-dkrFOg eudlDK">
<thead class="sc-iBYQkv fBmNxW">
<tr class="sc-hLBbgP imKlCt">
<th class="sc-eDvSVe jtchdi">
ID
</th>
<th class="sc-eDvSVe jtchdi">
NAME
</th>
<th class="sc-eDvSVe jtchdi">
</tr>
</thead>
<tbody class="sc-gKPRtg"/>
</table>
I have tried reading various docs online.
This works. I am accessing via columnheader.
it('shoulda colum with id', () => {
expect(screen.getByRole('columnheader', { name: /id/i })).toBeInTheDocument();
});

Having hard time scraping a cell with Cheerio

I'm trying to scrape a cell from a table but I'm having a hard time and I'm probably doing something wrong because I get an empty result in the console(literally nothing).
Here's the HTML:
I'm trying to get the <td class="center bold storing_1">1</td>.
Here's my code:
const rp = require('request-promise');
const cheerio = require('cheerio');
const url = 'MY URL';
rp(url)
.then(function(html) {
$ = cheerio.load(body);
console.log($('#table_results tbody tr:nth-child(1) td.center.bold.sorting_1')).text();
})
.catch(function(err) {
});
Any help is appreciated! Thanks!
I think your code is actually ok, I think you just have a few typos in it.
You are parsing 'body' rather than 'html'
You are reading .text() from the result of console.log() rather than the cheerio object ($).
If you try the code below it should work:
const rp = require('request-promise');
const cheerio = require('cheerio');
const url = 'MY URL';
rp(url).then(function(html) {
$ = cheerio.load(html);
console.log("Result:", $('#table_results tbody tr:nth-child(1) td.center.bold.sorting_1').text());
})
.catch(function(err) {
console.error("An error occurred:", err);
});
Html I'm testing with:
Test html
<table id="table_results">
<thead></thead>
<tbody>
<tr ajax-controller="community">
<td class="center bold sorting_1">1</td>
<td class="center bold sorting_1">2</td>
</tr>
</tbody>
</table>
Simple test setup:
You can play around with this to see how editing the selector changes things:
const testHtml =
`<table id="table_results">
<thead></thead>
<tbody>
<tr ajax-controller="community">
<td class="center bold sorting_1">1</td>
</tr>
</tbody>
</table>`;
$ = cheerio.load(testHtml);
console.log("Result:", $('#table_results tbody tr:nth-child(1) td.center.bold.sorting_1').text());

MVC 5 get value of DropDownList within a table row

I have a view with a table of products that can be added to a shopping cart. Each row has a DropDownList with allowed quantities that can be ordered along with a button to add to cart. Everything is populating and displaying properly. I know how to pass the item ID in the ActionLink but how can I get the value of the DownDownList associated with the table row of the ActionLink that was clicked?
I am guessing possibly using JQuery that fires when the ActionLink is clicked?
I also thought of making every row a form but that seems overkill.
Is there an easy MVC way to do this?
In prepping more info for a proper question and went ahead and solved it. Thank you Stephen for the nudge and info.
I tried putting a Html.BeginForm around each <tr> tag in the details section. This did indeed work for me. I was able to easily get the unique form info to POST for each individual row. However, when I would enable JQuery DataTables the submit would break. DataTables must be capturing the submit or click somehow. Haven't figured that out but it made me try JQuery which seems a much better way to do it.
Here is how I construct the table data row:
#foreach (var item in Model)
{
<tr>
<td>
<img src="#item.GetFrontImage()" width="100" />
</td>
<td>
<strong>#Html.DisplayFor(modelItem => item.DisplayName)</strong>
</td>
<td>
#Html.DisplayFor(modelItem => item.CustomerSKU)
</td>
<td>
#Html.DropDownList("OrderQty", item.GetAllowedOrderQuantities(), htmlAttributes: new { #class = "form-control" })
</td>
<td>
<a class="btn btn-default pull-right" data-id="#item.ID">Add to Cart</a>
</td>
</tr>
}
This creates a select with id of OrderQty and I embedded the item ID in data-id attribute of the link. I then used this JQuery to capture the info and POST it to my controller. Just have a test div displaying the results in this example:
// Add to Cart click
$('table .btn').click(function () {
// Gather data for post
var dataAddToCard = {
ID: $(this).data('id'), // Get data-id attribute (Item ID)
Quantity: $(this).parent().parent().find('select').val() // Get selected value of dropdown in same row as button that was clicked
}
// POST data to controller
$.ajax({
url: '#Url.Action("AddToCart","Shopping")',
type: 'POST',
data: JSON.stringify(dataAddToCard),
contentType: 'application/json',
success: function (data) { $('#Result').html(data.ID + ' ' + data.Quantity); }
})
});
The JQuery function receives the reference to the link being clicked so I can extract the Item ID from the data-id attribute. I can then get a reference to the dropdown (select) that is in the same row by using .parent.parent (gets me to the <tr> tag) and then just finding the next 'select' tag. Probably pretty obvious to a lot of you.
This works great for my purposes. I can also update other elements with data returned from the POST.
Thank you
Karl
for the table in html:
<div class="table-responsive">
<table id="employeeTable"class="table table-bordered">
<thead>
<tr>
<th class="text-center">ُُُEmpId</th>
<th class="text-center">Name</th>
<th class="text-center">Absense State</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
<td>#item.Id</td>
<td>#item.Name</td>
<td class="text-center">#Html.DropDownList("DDL_AbsentStatus", new SelectList(ViewBag.statusList, "Id", "Name"), new { #class = "form-control text-center" })</td>
</tr>
}
</tbody>
</table>
</div>
in javascript to get the selected value:
//Collect Date For Pass To Controller
$("#btn_save").click(function (e) {
e.preventDefault();
if ($.trim($("#datepicker1").val()) == "") {
alert("ادخل تاريخ يوم صحيح!")
return;
}
var employeesArr = [];
employeesArr.length = 0;
$.each($("#employeeTable tbody tr"), function () {
employeesArr.push({
EmpId: $(this).find('td:eq(0)').html(),
EntryDate: $.trim($("#datepicker1").val()),
StatusId: $(this).find('#DDL_AbsentStatus').val()
});
});
$.ajax({
url: '/Home/SaveAbsentState',
type: "POST",
dataType: "json",
data: JSON.stringify(employeesArr),
contentType: 'application/json; charset=utf-8',
success: function (result) {
alert(result);
emptyItems();
},
error: function (err) {
alert(err.statusText);
}
});
})

How to wrap #Html.DisplayFor() with #Html.ActionLink()

I just need to wrap column into hyperlink. So that a user can click on item of Number Column and can be redirected.
Here is my current View:-
#foreach (var item in Model) {
<tr>
<th>
#Html.ActionLink("Read", "Read", new { id = item.id})
</th>
<td>
#Html.DisplayFor(modelItem => item.Number)
</td>
</tr>
Trying to do something like this. I know its not right but need to know the right way to do it. I am new to MVC
#Html.ActionLink(#Html.DisplayFor(modelItem => item.Number).ToString(), "Read", new { id = item.id })
You can't really, but you can just use Url.Action instead:
<a href="#Url.Action("Read", new { id = item.id })">
#Html.DisplayFor(modelItem => item.Number)
</a>
I don't know if there's a way to do this with ActionLink (I suspect there isn't, at least not in any way I'd want to support in the code.) But you can manually craft an a tag and still keep its URL dynamic by using Url.Action() instead:
<a href="#Url.Action("Read", new { id = item.id })">
#Html.DisplayFor(modelItem => item.Number)
</a>

Resources