How to nest loop number into an xpath in python? - python

I have the xpath to follow a user on a website in selenium. Here is what I thought of doing so far:
followloop = [1,2,3,4,5,6,7,8,9,10]
for x in followloop:
driver.find_element_by_xpath("/html/body/div[7]/div/div/div[2]/div[>>>here is where i want the increment to increase<<<]/div[2]/div[1]/div/button").click()
So where I stated in the code is where I want the number to go up in increments. Also as you see with the for loop Im' doing 1,2,3,4,5...can I code it more simply to be like 1-100? Because I don't just want 1-10 I will want it 1-whatever higher number.
I tried to just put x in where I want it but realised that python won't pick up that it's a variable I want to put in that slot and will just consider it as part of the xpath. So how do I make it put the increasing number variable number in there on each loop?

You need to convert the index from the for loop into a string and use it in your xpath:
follow_loop = range(1, 11)
for x in follow_loop:
xpath = "/html/body/div[7]/div/div/div[2]/div["
xpath += str(x)
xpath += "]/div[2]/div[1]/div/button"
driver.find_element_by_xpath(xpath).click()
Also, there will generally be a neater/better way of selecting an element instead of using the XPath /html/body/div[7]/div/div/div[2]. Try to select an element by class or by id, eg:
//div[#class="a-classname"]
//div[#id="an-id-name"]

