I need some help in Ruby/Selenium
i have a few elements on page like this:
<a class="Name" title="Migel" href="/profiles/users/_1324567980000000c/">Migel</a>
i'd like give HREF string value into array.
when i use "find_element" - ALL OK:
profile = driver.find_element(:xpath, "****").attribute ('href')
but page contains a lot of such elements, and i try to use
profile_array = driver.find_elements(:xpath, "lbuh-bluh").attribute ('href')
naturally that attribute ('href') dont work with array.
how can I do in this case?
in general, my task in implementing "random click" on page and i want collect all "href" elements which i need into array, and then realize something like this:
array[srtring1, string2....stringN].sample.click (schematically)
would just mapping over elements and get href attribute be sufficient?
profile_array = driver
.find_elements(:xpath, "lbuh-bluh")
.map { |el| el.attribute('href') }
I see that this is some sort of parsing html with Ruby, if this is the case why dont you use the Nokogiri gem, lets say you have something like:
<div id="funstuff">
<p>Here are some entertaining links:</p>
<ul>
<li>YouTube</li>
<li><a data-category="news" href="http://reddit.com">Reddit</a></li>
<li>Kathack</li>
<li><a data-category="news" href="http://www.nytimes.com">New York Times</a></li>
</ul>
</div>
Which is the content of a file called lets say: selenium.html located at your Desktop: C:\Desktop\selenium.html
here is the ruby code that handels that:
page = Nokogiri::HTML(open("C:\Desktop\selenium.html"))
links = page.css("a")
profile_array = []
links.each{|ref| profile_array << ref["href"] }
puts profile_array
=>http://youtube.com
=>http://reddit.com
=>http://kathack.com/
=>http://www.nytimes.com
Related
I'm looking to purify HTML with the HtmlPurifier package and add attributes to certain elements. Specifically, I'd like to add classes to <div> and <p> elements so that this:
<div>
<p>
Hello
</p>
</div>
Gets purified/transformed into this:
<div class="div-class">
<p class="p-class">
Hello
</p>
</div>
How would one go about doing this with HtmlPurifier? Is it possible?
I believe you could do this by doing something along these lines (though please treat this as pseudocode, the last time this scenario worked for me was years ago):
class HTMLPurifier_AttrTransform_DivClass extends HTMLPurifier_AttrTransform
{
public function transform($attr, $config, $context) {
$attr['class'] = 'div-class';
return $attr;
}
}
class HTMLPurifier_AttrTransform_ParaClass extends HTMLPurifier_AttrTransform
{
public function transform($attr, $config, $context) {
$attr['class'] = 'p-class';
return $attr;
}
}
$htmlDef = $this->configuration->getHTMLDefinition(true);
$div = $htmlDef->addBlankElement('div');
$div->attr_transform_post[] = new HTMLPurifier_AttrTransform_DivClass();
$para = $htmlDef->addBlankElement('p');
$para->attr_transform_post[] = new HTMLPurifier_AttrTransform_ParaClass();
Remember to allowlist the class attribute for div and p as well, if you haven't already.
That said, at first glance, HTML Purifier doesn't seem to be the right place for this kind of logic, since adding class names isn't relevant for the security of your site (or is it?). If you're already using HTML Purifier to allowlist your HTML tags, attributes and values, and just want to leverage its HTML-parsing capabilities for some light-weight additional DOM manipulation, I see no particular reason not to. :) But it might be worth reflecting on whether you want to add the classes using some other process (e.g. in the frontend, if that's relevant for your use case).
I have quite a weird problem.
There's a website that has the following two buttons (I can see them when I inspect the page):
button 1
<ul class=" _3dEhb">
<li class = " LH76I">
<a class="-na14 _81NM2" href="/preview/">
<span class="g47FY 10XF41"</span>" preview"
<li class = " LH76I">
<a class="-na14 _81NM2" href="/launch/">
<span class="g47FY 10XF41"</span>" launch"
I'm using the python selenium code
buttons = driver.find_element_by_class_name('LH76I')
if I run it without inspecting the webpage, this code gives me an empty list.
However, if I debug and I inspect the webpage, the same code gives me 2 items in the list.
What am I doing wrong?
Thanks
You should use driver.find_elements_by_class_name instead because you are trying to get a list of elements with same identifier. Try the following code:
buttons = driver.find_elements_by_class_name('LH76I')
Then, if you want to click or something, you would do:
buttons[0].click()
EDIT - You can try the way the list items are generally extracted:
main_list = driver.find_element_by_class_name('_3dEhb') //gets the main ul element
List<WebElement> list_items = main_list.findElements(By.tagName("li"));
for x in range(0, len(list_items)):
{
// whatever you want to do with the item
}
I'm working at a project written in Ionic/Angular/Typescript. In the .html file, I have
< p> {{stringVar}} </p>
In the .ts file,I have
this.stringVar= "Visit http://www.google.com.
Visit http://www.stackoverflow.com."
I have 2 questions:
1) I want the 2 sentences in the string to be displayed in html on different lines. What should I do in order to achieve this: add \n or < br> or something like this?
2) I want the 2 links in the string to appear as links in html,too. That is,when the user clicks on them,he will be taken to those sites.
Thanks in advance!
1) To appear in different lines, you must put each one inside their own <p> tag, like this:
<p>first line</p>
<p>second line</p>
2) To appear as clickable links, you need to put in <a> tags, with url in href attribute, like this:
<p>click here to visit google.</p>
It would be better if you could change the structure of your data, to something like this:
<p ng-repeat="url in urlList">Visit {{url}}</p>
this.urlList = [
"http://www.google.com",
"http://www.stackoverflow.com"
];
or even better:
<p ng-repeat="site in siteList">Visit {{site.name}}</p>
this.siteList= [
{ name: "Google", url: "http://www.google.com" },
{ name: "StackOverflow", url: "http://www.stackoverflow.com" }
];
The best approach to go with a 'list', rather than a stringVar
this.linkList = [
"http://www.google.com",
"http://www.stackoverflow.com"
];
1) I would suggest to have <p></p> instead of <br/> in between.
2) The following is a working sample with Angular2
<p *ngFor="let link of linkList">Visit {{link}}</p>
Check the working sample here : https://embed.plnkr.co/Om3CXpT9xN07YCz2aHQr/
Both Question has one answer you Basically want to Interpolate string with html in the angular, although i am not expert in angular1.x but yes there is one service used for the same called as
$interpolate(templateString)(you_.ts/js_code);
by using this you can show your string as it as on the webpage event using html in you javascript file too. you just have to pass the html in your string ans display it in the webpage
for example lets assume your use case you simple have to add this like :-
this.stringVar= "Visit <a href='http://www.google.com'>Google</a> Here and<br> Visit <a href='http://www.stackoverflow.com'>Stackoverflow</a> Here."
and than convert this using interpolate like this
$scope.your_string = $interpolate(templateString)(stringVar);
Working Example for the same
I'm creating an application to manage restaurant orders.
I create the menu from $http so I've this list:
<div class="row vertical" style="background-image: url(/gest/images/etichette/ANTIPASTI.png);border-color: #0CF">
<div class="card piatti col s2" ng-repeat="anti in antis | filter:{tipo:'ANTIPASTI'}">
<div class="card-content"> <span class="card-title truncate red darken-3">{{anti.piatto}}</span> </div>
<div class="card-action"> {{n}}</div>
</div>
</div>
The div with class "row vertical" contain one time starters, then pasta, then beef ecc.
So I use ng-repeat each time, and filter by tipo.
My question is: is there any way to make ng-repeat only one time to show all menu (orderer before by starters, then pasta, beef ecc)?
I have this data (is a restaurant menu):
piatto: name of the the dish
tipo: category of the dish (like pasta, beef, fish, starters ecc)
I would show with only one repeat all the dishes ordered so:
starters, pasta, beef, fish, dessert etc.
And I would create each time a new row
From what I understand you already have all your date on the antis and you just want to filter it by type or do you want to OrderIt by a certain type?
This fiddle for example would order by name, but you can also provide an array with functions to retrieve each type in the way that you like, you can read about it here.
But basically you'd do
anti in antis | orderBy:'+tipo'
or
anti in antis | orderBy: [ function(){}, function(){} ]
EDIT:
As #yarons mentioned you can also chain strings to filter even further. I've updated the Fiddle so now the filter would be anti in antis | orderBy:['+tipo', '+piato']" which indicates that first the tipo would be alphabetically ordered ascending (+ indication) and after that the piato would also be alphabetically ascending.
If you'd want to define a different order than the alphabetical one I think you can use a sort of ENUM for the tipo as in:
var tipoENUM = {};
tipoENUM['ANIPASTI'] = 0;
tipoENUM['PASTA'] = 1;
tipoENUM['PIZZA'] = 2;
tipoENUM['BEEF'] = 3;
tipoENUM['DESERT'] = 4;
So that way you'd avoid using the string for the order, see following fiddle for the example.
EDIT 2:
Ok, so if you receive the data via the HTTP request it's better if you create a order function to help you, check this updated fiddle, like so:
// The enum would be defined as before but:
$scope.orderTipo = function (dish) {
return tipoENUM[dish.tipo];
}
On the HTMl you'll do:
ng-repeat="anti in antis | orderBy:[orderTipo, '+piato']"
Ok your example is perfect but I would repeat each time the "tipo" and then the relative "piato" in a list....something like this:
ANTIPASTI
- bruschetta
- suppli
- fritto
PRIMI
- caqrbonara
- amatriciana
etc.
Is it possible?
I know that we can easily use ng-repeat for json objects or arrays like:
<div ng-repeat="user in users"></div>
but how can we use the ng-repeat for dictionaries, for example:
var users = null;
users["182982"] = "{...json-object...}";
users["198784"] = "{...json-object...}";
users["119827"] = "{...json-object...}";
I want to use that with users dictionary:
<div ng-repeat="user in users"></div>
Is it possible?. If yes, how can I do it in AngularJs?
Example for my question:
In C# we define dictionaries like:
Dictionary<key,value> dict = new Dictionary<key,value>();
//and then we can search for values, without knowing the keys
foreach(var val in dict.Values)
{
}
Is there a build-in function that returns the values from a dictionary like in c#?
You can use
<li ng-repeat="(name, age) in items">{{name}}: {{age}}</li>
See ngRepeat documentation. Example: http://jsfiddle.net/WRtqV/1/
I would also like to mention a new functionality of AngularJS ng-repeat, namely, special repeat start and end points. That functionality was added in order to repeat a series of HTML elements instead of just a single parent HTML element.
In order to use repeater start and end points you have to define them by using ng-repeat-start and ng-repeat-end directives respectively.
The ng-repeat-start directive works very similar to ng-repeat directive. The difference is that is will repeat all the HTML elements (including the tag it's defined on) up to the ending HTML tag where ng-repeat-end is placed (including the tag with ng-repeat-end).
Sample code (from a controller):
// ...
$scope.users = {};
$scope.users["182982"] = {name:"John", age: 30};
$scope.users["198784"] = {name:"Antonio", age: 32};
$scope.users["119827"] = {name:"Stephan", age: 18};
// ...
Sample HTML template:
<div ng-repeat-start="(id, user) in users">
==== User details ====
</div>
<div>
<span>{{$index+1}}. </span>
<strong>{{id}} </strong>
<span class="name">{{user.name}} </span>
<span class="age">({{user.age}})</span>
</div>
<div ng-if="!$first">
<img src="/some_image.jpg" alt="some img" title="some img" />
</div>
<div ng-repeat-end>
======================
</div>
Output would look similar to the following (depending on HTML styling):
==== User details ====
1. 119827 Stephan (18)
======================
==== User details ====
2. 182982 John (30)
[sample image goes here]
======================
==== User details ====
3. 198784 Antonio (32)
[sample image goes here]
======================
As you can see, ng-repeat-start repeats all HTML elements (including the element with ng-repeat-start). All ng-repeat special properties (in this case $first and $index) also work as expected.
JavaScript developers tend to refer to the above data-structure as either an object or hash instead of a Dictionary.
Your syntax above is wrong as you are initializing the users object as null. I presume this is a typo, as the code should read:
// Initialize users as a new hash.
var users = {};
users["182982"] = "...";
To retrieve all the values from a hash, you need to iterate over it using a for loop:
function getValues (hash) {
var values = [];
for (var key in hash) {
// Ensure that the `key` is actually a member of the hash and not
// a member of the `prototype`.
// see: http://javascript.crockford.com/code.html#for%20statement
if (hash.hasOwnProperty(key)) {
values.push(key);
}
}
return values;
};
If you plan on doing a lot of work with data-structures in JavaScript then the underscore.js library is definitely worth a look. Underscore comes with a values method which will perform the above task for you:
var values = _.values(users);
I don't use Angular myself, but I'm pretty sure there will be a convenience method build in for iterating over a hash's values (ah, there we go, Artem Andreev provides the answer above :))
In Angular 7, the following simple example would work (assuming dictionary is in a variable called d):
my.component.ts:
keys: string[] = []; // declaration of class member 'keys'
// component code ...
this.keys = Object.keys(d);
my.component.html: (will display list of key:value pairs)
<ul *ngFor="let key of keys">
{{key}}: {{d[key]}}
</ul>