Finding one element by XPATH using another element - html

I have a website from which I want to extract values using XPATH. These values are changable but generally they are in same repeated node trees (there are hundreds of same structurally node trees with this one changeable value). This is example of one of these tree:
<div style="position: absolute; left: 0px; top: 178px; height: 89px; width: 100%;">
<a class="css-18rtd1e" href="/offers/appunite-backend-developer-elixir">
<div class="css-ysfq6d"></div>
<div class="css-1anw03b"><img src="https://bucket.justjoin.it/offers/company_logos/thumb/22f3ad736e1bc02190ff8beb9d4c55a4de297104.png?1572275788" alt="AppUnite" class="css-h8h6qh"></div>
<div class="css-rmb95w">
<div class="css-fxb39h">
<div class="css-18hez3m">
<div class="css-1x9zltl">Elixir Developer</div>
<div class="css-1suuexb"><span class="css-5fhp0m">Online<br>interview</span></div>
</div>
<div class="css-16tql6o">
<span class="css-112rr0w">7 000 - 11 000 PLN </span>
<div class="css-hw5uoy">New</div>
</div>
</div>
<div class="css-m6o8yl">
<div class="css-pdwro7">
<div class="css-ajz12e">
<svg class="MuiSvgIcon-root" focusable="false" viewBox="0 0 24 24" aria-hidden="true">
<path d="M12 7V3H2v18h20V7H12zM6 19H4v-2h2v2zm0-4H4v-2h2v2zm0-4H4V9h2v2zm0-4H4V5h2v2zm4 12H8v-2h2v2zm0-4H8v-2h2v2zm0-4H8V9h2v2zm0-4H8V5h2v2zm10 12h-8v-2h2v-2h-2v-2h2v-2h-2V9h8v10zm-2-8h-2v2h2v-2zm0 4h-2v2h2v-2z"></path>
</svg>
AppUnite
</div>
<div class="css-1ihx907">
<svg class="MuiSvgIcon-root" focusable="false" viewBox="0 0 24 24" aria-hidden="true">
<path d="M12 2C8.13 2 5 5.13 5 9c0 4.17 4.42 9.92 6.24 12.11.4.48 1.13.48 1.53 0C14.58 18.92 19 13.17 19 9c0-3.87-3.13-7-7-7zm0 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z"></path>
</svg>
Poznań
</div>
<span class="css-5fhp0m">Online interview</span>
</div>
<div class="css-1ij7669">
<div class="tag css-1g8us6r">Phoenix</div>
<div class="tag css-1g8us6r">Elixir</div>
<div class="tag css-1g8us6r">Web Applications</div>
</div>
</div>
</div>
</a>
</div>
I want to extract word AppUnite and it would be simple task but there is one condition to be met: I need to use in my XPATH element containing text from "css-1x9zltl" class (in this case it would be word Elixir Developer). In other words I want to get access to AppUnite using extracted word from "css-1x9zltl" class. So beginning is simple: //div[contains(#class, "css-1x9zltl") and text()="Elixir Developer"] but what next?

You want to get the names of the hiring companies.
Since the names of the #class attributes are fixed (css-1x9zltl,css-ajz12e) on JJI website, you can use :
//div[contains(#class,"css-1x9zltl")][contains(.,"Elixir Developer")]/following::div[#class="css-ajz12e"][1]/text()
Note this will select "Elixir Developer", "Senior Elixir Developer" offers. To be more strict, remove the second contains :
//div[contains(#class,"css-1x9zltl")][.="Elixir Developer"]/following::div[#class="css-ajz12e"][1]/text()

If I understand you correctly, in the case of the sample in your question, an xpath expression like this may do the trick:
//div[contains(#class, "css-1x9zltl")]["Elixir Developer"]/ancestor::div[#class="css-fxb39h"][1]/following-sibling::div [#class="css-m6o8yl"]//div[#class="css-ajz12e"]/text()
This expression basically locates the <div> node meeting your class and text conditions, goes up to the first ancestor which is a sibling of the <div> node in which the target text is buried, then goes down to the <div>child node (of that sibling) which contains the target text, and finally selects the text node of that child node.

Related

Get second CSS selector selenium vba