I would use a wildcard '%s' for your task and range() as indicated in previous comments:
for x in range(0,100):
driver.find_element_by_xpath("/html/body/div[7]/div/div/div[2]/div[%s]/div[2]/
div[1]/div/button").click() % x

Use a format string.
And use range() (or xrange() for larger numbers) instead. It does exactly what you want.
for x in range(10):
driver.find_element_by_xpath("/html/body/div[7]/div/div/div[2]/div[%d]/div[2]/div[1]/div/button" % (x,)).click()

Related

How to add words/strings in lines from a list?

output
the Code
I'm trying to add different words from a list to lines in order. However, I am stuck with it. Can you please tell me how to proceed? I am getting a type error, and couldn't get my output.
The output that I'm trying to get:
it starts with: one or more.
it starts with: two or more.
it starts with: three or more.
The code that I tried:
a=["one","two","three"]
for i in a:
print("it starts with: " + a[i] + "or more")
The result I'm getting:
TypeError: list indices must be integers or slices, not str
i is already the element you want.
In Python the expression for i in a assigns elements of the array a to the variable i on every pass of the loop. You don't nedd to address the elements.
for i in a:
print("it starts with: " + i + "or more")
i already represents each element in the list. You can use an f-string to put it into the string:
for i in a:
print(f"it starts with: {i} or more")
So the issue you're encountering is that when you tell python to take an element i from the list the i value is not the index but rather the value. So basically what your code is doing is a["one"] which doesn't work.
If you replace a[i] with just i it should work. Also I would recommend replacing '+' with ',' for there to be a space between your two strings and the value you're taking from a.
You mix-up the iteration part, here looping over the length of the list
a=["one","two","three"]
for i in range(len(a)):
print("it starts with: " + a[i] + "or more")
Here another approach. Used a string template where {} represent the placeholder.
a=["one","two","three"]
template = "it starts with: {} or more"
print(*map(template.format, a), sep='\n')
for loops work with iterables
So, for example,
for X in Y:
pass
Here, Y is an iterable and X will acquire the values from Y one at a time until the iterable is exhausted.
In your case, a is a list (an iterable) of strings.
Therefore you could simply do this:
a = ["one", "two", "three"]
for w in a:
print('it starts with:', w, 'or more')
Note how neither f-strings nor string concatenation is required in this case. This is because multiple values can be passed to print() and they will be emitted separated by a single space (by default).
Output:
it starts with: one or more
it starts with: two or more
it starts with: three or more
I think the other answers should fix your problem but to avoid this trivial error in the future, you should try to examine the value of the variable you're using with one of these methods:
Adding a print() statement. In your case: add this after line 3
print(i)
Using debugging feature of your IDE. For example in VSCOde: https://code.visualstudio.com/docs/python/debugging

Loop over lists in Xpath

How would I loop over a list in the Xpath? I thought it was similar to using the .format function like it would when looping over a string, this obviously does not work. I wanted to get the href from each list - for example:
for i in range(0, 15):
test_page = response.xpath('.//li[{i}]/a[#class="pagination__item"]/#href').format(i)
Taken from the link: https://www.ebay.com/b/Collectible-Card-Games-Accessories/2536/bn_1852210?LH_BIN=1&LH_PrefLoc=2&mag=1&rt=nc&_pgn=4&_sop=16
Expected output:
A way to index i or some type of boolean logic i.e. to select between 1 and 30.

Find specific number of things with Beautiful soup

I know that the find() command finds only the first occurrence and that find_all() finds all of them. Is there a way to find a specific number?
If i want to find only the first two occurrences is there a method for that or does that need to be resolved in a loop?
You can use CSS selectors knowing the child position you need to extract. Let's assume the HTML you have is like this:
<div id="id1">
<span>val1</span>
<span>val2</span>
<span>val2</span>
</div>
Then you can select the first element by the following:
child = div.select('span:nth-child(1)')
Replace 1 by the number you want
If you want to select multiple occurrences, you can concatenate the children like this:
child = div.select('span:nth-child(1)') + div.select('span:nth-child(2)')
to get the first two children
nth-child selector can also get you the odd number of occurrences:
child = div.select('span:nth-child(2n+1)')
where n starts from 0:
n: 0 => 2n+1: 1
n: 1 => 2n+1: 3
..
Edited after addressing the comment, thanks!
If you are looking for first n elements:
As pointed out in comments, you can use find_all to find all elements and then select necessary amount of it with list slices.
soup.find_all(...)[:n] # get first n elements
Or more efficiently, you can use limit parameter of find_all to limit the number of elements you want.
soup.find_all(..., limit = n)
This is more efficient because it doesn't iterate through the whole page. It stops execution after reaching to limit.
Refer to the documentation for more.
If you are looking for the n(th) element:
In this case you can use :nth-child property of css selectors:
soup.select_one('span:nth-child(n)')

How to refer to a value if you have the depth of the tuple when you can't use the index of a nested tuple explicitly?

Let's say there is a tuple in the form
J = ((1),((2),((3),((4), (7,7)))))
and you want to change the value of a index of J depending on how many iterations have occurred within a for loop.
The problem involves replacing the second tuple with an integer, but because of the for loop each time the depth being referred to will be different.
Objective:
does an operation using values within a tuple and to replace that tuple with the value
I know that
list(J)[1][1][1][1]
will be equal to the (7,7) the value that I want to change.
But say I have the depth of the index - 4. Is there a way to have that as a variable and code to refer to
list(J)[1][1][1][1]
by using 4 instead of having to type out each bracket, in a hardcoded way?
Reason being, I want to include the assignment within a for loop.
i.e. something like
list(J)"[1]"*depthvariable = changed value
or something, which will be equal to
list(J)[1][1][1][1] = changed value
when depthvariable is equal to 4?
In short, is there a way to use integers that will be incremented each time so that within the code itself it can do this:
for 1 time :
J[1]
for 2 time:
J[1][1]
for 3 time:
J[1][1][1]
If I use for jelement in J, then I lose the overall variable. I'm not trying to get elements within the J tuple, and I need to keep the overall variable. I'm just trying to change certain elements within J, but I'm not sure how to code if the depth I'm looking at is different each time within a for loop.
The part I'm really struggling with is finding an expression to refer to an element in the tuple when the depth changes each time.
Because it will involve having a different number of brackets.
E.g.
J[1], J[1][1] etc.
Thanks for the help in advance!
EDIT:
It's important that I can change J itself using the variable depth index.
Use a loop.
J = ((1),((2),((3),((4), (7,7)))))
cur = J
depthvariable = 4
for _ in range(depthvariable):
cur = cur[1]
print(cur)
You can use reduce and operator.getitem.
from functools import reduce
from operator import getitem
J = ((1),((2),((3),((4), (7,7)))))
print(reduce(getitem, [1] * 4, J))

How to print values in a list on separate lines? Must use a for statement.

I need to use a for statement in order to print each value of a list on separate lines. When using the for statement it prints the entire list on one line. Additionally when trying to print just the values in the list on the same line it appears with double brackets instead of single.
Numbers=range(5,25,4)
NumberSequence=[]
NumberSequence.append(Numbers)
print NumberSequence
for elem in NumberSequence:
print elem
NumberSequence2=[]
Numbers2=range(26,0,-7)
NumberSequence2.append(Numbers2)
print NumberSequence2
for digits in NumberSequence2:
print digits
That is because you made a list and then put it inside of another list. If I understand you correctly, you want to print each individual number on a separate line. This can be done with:
Numbers = range(5,24,4)
for elem in Numbers:
print elem
Also, as #roganjosh mentioned, you seem to be using Python 2 which is rather old, slower than Python 3, and it's days of being supported are numbered. I highly recommend you make the switch to python 3 :)

Categories