Recursive search with Beautiful Soup - recursion

I am trying to extract info from nested html tags:
<div id="container">
<div id="cover_1" class="default"></div>
<div id="container_2">
<div class="blue">
<div id="container_3" class="red">
</div>
However, when I try to inspect the children of container_2 by:
container_2tag = soup.find("div", id = "container_2")
children = container_2tag.findChildren()
the children list is empty and so I cannot dig deeper into the structure. I've looked at the answers explaining the iteration over tree tags using findAll but couldn't find a problem where html nesting is not visible to Beautiful Soup. Could it be a bad parser? (I've got html5lib installed)..

You don't have a tag with the id container_2tag
do
container_2tag = soup.find("div", id = "container_2")
And the children can be found
>>> children = container_2tag.findChildren()
>>> children
[<div class="blue">
<div id="container_3" class="red">
</div>
</div>, <div id="container_3" class="red">
</div>]
>>> children[0]
<div class="blue">
<div id="container_3" class="red">
</div>
</div>
>>> children[1]
<div id="container_3" class="red">
</div>
>>> children[2]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: list index out of range

Related

Selecting text using nth-of-type returns concatenated string

I have the following HTML and I want to select the value "1933".
I tried $('div.mydata dl:nth-of-type(1)').text() but that returns "1933110 m243" where I'd expect "1933". What am I doing wrong?
I checked here already.
console.log($('div.mydata dl:nth-of-type(1)').text());
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="mydata">
<div>
<div class="left">
Year: Lot size: Total: Cars: Motors:
</div>
<div class="right">
<div>
<dl>1933</dl>
</div>
<div>
<dl>110 m<sup>2</sup></dl>
</div>
<div>
N.A.
</div>
<div>
<dl>4</dl>
</div>
<div>
<dl>3</dl>
</div>
</div>
</div>
</div>
The selector: $('div.mydata dl:nth-of-type(1)').text() is essentially selecting the first of every <dl> inside of div.mydata.
If you just want the contents of the first <dl> on the page use:
$($('div.mydata div dl').get(0)).text()

How to put div tag to put all buttons on one line?

Code for Filter Button
import React from "react";
function FilterButton(props){
return (
<div className="box">
<button
type = "submit"
className="button is-info"
onClick={()=>props.setFilter(props.name)}
>
<span>{props.name}</span>
</button>
</div>
);
}
export default FilterButton;
Unfortunately, the div tag is not able to put the following buttons(All, Active, Completed, Important) on the same line.
Is there any solution for this problem?
If you want to use the grid system of BULMA, you can do the following things:
see https://bulma.io/documentation/columns/basics/:
<div class="columns">
<div class="column">
First column
</div>
<div class="column">
Second column
</div>
<div class="column">
Third column
</div>
<div class="column">
Fourth column
</div>
</div>
If you want to use css in order to do this, you can use the css property display: inline-block,as it is shown here:
https://www.w3schools.com/css/css_inline-block.asp

How to display elements inside an arrayList with two CSS style?

I'm writing a code where there's an arrayList having two names in it i.e.Bob & Steve and i want to display them such that if Bob is displayed it should be green in color and if Steve is displayed it should be REd in color.
Component.CSS
.Bob{
font-weight:bold;
color:green;
}
.Steve{
color:red;
}
Component.HTML
<div class="container">
<div class="row" *ngFor="let st of Names;">
<div class="col-2">
<p class="Bob">{{st}}</p>
</div>
<div class="col-2">
<p class="Steve">{{st}}</p>
</div>
</div>
</div>
in Component.Ts
Names:string[]=['Bob','Bob','Steve','Bob','Steve']; in Component.Ts
You can provide class based on condition .
Modify your code like below :
<div class="container">
<div class="row" *ngFor="let st of Names;">
<div class="col-2">
<p [ngClass]="(st=='Bob')?'Bob':'Steve'">{{st}}</p>
</div>
</div>
</div>
Here is the working example :
Working Stackblitz Example
When we have a large number of elements and we can showed it with different background we can adopt several approaches.
Has an array of styles/background and use the index
colors=['red','yellow','green'...]
<div *ngFor="let item of items;let index=i>
<div [style.background-color]="colors[i]">item.data</div>
</div>
The background was a "property" of "items"
items=[{data:...,color:'Red'},{data:...,color:'yellow'},...]
<div *ngFor="let item of items;let index=i>
<div [style.background-color]="item.background">item.data</div>
</div>
We can use
[style.css_property]="value"
//or
[className]="class"
//or
[ngClass]="{'class':condition}"
In your case, Aman, I think that it's better that your "items" has a property "class" that was, e.g.
{data:...,class:'bold-true green-true'}
So, when you want add a item, you can make a function
getClass()
{
let class="";
if (this isBold)
class="isBlod-true";
if (this.isCut)
class=class+" isCut-true";
if (this.isGreen)
class=class+" isGreen-true";
...
return class
}
And when you add an item, you can do
items.push({data:...,class:this.getClass()})
Then the code
<div *ngFor="let item of items;let index=i>
<div [className]="item.class">item.data</div>
</div>
make the trick

Get HTML attributes from loop

I have a list of items:
<div class="item">
<a href="//external-link.com">
<img src="main-image.jpg" alt=""/>
</a>
<h2> Title </h2>
<p> Description lorem here </p>
</div>
<div class="item">
<a href="//external-link.com">
<img src="main-image.jpg" alt=""/>
</a>
<h2> Title </h2>
<p> Description lorem here </p>
</div>
<div class="item">
<a href="//external-link.com">
<img src="main-image.jpg" alt=""/>
</a>
<h2> Title </h2>
<p> Description lorem here </p>
</div>
I want to extract the text of the <h2> tag, and the "src" and "href" of the <a> and <img> tags, but I can't figure out how to extract the "src" and "href" attributes.
This is something like what I'm using:
require 'nokogiri'
require 'open-uri'
pageURL = 'http://ticketdriver.com/amg/buy/tickets'
page = Nokogiri::HTML(open(pageURL), nil, 'UTF-8')
page.css('.item').each do |node|
title = node.css('h2').text
srcUrl = node.css('img')['src']
end
The text part is working but I can't access the key and value for child elements of ".item". I tried children[0], [0]['src'] , [:src], attr(), attribute() and a few more.
I'm completely out of ideas and Google search pages.
I'd do something like:
doc = Nokogiri::HTML(<<EOT)
<html><body>
<div class="item">
<a href="//external-link.com">
<img src="main-image1.jpg" alt=""/>
</a>
<h2> Title1 </h2>
</div>
<div class="item">
<a href="//external-link.com">
<img src="main-image2.jpg" alt=""/>
</a>
<h2> Title2 </h2>
</div>
<div class="item">
<a href="//external-link.com">
<img src="main-image3.jpg" alt=""/>
</a>
<h2> Title3 </h2>
</div>
</body></html>
EOT
items = doc.search('.item').map { |item|
{
title: item.at('h2').text,
src: item.at('img')['src']
}
}
Which results in:
items
# => [{:title=>" Title1 ", :src=>"main-image1.jpg"},
# {:title=>" Title2 ", :src=>"main-image2.jpg"},
# {:title=>" Title3 ", :src=>"main-image3.jpg"}]
I'm deliberately only getting the "src" attribute from the <img> tag. Given the code above you can figure out how to get what you want from the <a> tags.
Notice that I'm using the generic search rather than css. Nokogiri is smart enough to differentiate between CSS and XPath selectors most of the time. The only time I use either css or xpath is when Nokogiri can't figure it out. I use CSS because it's generally simpler and more easily read.
Also, notice that I don't use node.css('h2').text. css returns a NodeSet, which is akin to an Array, whereas at returns a single Node. In your code you're masking the difference between the two, but using css, xpath or the generic search is a bug in waiting. Consider this:
require 'nokogiri'
doc = Nokogiri::HTML(<<EOT)
<html><body>
<p>foo</p>
<p>bar</p>
<p>baz</p>
</body></html>
EOT
doc.search('p').text # => "foobarbaz"
doc.at('p').text # => "foo"
What this means is, if search or one of its specific methods returns a NodeSet, text will return the text of all Nodes in that set, which is rarely what you want. Instead, you need to use at to find the specific child-node you want and then extract its text. How you do that is a different question, but it's easily done.

Find the biggest height of a div in ng-repeat

I have a set of data which is an array of objects. Some objects have more data than the other. But each object will display in each col-md-4 div. Therefore, the height of each div will be different based on how much data an object has.
Here is my code:
<div class="col-md-12 eventlog-info-container">
<div class="row eventlogs-single-container">
<div class="col-md-4 eventlog-1-container" ng-repeat="record in records track by $index">
<h4>Event Log {{$index}}</h4>
<ul>
<li ng-repeat="(key, value) in record">{{::key}}: {{::value}}</li>
</ul>
</div>
</div>
</div>
My question is after ng-repeat, I want to find the biggest height of the element. And then apply the biggest height to each of the element using ng-style.
I have an idea to approach that using JQuery. However, I want to use Angular to do that? Any suggestion? Anuglar is not good for DOM manipulation?
Thank you in advanced.
After I did some research yesterday. I found an open source angular directive to solve my problem - angularJS Vertilize Directive An AngularJS directive to vertically equalize a group of elements with varying heights. In other words, it dynamically makes a group of elements the same height. Thank you Chris Collins who made this directive.
<div vertilize-container class="row">
<div ng-repeat="col in columns" class="col-sm-3">
<div class="well">
<div vertilize>
<h3>{{ col.title }}</h3>
<p>{{ col.body }}</p>
</div>
</div>
</div>
</div>
This answer should get you started on the right path.
<div class="col-md-12 eventlog-info-container">
<div class="row eventlogs-single-container">
<div class="col-md-4 eventlog-1-container" ng-repeat="record in records track by $index">
<h4>Event Log {{$index}}</h4>
<ul>
<li outer-height ng-repeat="(key, value) in record">{{::key}}: {{::value}}</li>
</ul>
</div>
</div>
</div>
app.directive('outerHeight', function(){
return{
restrict:'A',
link: function(scope, element){
//using outerHeight() assumes you have jQuery
// if not using jQuery
console.log(element.outerHeight());
}
};
});

Resources