I am trying to inspect an element and I have used css selector
Here's the HTML
<div class="MuiPaper-root MuiPaper-elevation0 jss325 MuiPaper-rounded">
<div class="MuiPaper-root MuiPaper-elevation1 jss329 MuiPaper-rounded" style="text-align: right;">
<div class="MuiGrid-root MuiGrid-container">
<div class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-2" style="margin-top: 14px; padding-right: 10px;"><svg class="MuiSvgIcon-root" focusable="false" viewBox="0 0 24 24" aria-hidden="true" role="presentation" style="cursor: pointer;"><path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z"></path></svg></div>
<div
class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-9" style="margin-top: 10px;"><span class="MuiTypography-root jss330 MuiTypography-body1">الرقم الآلي للوحدة 10670235</span><br><span class="MuiTypography-root jss331 MuiTypography-body1">العديلية - قطعة 3 - شارع عيسى عبد الرحمن العسعوسي - قسيمة 129 - منزل 19 - الدور الأرضي - الرقم الآلي للوحدة 10670235</span></div>
</div>
<hr class="MuiDivider-root" style="margin-right: 30px; margin-left: 30px;">
</div>
</div>
I have tried the following css selector span.MuiTypography-root but I found multiple instances. How can I get the desired one only?
The desired text is after the element MuiTypography-root jss331 MuiTypography-body1
I can't use this jss331 as this is created dynamically
You can add more specifiers by just chaining:
span.MuiTypography-root.jss331
This will get any span with classes MuiTypography-root and jss331.
You can chain more as needed.
PS: you can test out selectors by hitting ctrl + f while inspecting the elements. You can type in text to find, CSS selectors, and XPath if I remember correctly
Edit: if a class is dynamic then we have to go by what we know is consistent. If we can assume it will always be the last-child then you can use span.MuiTypography-root:last-child
Or if it's always the third child then span.MuiTypography-root:nth-child(3)
Or (if it's always the second span with the MuiTypography-root class) in whatever app you're using selenium, you can use the find_elements_by_css_selector method, which returns an array, and access the second element found.
So you want to inspect this one MuiTypography-root jss331 MuiTypography-body1
Did you tried this:-
span.MuiTypography-root:last-child{
border: 1px solid;
background-color: gold;
}

Why XPath is selecting node with svg child when using not(svg)

I'm new to XPath and trying out a few different things, but there's this one query that really doesn't make sense to me.
I want to select all span nodes that don't contain an svg child node, like this:
To me, adding [not(svg)] should stop the query from selecting the exact element that it is selecting, is this some weird behavior or am I being stupid? The XPath query I'm using is:
//div/a/span[not(svg)]
Thanks!
Edit:
The full XPath to the svg node is:
/html/body/div[1]/div[2]/div/div[1]/div[2]/div[1]/div[1]/a/span[1]/svg
And a snippet of the code:
<!DOCTYPE html>
<!-- saved from url=(0019)https://medium.com/ -->
<html xmlns:cc="http://creativecommons.org/ns#" class="">
<head prefix="og: http://ogp.me/ns# fb: http://ogp.me/ns/fb# medium-com: http://ogp.me/ns/fb/medium-com#"></head>
<body itemscope="" class="browser-chrome os-windows is-withMagicUnderlines v-glyph v-glyph--m2 is-js is-resizing" data-action-scope="_actionscope_0" data-gr-c-s-loaded="true">
<div class="site-main surface-container" id="container">
<div class="butterBar butterBar--error" data-action-scope="_actionscope_1"></div>
<div class="surface" id="_obv.shell._surface_1600536527994" style="display: block; visibility: visible;">
<div class="screenContent surface-content" data-used="true" data-action-scope="_actionscope_2">
<div class="metabar u-clearfix js-metabar is-withBottomSection metabar--affixed is-transitioning is-maximized">
<div class="branch-journeys-top"></div>
<div class="js-metabarMiddle metabar-inner u-marginAuto u-maxWidth1032 u-flexCenter u-justifyContentSpaceBetween u-height65 u-xs-height56 u-paddingHorizontal20">
<div class="metabar-block u-flex1 u-flexCenter">
<div class="u-xs-show js-metabarLogoLeft"><span class="svgIcon svgIcon--logoMonogram svgIcon--45px"><svg class="svgIcon-use" width="45" height="45"><path d="M5 40V5h35v35H5zm8.56-12.627c0 .555-.027.687-.318 1.03l-2.457 2.985v.396h6.974v-.396l-2.456-2.985c-.291-.343-.344-.502-.344-1.03V18.42l6.127 13.364h.714l5.256-13.364v10.644c0 .29 0 .342-.185.528l-1.848 1.796v.396h9.19v-.396l-1.822-1.796c-.184-.186-.21-.238-.21-.528V15.937c0-.291.026-.344.21-.528l1.823-1.797v-.396h-6.471l-4.622 11.542-5.203-11.542h-6.79v.396l2.14 2.64c.239.292.291.37.291.768v10.353z"></path></svg></span><span class="u-textScreenReader">Homepage</span></div>
<div class="u-xs-hide js-metabarLogoLeft"><span class="svgIcon svgIcon--logoWordmark svgIcon--112x22px u-xs-hide u-flex"><svg class="svgIcon-use" height="22" width="112" viewBox="0 0 111.5 22"><path d="3-.7V7.3c0-.5 0-1.2.1-1.8L11.4 22h-.1L4.5 6.8c-.1-.4-.2-.4-.3-.6v10c-.1.7 0 1.3.3 1.9l2.7 3.6v.1H0v-.1L2.7 18c.3-.6.4-1.3.3-1.9v-11c0-.5-.1-1.1-.5-1.5L.7 1.1V1h7l5.8 12.9L18.6 1h6.8v.1l-1.9 2.2c-.2.2-.3.5-.3.7v15.2c0 .2.1.5.3.6zm7.6-5.9c0 3.8 1.9 5.3 4.2 5.3 1.9.1 3.6-1 4.4-2.7h.1c-.8 3.7-3.1 5.5-6.5 5.5-3.7 0-7.2-2.2-7.2-7.4 0-5.5 3.5-7.6 7.3-7.6 3.1 0 6.4 1.5 6.4 6.2v.8h-8.7zm0-.8h4.3v-.8c0-3.9-.8-4.9-2-4.9-1.4.1-2.3 1.6-2.3 5.7z"></path></svg></span><span class="svgIcon svgIcon--logoWordmark svgIcon--122x45px u-xs-show u-flex"><svg class="svgIcon-use" width="122" height="45"><path d="0 00-.487-1.602l-2.089-2.708v-.065h7.494l6.277 13.686 5.527-13.686h7.335v.065l-2.061 2.296a.806.806 0 00-.319.786v16.15a.75.75 0 00.319.759zm8.215-6.332v.065c0 4.01 2.07 5.62 4.497 5.62a5.105 5.105 0 004.777-2.894h.066c-.844 3.963-3.298 5.836-6.97 5.836-3.962 0-7.7-2.389-7.7-7.925 0-5.817 3.747-8.14 7.887-8.14 3.335 0 6.886 1.573 6.886 6.632v.806h-9.443zm0-.806h4.618v-.815c0-4.122-.852-5.218-2.136-5.218-1.555 0-2.5 1.64-2.5 6.033h.018z"></path></svg></span><span class="u-textScreenReader">Homepage</span></div>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
Additionally, the XPath to the top div element of the code snippet above is:
/html/body/div[1]/div[2]/div/div[1]/div[2]/div[1]/div[1]
For anyone who stumbles across this, the issue was due to SVG and HTML namespace differences, which are covered in the answers included in MichealKay's comments.
To select the SVG element, I had to write:
//span/*[name()="svg"]

Is there any way to use the same code multiple times in HTML (Code Reusability)?

I am making 'Projects' Page for my Portfolio website, I am adding a SVG Icon before the every Project's name. Since the code for SVG Icon is very large, I want something which can do something similar to what functions do in programming languages but I don't know how to do it.
Here's a part of my code:
<section>
<div class="container">
<div class="row">
<div>
<h5 class="card-title">
<svg role="img" viewBox="0 0 20 20" height="20px" width="20px">
<path fill="#000000" d="M4 9H3V8h1v1zm0-3H3v1h1V6zm0-2H3v1h1V4zm0-2H3v1h1V2zm8-1v12c0 .55-.45 1-1 1H6v2l-1.5-1.5L3 16v-2H1c-.55 0-1-.45-1-1V1c0-.55.45-1 1-1h10c.55 0 1 .45 1 1zm-1 10H1v2h2v-1h3v1h5v-2zm0-10H2v9h9V1z">
</path>
</svg>
</h5>
<!-- More Stuff here -->
</div>
<div>
<h5 class="card-title">
<svg role="img" viewBox="0 0 20 20" height="20px" width="20px">
<path fill="#000000" d="M4 9H3V8h1v1zm0-3H3v1h1V6zm0-2H3v1h1V4zm0-2H3v1h1V2zm8-1v12c0 .55-.45 1-1 1H6v2l-1.5-1.5L3 16v-2H1c-.55 0-1-.45-1-1V1c0-.55.45-1 1-1h10c.55 0 1 .45 1 1zm-1 10H1v2h2v-1h3v1h5v-2zm0-10H2v9h9V1z">
</path>
</svg>
</h5>
<!-- More Stuff here -->
</div>
</div>
</div>
</section>
This snippet contains two SVG icons but there are lot more icons in the page (having larger code) which are used multiple times. So, it is inefficient to write the same code multiple times. It would be nice if we have to write code only once and then it can be used anywhere in the whole HTML file.
I've seen a few answers but they are using JQuery, Php etc. I am wondering if this can be done using HTML/CSS/Bootstrap only.
If not, then Is it possible to do it with JavaScript (I am a beginner in JS).
In case you need to check the whole code: https://devansh-07.github.io/projects.html
I'd completely remove svg files from your html (it's semantic drag) so I'd define one class with and then auto prepend it to h5 or that class, see demo below
CSS native purpose was just that: define it once - reuse x times! but people tend to forget it this days because of plethora of frameworks and what not ..
.card-title::before{
content: "";
display: inline-block;
width: 20px;
height: 20px;
background-image: url("data:image/svg+xml, %3Csvg xmlns='http://www.w3.org/2000/svg' role='img' viewBox='0 0 20 20' height='20px' width='20px'%3E%3Cpath fill='%23000000' d='M4 9H3V8h1v1zm0-3H3v1h1V6zm0-2H3v1h1V4zm0-2H3v1h1V2zm8-1v12c0 .55-.45 1-1 1H6v2l-1.5-1.5L3 16v-2H1c-.55 0-1-.45-1-1V1c0-.55.45-1 1-1h10c.55 0 1 .45 1 1zm-1 10H1v2h2v-1h3v1h5v-2zm0-10H2v9h9V1z'%3E%3C/path%3E%3C/svg%3E");
}
<section>
<div class="container">
<div class="row">
<div>
<h5 class="card-title">
Title 1
</h5>
<!-- More Stuff here -->
</div>
<div>
<h5 class="card-title">
Title 2
</h5>
<!-- More Stuff here -->
</div>
</div>
</div>
</section>
I've converted your svg with help of this great and free SVG > CSS online converter - give it a try here if needed for other tasks
https://yoksel.github.io/url-encoder/
you are welcome :)
You can use this snippet. Insert it before the </body> tag in your document. Than you can remove the svg from your original markup.
<script>
document.addEventListener('DOMContentLoaded', function(){
var titles = document.querySelectorAll('.card-title');
for (i=0;i<titles.length;i++) {
var span = document.createElement('span');
span.innerHTML = '<svg role="img" viewBox="0 0 20 20" height="20px" width="20px"><path fill="#ffffff" d="M4 9H3V8h1v1zm0-3H3v1h1V6zm0-2H3v1h1V4zm0-2H3v1h1V2zm8-1v12c0 .55-.45 1-1 1H6v2l-1.5-1.5L3 16v-2H1c-.55 0-1-.45-1-1V1c0-.55.45-1 1-1h10c.55 0 1 .45 1 1zm-1 10H1v2h2v-1h3v1h5v-2zm0-10H2v9h9V1z"></path></svg>';
titles[i].prepend(span);
}
})
</script>
You can use Blade Templates with Laravel, also Twig Templates with Symfony, and you can also doing this in Django. If you have a MVC framework, there is a way to use views in all controller. Like CodeIgniter 3 calling with $this->view('route..', $data);. Then you can pass to all of them variables with the svg large code, and printing in the template.
In Laravel Blade is like this:
#include('route/viewname', ['svgcode' => '...'])
In Symfony Twig is like this:
{% include 'route/viewname.twig'
with {'svgcode': '...'} %}
In PHP without framework:
<?php
$svgcode = '...';
include 'route/viewname.php';
?>
In CodeIgniter 3:
$data['svgcode'] = '...'
$this->view('route/viewname', $data);
In Django:
{% include "route/viewname.html" with svgcode = "..." %}

