Why Doesn't the Selector H3:Nth-Child(1):Contains('A') Work

Why doesn't the selector h3:nth-child(1):contains('a') work?

:contains() is not was going to be a CSS3 selector (thanks T.J. Crowder for the link), but it didn't make it, most likely because the way it works tends to lead to severe performance and over-selection issues. For example, if an element E matches :contains() for a given string argument, then all of its ancestors would also match; using it with a universal selector would lead to unexpected results with certain style properties, on top of being slow for the browser.

There is no other CSS selector that serves a purpose like :contains(). So you'll have to find some other way, either by modifying your HTML or even by using jQuery's :contains(), to achieve the effect you want:

Select an h3 element

if it is the first child of its parent

and its text contains the letter 'a'.

For jQuery and Selenium RC users: :contains() is implemented in the Sizzle selector engine used by jQuery, which is also used in Selenium RC (but not Selenium WebDriver). It works as described in this decade-old revision of the CSS3 spec, but again, due to how the spec describes it, you need to use it with care or it may lead to unexpected selections.

On a final note, h3:nth-child(1) can be replaced with h3:first-child, which as a CSS2 selector has better browser support.

:nth-child(2) doesn't work. :nth-child(1) and :nth-child(3) do

Here is an explanation of what went wrong. It was the result of your selector. The oddity in the way it played out was due to your html structure, and using querySelector.

div.rules :nth-child()

This will first target the <div class="rules"> element. Then, it will look for all elements which are the nth-child inside of that div because of the space between the two selectors. Following that, using querySelector will select the first element of the matched set.

This is why you ended up getting the first <div> with :nth-child(1), because it in fact matched every single nth-child(1), but taking the first result was coincidentally the element you expected.

However, :nth-child(2) matching every second child element was far too wide of a net, and ended up getting the second child in the first div, and since that was the first result, that was where the red background showed up.

The final curiosity of :nth-child(3) seeming to actually hit the proper element was only because there is only one third child element in all of that html, and it was the one which you expected, although as explained for reasons other than assumed.

CSS nth-child is not working based on my expectation

This is because the first service-box is actually the second child of its parent, center-text being the first. Remove center-text and use .service-box:nth-child(3).

.service-box:nth-child(3) {  background-color: red;}
<div class="our-services">  <div class="service-box">    <h3 class="center-text">Service 1</h3>    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non.</p>  </div>  <div class="service-box">    <h3 class="center-text">Service 2</h3>    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non.</p>  </div>  <div class="service-box">    <h3 class="center-text">Service 3</h3>    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non.</p>  </div></div>

Finding link using text in CSS Selector is not working

You are trying to locate a link by using the following CssSelectors:

  • a[text='This is a link']
  • a[innertext='This is a link']

As per Issue#987 and Issue#1547:

The :contains pseudo-class isn't in the CSS Spec and is not supported by either Firefox or Chrome (even outside WebDriver).

You can find a detailed discussion in selenium.common.exceptions.InvalidSelectorException with “span:contains('string')”

Solution

As per the HTML you can use either of the following solutions:

  • CssSelector using the attribute title:

    "a[title='seleniumframework']"
  • CssSelector using the attribute href:

    "a[href='http://www.seleniumframework.com']"
  • CssSelector using the attributes title and href:

    "a[title='seleniumframework'][href='http://www.seleniumframework.com']"

selenium.common.exceptions.InvalidSelectorException with span:contains('string')

Using css_selector to locate element by text is not supported in Selenium (although it will work in the developer tools console). The only possibility is xpath

element = "//span[contains(text(), 'Control panel')]"
my_driver.find_element_by_xpath(element)

Edit: a comment by @FlorentB:

A css selector is not supported by the console either, but JQuery supports it. The $('...') from the console is a shorthand for document.querySelector which is generally overridden with JQuery when the page has it.

scrapy get nth-child text of same class

The <div class="adxExtraInfo"> that you are targetting is not the 1st child of its <div class="adxHeader"> parent. The <h3> is.
So div.adxExtraInfo:nth-child(1) will not match anything in your input:

>>> s = scrapy.Selector(text='''<div class="adxHeader">
... <h3 itemprop="name"> » درج داخلي للاجار جديد حي المونسيه</h3>
...
... <div class="adxExtraInfo">
... <div class="adxExtraInfoPart"><a href="/city/الرياض"><i class="fa fa-map-marker"></i> الرياض</a></div>
... <div class="adxExtraInfoPart"><a href="/users/ابو نوره"><i class="fa fa-user"></i> ابو نوره</a></div>
... </div>
...
... <div class="adxExtraInfo">
... <div class="adxExtraInfoPart"> قبل ساعه و 27 دقيقه</div>
... <div class="adxExtraInfoPart">#20467014</div>
... </div>
... <div class="moveLeft">
...
...
... <a href="www.google.com" class="nextad"> ← التالي </a>
... <br />
...
... </div>
...
... </div>''')

>>> s.css('div.adxHeader > div.adxExtraInfo:nth-child(1)').extract()
[]
>>> s.css('div.adxHeader > *:nth-child(1)').extract()
[u'<h3 itemprop="name"> \xbb \u062f\u0631\u062c \u062f\u0627\u062e\u0644\u064a \u0644\u0644\u0627\u062c\u0627\u0631 \u062c\u062f\u064a\u062f \u062d\u064a \u0627\u0644\u0645\u0648\u0646\u0633\u064a\u0647</h3>']
>>>

But you may want to anchor div.adxExtraInfo with the <h3> in that case, using the Adjacent sibling combinator (in other words, the <div class="adxExtraInfo"> immediately following the <h3>):

>>> print(
... s.css('''div.adxHeader
... > h3:nth-child(1) + div.adxExtraInfo
... div.adxExtraInfoPart:nth-child(1) a::text''').extract_first())
الرياض
>>>

Nth-child css property is counting html elements with display property set to none. How to change it?

Remove your nth-child CSS style and every time you change the layout, call this:

$("li.item:visible").each(function(i) {
if((i+1)%4==0) $(this).css("margin","30px 0");
else $(this).css("margin","30px 20px 30px 0");
})

Just tested it on your site with firebug and worked a treat.



Related Topics



Leave a reply



Submit