How to web scrape followers from Instagram web browser?

前端 未结 3 578
暗喜
暗喜 2020-12-29 15:10

Can anyone tell me how to access the underlying URL to view a given user\'s Instagram followers? I am able to do this with Instagram API, but given the pending changes to th

3条回答
  •  半阙折子戏
    2020-12-29 15:42

    EDIT: Dec 2018 Update:

    Things have changed in Insta land since this was posted. Here is an updated script that is a bit more pythonic and better utilizes XPATH/CSS paths.

    Note that to use this updated script, you must install the explicit package (pip install explicit), or convert each line with waiter to a pure selenium explicit wait.

    import itertools
    
    from explicit import waiter, XPATH
    from selenium import webdriver
    
    
    def login(driver):
        username = ""  # 
        password = ""  # 
    
        # Load page
        driver.get("https://www.instagram.com/accounts/login/")
    
        # Login
        waiter.find_write(driver, "//div/input[@name='username']", username, by=XPATH)
        waiter.find_write(driver, "//div/input[@name='password']", password, by=XPATH)
        waiter.find_element(driver, "//div/button[@type='submit']", by=XPATH).click()
    
        # Wait for the user dashboard page to load
        waiter.find_element(driver, "//a/span[@aria-label='Find People']", by=XPATH)
    
    
    def scrape_followers(driver, account):
        # Load account page
        driver.get("https://www.instagram.com/{0}/".format(account))
    
        # Click the 'Follower(s)' link
        # driver.find_element_by_partial_link_text("follower").click()
        waiter.find_element(driver, "//a[@href='/instagram/followers/']", by=XPATH).click()
    
        # Wait for the followers modal to load
        waiter.find_element(driver, "//div[@role='dialog']", by=XPATH)
    
        # At this point a Followers modal pops open. If you immediately scroll to the bottom,
        # you hit a stopping point and a "See All Suggestions" link. If you fiddle with the
        # model by scrolling up and down, you can force it to load additional followers for
        # that person.
    
        # Now the modal will begin loading followers every time you scroll to the bottom.
        # Keep scrolling in a loop until you've hit the desired number of followers.
        # In this instance, I'm using a generator to return followers one-by-one
        follower_css = "ul div li:nth-child({}) a.notranslate"  # Taking advange of CSS's nth-child functionality
        for group in itertools.count(start=1, step=12):
            for follower_index in range(group, group + 12):
                yield waiter.find_element(driver, follower_css.format(follower_index)).text
    
            # Instagram loads followers 12 at a time. Find the last follower element
            # and scroll it into view, forcing instagram to load another 12
            # Even though we just found this elem in the previous for loop, there can
            # potentially be large amount of time between that call and this one,
            # and the element might have gone stale. Lets just re-acquire it to avoid
            # that
            last_follower = waiter.find_element(driver, follower_css.format(follower_index))
            driver.execute_script("arguments[0].scrollIntoView();", last_follower)
    
    
    if __name__ == "__main__":
        account = 'instagram'
        driver = webdriver.Chrome()
        try:
            login(driver)
            # Print the first 75 followers for the "instagram" account
            print('Followers of the "{}" account'.format(account))
            for count, follower in enumerate(scrape_followers(driver, account=account), 1):
                print("\t{:>3}: {}".format(count, follower))
                if count >= 75:
                    break
        finally:
            driver.quit()
    

    I did a quick benchmark to show how performance decreases exponentially the more followers you attempt to scrape this way:

    $ python example.py
    Followers of the "instagram" account
    Found    100 followers in 11 seconds
    Found    200 followers in 19 seconds
    Found    300 followers in 29 seconds
    Found    400 followers in 47 seconds
    Found    500 followers in 71 seconds
    Found    600 followers in 106 seconds
    Found    700 followers in 157 seconds
    Found    800 followers in 213 seconds
    Found    900 followers in 284 seconds
    Found   1000 followers in 375 seconds
    

    Original post: Your question is a little confusing. For instance, I'm not really sure what "from which I can scrape and paginate through all iterations" actually means. What are you currently using to scrape and paginate?

    Regardless, instagram.com/instagram/media/ is not the same type of endpoint as instagram.com/instagram/followers. The media endpoint appears to be a REST API, configured to return an easily parseable JSON object.

    The followers endpoint isn't really a RESTful endpoint from what I can tell. Rather, Instagram AJAXs in the information to the page source (using React?) after you click the Followers button. I don't think you will be able to get that information without using something like Selenium, which can load/render the javascript that displays the followers to the user.

    This example code will work:

    from selenium import webdriver
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.support import expected_conditions as EC
    
    
    def login(driver):
        username = ""  # 
        password = ""  # 
    
        # Load page
        driver.get("https://www.instagram.com/accounts/login/")
    
        # Login
        driver.find_element_by_xpath("//div/input[@name='username']").send_keys(username)
        driver.find_element_by_xpath("//div/input[@name='password']").send_keys(password)
        driver.find_element_by_xpath("//span/button").click()
    
        # Wait for the login page to load
        WebDriverWait(driver, 10).until(
            EC.presence_of_element_located((By.LINK_TEXT, "See All")))
    
    
    def scrape_followers(driver, account):
        # Load account page
        driver.get("https://www.instagram.com/{0}/".format(account))
    
        # Click the 'Follower(s)' link
        driver.find_element_by_partial_link_text("follower").click()
    
        # Wait for the followers modal to load
        xpath = "//div[@style='position: relative; z-index: 1;']/div/div[2]/div/div[1]"
        WebDriverWait(driver, 10).until(
            EC.presence_of_element_located((By.XPATH, xpath)))
    
        # You'll need to figure out some scrolling magic here. Something that can
        # scroll to the bottom of the followers modal, and know when its reached
        # the bottom. This is pretty impractical for people with a lot of followers
    
        # Finally, scrape the followers
        xpath = "//div[@style='position: relative; z-index: 1;']//ul/li/div/div/div/div/a"
        followers_elems = driver.find_elements_by_xpath(xpath)
    
        return [e.text for e in followers_elems]
    
    
    if __name__ == "__main__":
        driver = webdriver.Chrome()
        try:
            login(driver)
            followers = scrape_followers(driver, "instagram")
            print(followers)
        finally:
            driver.quit()
    

    This approach is problematic for a number of reasons, chief among them being how slow it is, relative to the the API.

提交回复
热议问题