Angular JS assistance with adding values and decimals

Im working wiht some home automation tools which displays energy usage using some widgets created but others smarter than I.
I can get this to work, it will display usage in KW however its incorrect.
The same of the watts should be portion of a KW
Can anyone point me in the direction of resolving this so it shows 0.XX please
<div class="widget">
<div class="icon off">
<svg viewBox="0 0 48 48">
<use xlink:href="/static/matrix-theme/squidink.svg#thunder-1">
</use>
</svg>
</div>
<div class="name">Power</div>
<div class="valueGroup">
<div class="value">
{{itemValue('LivingRoomNum2')*1 + itemValue('KitchenNum2') | number:2}} kW
</div>
<div class="value">
{{itemValue('LivingRoomNum1')}} W (Living)
</div>
<div class="value">
{{itemValue('KitchenNum1')}} W (Kitchen)
</div>
</div>
</div>
I suspect that from function itemValue() returned value is of type string and this is causing wrong calculation. Make sure you parse the result as number. You can use parseFloat() when returning from itemValue().
Check the sample:
var app = angular.module('test', []);
app.controller('AppController', ['$scope', function($scope) {
}]);
app.run();
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="test" ng-controller="AppController" class="widget">
<div class="value">Wrong: {{'12.5' * 1 + '10' | number:2}} kW</div>
<div class="value">Correct: {{12.5 * 1 + 10 | number:2}} kW</div>
</div>
Add the | number:2 filter within the {{ }} of the 2nd and 3rd values. This filter allows numbers to be shown in decimals. Also make sure the data isn't string.
<div class="widget">
<div class="icon off">
<svg viewBox="0 0 48 48">
<use xlink:href="/static/matrix-theme/squidink.svg#thunder-1">
</use>
</svg>
</div>
<div class="name">Power</div>
<div class="valueGroup">
<div class="value">
{{(itemValue('LivingRoomNum2')*1 + itemValue('KitchenNum2')*1)/1000}} kW
</div>
<div class="value">{{itemValue('LivingRoomNum1')}} W (P1)</div>
<div class="value">{{itemValue('KitchenNum1')}} W (P2)</div>
</div>
</div>
This fixed it. My actual number is indeed a string

