简体   繁体   中英

How to pass an object between views in django?

Backstory/Problem

I have a web application that runs various jobs. One of these jobs includes running a python script that logs into linkedin.

When I run the script an instance of headless chromium starts, navigates to the linkedin login page and submits the proper credentials. Everything works fine up to this point, but sometimes linkedin will send my request to a checkpoint url and prompt me to submit a special pincode sent to my email before I can proceed.

I am having trouble understanding how to implement this conditional logic in my view; basically, I want to have a way where I can enter the pincode in my web application.

Expected Outcome

Run a script from django view to login to linkedin, and prompt user to enter pincode if checkpoint is reached, otherwise continue if no checkpoint is reached and login was successful.

What I've tried

  • Google - Couldn't find anything specific to my problem.

  • Code below - The view below shows my current attempt. I know it can be done, but I'm not sure if I should be trying to build it out in a single view, or if I should try passing my chromium instance to another view (Objects are not serializable so I'm not sure how I would do this; maybe I could pass the chromium id to another instance of my webdriver, but I don't think that's the best method?)

  • Ajax? -- I haven't actually tried this, but I know it's an option.

Notes**

The code Ive included below is everything. But the only important part to consider is the view, I figured adding the rest might clarify the logic and help someone help me. Hopefully this isn't too verbose!

View

def verify_linkedin(request):
    """Used for verifying login to linkedin with email pincode"""
    ln = LinkedinScraper()
    if ln.login_to_linkedin(username=os.getenv("LINKEDIN_USERNAME"), password=os.getenv("LINKEDIN_PASSWORD")):
        return HttpResponse("<h1>You are verified</h1>")
    else:
        if request.method == "POST":
            form = VerifyLinkedinForm(request.POST)
            if form.is_valid():
                print(form.cleaned_data)
                pin_code = form['verification_key']
                ln.authenticate_linkedin_login(pin_code)
                return redirect("home")
        else:
            form = VerifyLinkedinForm()

    context = {"form": form}
    return render(request, "linkedin_verify.html", context)

Form

class VerifyLinkedinForm(forms.Form):
    verification_key = forms.CharField()
    helper = FormHelper()
    helper.form_method = "post"
    helper.layout = Layout(
        'verification_key',
        FormActions(
            Submit("submit", "Verify Linkedin", style="display: block; margin: auto; margin-bottom:2em;",
                css_class="btn btn-success", ),
        )
    )

Template

{% extends 'base.html' %}
{% load crispy_forms_tags %}

{% block content %}
  {% crispy form %}
{% endblock %}

Webscraper Backend

class LinkedinScraper(WebScraper):
    """Class for logging into linkedin with chromedriver and scraping linkedin"""

    def __init__(self, headless=True, **kwargs):
        super(LinkedinScraper, self).__init__()
        self.setup_driver(headless=headless)
        self.data = {}
        self.pause = 10
        self.retries = 0
        self.max_retries = 3

    def login_to_linkedin(self, username: str, password: str) -> bool:
        """ Navigates to Linkedin login page and logs in with credentials"""
        login_url = "https://www.linkedin.com/login"
        self.driver.get(login_url)
        user_element = self.driver.find_element("id", "username")
        pass_element = self.driver.find_element("id", "password")
        login_btn = self.driver.find_element_by_class_name(
            "login__form_action_container"
        )
        self.login_and_authenticate(login_btn, user_element, pass_element, username, password)
        if 'checkpoint' in self.driver.current_url:
            return False
        else:
            return True

    def authenticate_linkedin_login(self, pin_code: str):
        """ Sometimes when logging into linkedin from a new ip address, linkedin will flag account for suscipicous access
        If this happens we need to use a pin code sent to email and input it into the form.

        This should be immedidately called after login_and_authenticate returns False
        """
        if 'checkpoint' in self.driver.current_url:
            verification_element = self.driver.find_element_by_xpath("//input[@id='input__email_verification_pin']")
            print(pin_code)
            self.random_send_keys(element=verification_element, keys=pin_code)
            submit_element = self.driver.find_element("id", "email-pin-submit-button")
            submit_element.click()
            return True
        else:
            raise BaseException(f"Driver not on correct url, current url is {self.driver.current_url} -- Should contain checkpoint")

There's two ways to solve this. One way was to create the object instance outside of the views, which was a bit of a hack and completely not scalable, but I was ableto verify my email account with selenium through the webrowser. I did not have to pass objects between views because it was global.

The second way is to not use selenium. Which is what I ended up doing. If anyone is interested in this approach leave me a message or look into pyppeteer.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM