Selenium, how to start Firefox with addons? - python

I want to load the Firefox Addon RequestPolicy. This is how i tried it:
rp = open(wd + "/requestpolicy.xpi")
firefoxProfile = FirefoxProfile()
firefoxProfile.add_extension(rp)
self.driver = webdriver.Firefox(firefoxProfile)
self.usr = user.User(self.driver, username, password, world)
self.usr.login()
No error, according to the Docs it should work, but it doesn't, it still starts without the addon.
Next thing i've tried is calling it this way:
self.driver = webdriver.Firefox(browser_profile=firefoxProfile)
Output:
TypeError: __init__() got an unexpected keyword argument 'browser_profile'
But this is an aspect of python i dont know much about. I got that idea because the source looks that way.

I don't have enough Stackoverflow rep to leave a comment on your question, and unfortunately I don't know the answer to your question, but for what it's worth you need to call webdriver.Firefox() with firefox_profile, not browser_profile, as you have done.
See also: http://code.google.com/p/selenium/source/browse/trunk/py/selenium/webdriver/firefox/webdriver.py#33

what I did and worked was:
profile=webdriver.FirefoxProfile()
profile.add_extension("/home/.../.mozilla/firefox/zrdb9ki8.default/extensions/{d10d0bf8-f5b5-c8b4-a8b2-2b9879e08c5d}.xpi") # for adblockplus
profile.set_preference("extensions.adblockplus.currentVersion", "2.8.2")
Fox = webdriver.Firefox(profile)
Fox.get(website_Url) #https://.....

It took me a few hours to find a solution.
All you need to do is download your extension as .xip file.
And then add this line to your code:
driver.install_addon('/Users/someuser/app/extension.xpi', temporary=True)
Replace "/Users/someuser/app/extension.xpi" with path to your extension .xip file.

Additionally you should not open the xpi file directly. Instead try to just give the address:
firefoxProfile.add_extension(wd + "/requestpolicy.xpi")

Related

Pytest bdd error "scenario_wrapper() missing 1 required positional argument: 'request'"

I'm learning pytest and I get an error trying to run a test that worked fine before I added pytest-bdd(feature file, step file is the one I'm trying to run)
This is my code:
import pytest
import time
from selenium import webdriver
from pytest_bdd import scenario, given, when, then
#scenario('../feature/learn.feature', 'learning pytest-bdd')
#when('Does work-->website open, find element')
def does_work():
driver = webdriver.Edge(r"C:/Users/artri/Downloads/edgedriver_win64/msedgedriver.exe")
driver.get('https://www.example.com/')
driver.maximize_window()
print(driver.title)
time.sleep(5)
element = driver.find_element_by_xpath("//button[#class='btn btn-outline-light btn-lg btn-close']")
element.click()
name = driver.find_element_by_xpath("//a[#href='/items/something/']").text
driver.quit()
return name
#then('Get text "something"')
def test_work():
assert does_work() == 'something'
It finds the element and checks if it's value is right. I would like to know why after adding steps and making the feature file it doesn't work. Other test in the same steps file works just like they did before.
The error massage:
#then('Get text "something"')
def test_work():
> assert does_work() == 'something'
E TypeError: scenario_wrapper() missing 1 required positional argument: 'request'
I looked at a couple similar questions, but non were understandable for me.
If anyone has any idea where the issue might be or some links would be very appreciated!
You have decorator without function def.
From documentation at: https://github.com/pytest-dev/pytest-bdd
#scenario('publish_article.feature', 'Publishing the article')
def test_publish():
pass
You need to decorate empty function.

Selenium webdriver isn't able to clear a field, but is able to send_keys to it

I'm trying to create a program that signs up for instagram with a new account, I've got the emails and the rest generated, when I go ahead and send_keys to the appropriate fields, it does it just fine. I wanted to implement a retry function, which would clear the email field and try with a different mail. However this does not work, even though send_keys to it worked previously? Snippet of my code below.
driver.get('https://www.instagram.com')
driver.find_element_by_xpath("//*[contains(#aria-label,'Email')]").send_keys(mail)
driver.find_element_by_xpath("//*[contains(#aria-label,'Full')]").send_keys(name + lastname)
driver.find_element_by_xpath("//*[contains(#aria-label,'User')]").send_keys(namae+lastonamae+pamae2)
driver.find_element_by_xpath("//*[contains(#aria-label,'Password')]").send_keys(password)
driver.find_element_by_xpath("//*[contains(#type,'submit')]").click()
This attempts to create a new account with the appropriate credentials, however when it fails, I want it to try to look for an element that is only present when it fails, and if it finds that, it should clear the email field and retry with a different one. Code below.
driver.find_element_by_xpath('//*[#id="react-root"]/section/main/article/div[2]/div[1]/div/form/div[3]/div/div[2]/span') #this looks for the element only present on the fail page
driver.find_element_by_xpath("//*[contains(#aria-label,'Email')]").clear()
driver.find_element_by_xpath("//*[contains(#aria-label,'Email')]").send_keys(mail2)
It doesn't clear the field, but doesn't raise an error either. It then proceeds to type the 2nd email with no problems. I appreciate any help on the matter.
EDIT: Posting a bigger chunk of the code.
def signup():
driver.get('https://www.instagram.com')
time.sleep(7)
if trycounter < 3: #this is almost always true, just a failsafe
driver.find_element_by_xpath("//*[contains(#aria-label,'Email')]").send_keys(mail1)
driver.find_element_by_xpath("//*[contains(#aria-label,'Full')]").send_keys(name + ' ' + lastname)
driver.find_element_by_xpath("//*[contains(#aria-label,'User')]").send_keys(name+lastname+extension)
driver.find_element_by_xpath("//*[contains(#aria-label,'Password')]").send_keys(password)
driver.find_element_by_xpath("//*[contains(#type,'submit')]").click()
time.sleep(7)
try: #this only executes if a popup that wants you to confirm your age pops up
driver.find_element_by_xpath('//*[#id="igCoreRadioButtonageRadioabove_18"]').click()
driver.find_element_by_xpath('/html/body/div[3]/div/div[3]/div/button').click()
time.sleep(5)
except:
pass
try:
randomgen() #generates the mail,password and name
driver.find_element_by_xpath('//*[#id="react-root"]/section/main/article/div[2]/div[1]/div/form/div[3]/div/div[2]/span')
time.sleep(1)
driver.find_element_by_xpath("//*[contains(#aria-label,'Email')]").clear()
time.sleep(1)
driver.find_element_by_xpath("//*[contains(#aria-label,'Email')]").send_keys(mail2)
driver.find_element_by_xpath("//*[contains(#aria-label,'User')]").send_keys(username)
driver.find_element_by_xpath("//*[contains(#type,'submit')]").click()
time.sleep(7)
You can use following code as alternative for clear method:
from selenium.webdriver.common.keys import Keys
email_element = driver.find_element_by_xpath("//*[contains(#aria-label,'Email')]")
email_element.send_keys(Keys.CONTROL, 'a')
email_element.send_keys(mail1)
fullname_element = driver.find_element_by_xpath("//*[contains(#aria-label,'Full')]")
fullname_element.send_keys(Keys.CONTROL, 'a')
fullname_element.send_keys(name + ' ' + lastname)
# do it for other field as well
So this will definitely work as a workaround. I just tried it on instagram. Although there was no field with an aria label called Email for me. It was aria-label "Mobile Number or Email" for me.
driver.execute_script("$(\"input[aria-label='Email']"\").value = '';");
I will keep looking at it to see why the clear command didn't work though.
You can try something like this to delete mail1.
driver.find_element_by_xpath("//*[contains(#aria-label,'Email')]").send_keys(Keys.chord(Keys.CONTROL,"a"))
driver.find_element_by_xpath("//*[contains(#aria-label,'Email')]").send_keys(Keys.DELETE)
driver.find_element_by_xpath("//*[contains(#aria-label,'Email')]").send_keys(mail2)

PRAW Errors updating to new Python Distro

So I am trying to create a bot that cross posts from a sub (r/pics) to (r/polpics) using a bit of code from u/GoldenSights. I upgraded to a new python distro and I get a ton of errors, I don't even know where to begin. Here is the code (formatting off, error lines bold):
Traceback (most recent call last):
File "C:\Users\tonyc\AppData\Local\Programs\Python\Python36-32\Lib\site-
packages\praw\subdump.py", line 84, in <module>
r = praw.Reddit(USERAGENT)
File "C:\Users\tonyc\AppData\Local\Programs\Python\Python36-32\lib\site-
packages\praw\reddit.py", line 150, in __init__
raise ClientException(required_message.format(attribute))
praw.exceptions.ClientException: Required configuration setting 'client_id'
missing.
This setting can be provided in a praw.ini file, as a keyword argument to the `Reddit` class constructor, or as an environment variable.
This seems to be related to USERAGENT setting. I don't think I have that configured right.
USERAGENT = ""
# This is a short description of what the bot does. For example
"/u/GoldenSights' Newsletter bot"
SUBREDDIT = "pics"
# This is the sub or list of subs to scan for new posts.
# For a single sub, use "sub1".
# For multiple subs, use "sub1+sub2+sub3+...".
# For all use "all"
KEYWORDS = ["It looks like this post is about US Politics."]
# Any comment containing these words will be saved.
KEYDOMAINS = []
# If non-empty, linkposts must have these strings in their URL
This is the error line:
print('Logging in')
r = praw.Reddit(USERAGENT) <--here, this is error line 84
r.set_oauth_app_info(APP_ID, APP_SECRET, APP_URI)
r.refresh_access_information(APP_REFRESH)
Also in Reddit.py :
raise ClientException(required_message.format(attribute)) <--- error
praw.exceptions.ClientException: Required configuration setting 'client_id'
missing.
This setting can be provided in a praw.ini file, as a keyword argument to
the `Reddit` class constructor, or as an environment variable.
Firstly, you're going to want to have your API credentials stored externally in your praw.ini file. This makes things a lot more secure, and looks like it might go some way to fixing your issue. Here's what a completed praw.ini file looks like, including the useragent, so try to replicate this.
[DEFAULT]
# A boolean to indicate whether or not to check for package updates.
check_for_updates=True
# Object to kind mappings
comment_kind=t1
message_kind=t4
redditor_kind=t2
submission_kind=t3
subreddit_kind=t5
# The URL prefix for OAuth-related requests.
oauth_url=https://oauth.reddit.com
# The URL prefix for regular requests.
reddit_url=https://www.reddit.com
# The URL prefix for short URLs.
short_url=https://redd.it
[appname]
client_id=IE*******T14_w
client_secret=SW***********************CLY
password=******************
username=appname
user_agent=web:appname:1.0.0 (by /u/username)
Let me know how things go after you sort this out.

getElementById() takes exactly 1 argument (2 given)

I want to do an automation of the Internet Explorer. Open the Internet Explorer, navigate to login.live.com and set a value into the email textbox.
Here's the simple script:
import win32com.client
import time
IE = win32com.client.DispatchEx("InternetExplorer.Application")
IE.Visible = 1
IE.Navigate('login.live.com')
time.sleep(5)
DOC = IE.document
DOC.getElementById('i0116').value = 'test'
The last line always returns the following TypeError:
getElementById() takes exactly 1 argument (2 given)
When I try to add the value through the console of the Internet Explorer it works.
Btw. the getElementsByTagName() method works without any Errors.
Thanks for any help!
Okay.. I wrote a workaround for this:
DOC = IE.Document
inputs = DOC.documentElement.getElementsByTagName('input')
for field in inputs:
if field.id == 'i0116':
email = field
break
email.value = 'example#test.com'
For browser automation I recommend to use the Selenium library.
As this answer suggests you have to use
DOC.Body.getElementById('i0116').value = 'test'

python selenium phantomJS element.location returns wrong location

I have problem with python selenium phantomjs which i couldn't solve. element.location returns wrong location. when I see cropped image it is showing part of desired image and also unwanted one. It worked on firefox perfectly but doesn't work on phantomjs.
Here is code:
def screenOfElement(self, _element):
_location = _element.location
_size = _element.size
_wholePage = Image.open(StringIO.StringIO(base64.decodestring(self.webdriver.get_screenshot_as_base64())))
_left = _location['x']
_top = _location['y']
_right = _location['x'] + _size['width']
_bottom = _location['y'] + _size['height']
return _wholePage.crop((_left, _top, _right, _bottom))
Thanks.
I have found only one solution that worked.
Method 1:
1) Hide everything except needed element:
with open('jquery-2.2.3.min.js', 'r') as jquery_js:
jquery = jquery_js.read() #read the jquery from a file
self.webdriver.execute_script(jquery) #active the jquery lib
self.webdriver.execute_script("""
element = $('#mydiv').parent();
while(element.parent().length)
{
element.parent().siblings().hide();
element = element.parent();
}
""")
2) Take screenshot.
3) Show every element that we hid:
self.webdriver.execute_script("""
element = $('#mydiv').parent();
while(element.parent().length)
{
element.parent().siblings().show();
element = element.parent();
}
""")
But the issue with that is, after we show all element, we might show ones that were hidden before. Also sometimes it doesn't work.
If you are using phantomJS probably visual parts doesn't matter. So better solution would be to
Method 2:
1) Move needed element directly inside <body>:
$('body').append($('#mydiv'))
2) Hide all element except needed one:
$('body > :not("#mydiv")').hide();
3) Show again:
$('body > *)').show();
Hope this helps who has encountered same problem.
Your PhantomJS window might be too small.
Try:
driver = webdriver.PhantomJS()
driver.set_window_size(1280, 1024)

Categories

Resources