Trying to click on the <Button> tag , in selenium web driver using python

I have been trying to click on a button for the following html by using python (selenium webdriver)
<div class="cssm-TopNav_printIcon_2VzB_">
<button type="button" aria-label="Print" title="Print" class="cssm-Button_button_2a549 cssm-Button_secondary_22F7i cssm-Button_sm_EPQ2U">
<div class="" aria-hidden="true" color="black" style="display: inline-block; height: 16px; width: 16px; min-height: 16px; min-width: 16px; max-height: 16px; max-width: 16px;">
<svg viewBox="0 0 24 24" class="" focusable="false">
<g fill="#3C3F51">
<path d="M19 8H5c-1.66 0-3 1.34-3 3v6h4v4h12v-4h4v-6c0-1.66-1.34-3-3-3zm-3 11H8v-5h8v5zm3-7c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1zm-1-9H6v4h12V3z">
</path>
<path d="M0 0h24v24H0z" fill="none">
</path></g></svg></div></button>
<button type="button" class="cssm-Button_button_2a549 cssm-Button_primary_1gH9y cssm-Button_sm_EPQ2U">
<!-- react-text: 314 -->View Custody List<!-- /react-text -->
</button>
I am trying to click on the second button in the above html.
I am using find_element_by_tag because i think for html <button> tag it should work .I am using following code snippet to click on it , but getting-:element not visible
driver.find_element_by_tag_name("button").click()
Any help will be appreciated!!
Selenium with Python documentation UnOfficial
Hii there
Selenium provides the following methods to locate elements in a page:
find_element_by_id
find_element_by_name
find_element_by_xpath
find_element_by_link_text
find_element_by_partial_link_text
find_element_by_tag_name
find_element_by_class_name
find_element_by_css_selector
To find multiple elements (these methods will return a list):
find_elements_by_name
find_elements_by_xpath
find_elements_by_link_text
find_elements_by_partial_link_text
find_elements_by_tag_name
find_elements_by_class_name
find_elements_by_css_selector
this is how your code should be
#this code will get the list of tags and select the second tag from the list
element = driver.find_elements_by_tag_name('button')[1]
#this will click the element
element.click()
There is probably more than one button tag on the page, try to be more explicit, like:
driver.find_element_by_class_name("cssm-Button_primary_1gH9y").click()
or even better, give the button an ID and use
driver.find_element_by_id("the-button-id").click()