diezo / Ensta

🔥 Fast & Reliable Python Package For Instagram API - 2024
https://bit.ly/ensta-discord
MIT License
358 stars 41 forks source link

User not found #56

Closed dvjhr closed 9 months ago

dvjhr commented 9 months ago

I'm currently developing back-end to scrap IG data using FastAPI and Ensta, this is my current code with just a simple endpoint to fetch user's information

from typing import Union
from typing import Annotated, Optional
from fastapi import FastAPI, Request, File, UploadFile, Form, HTTPException
from ensta import Host

app = FastAPI()

default_ig_username = "my_working_dummy_acc"
default_ig_password = "my_dummy_working_password"

def login(username: str, password: str) -> Host:
    """
    Login and initialize Ensta Host with the provided credentials.
    """
    print(username, password)
    return Host(username, password)

@app.post("/fetch_user_data")
async def fetch_user_data(
    username: Optional[str] = Form(default_ig_username),
    password: Optional[str] = Form(default_ig_password),
    target_username: str = Annotated[str, Form(..., description="Username to be fetched")],
):
    """
    Endpoint to fetch user data using the initialized Ensta Host.
    """
    host = login(username, password)

    # Fetch the profile data for the provided Instagram username
    profile = host.profile(target_username)

    # Return the relevant profile data
    return {
        "username": profile.user_id,
        "full_name": profile.full_name,
        "biography": profile.biography,
        "follower_count": profile.follower_count,
    }

With similar code (similar function, only without FastAPI), same account account credential, on local, it is currently working as expected. But on my server, this returns

ensta.lib.Exceptions.AuthenticationError: User doesn't exist.

Note: Not sure if it'll come in handy or not, but I'm using docker with python 3.11-slim, and regarding Cryptodome issue, I use pycryptodomex in my server (in my local I didn't use this workaround)

diezo commented 9 months ago

can you print the reponse_json on this line in this file so that i can get a better understanding about the error?

also, it's not recommended to log in everytime you make an authenticated request. it will get your account flagged for so many logins. instead, a better approach would be to make the user log in once using a seperate endpoint which returns a session_data string. then, require the user to pass that session_data string everytime he makes an authenticated request, which you can use to continue the same session using the SessionHost class.

here's the code sample:

from ensta import Host, SessionHost

@app.post("/login")
def login(username, password):

    host = Host(username, password)
    return host.session_data

@app.get("/profile")
def profile(target_username):

    host = SessionHost(cookies.session_data)  # fetch session_data from cookies, headers or anywhere you wish
    profile =  host.profile(target_username)

    return {
        "username": profile.username
    }
dvjhr commented 9 months ago

Thanks for the reply, took me a while to get the json dump since I'm also new with docker. From the json dump, it looked like I got redirected into challenge endpoint instead of login when I tried it on my server.

{
    "message": "checkpoint_required",
    "checkpoint_url": "https://www.instagram.com/challenge/AXHpTQU67fH3txxnBKevDiPiTR0OV7YqY_GQYelQBaE1t3ehFUtxLiwAaUCV76LDGV-k-ow/Afwq-LONdpoNUPZdnPfXR0A0ozh-DTR-O08Fft6owlTOcPt8v-23JeU7Pg-3NIlsAa14TghGqsh16Q/?challenge_context=Af4fO1USBiyX1engXGfpjtTeUQJtrxPWm2r05yJYVGXFVXBkGvIX4wOQkVXVwLFfTdvMqOVhLNMtqaN6SyKe7gIN4DEB3QIZBQnYDIrAN3sc4PXHxyRNkyRIGGfTByYWGoI2a0il1sabGqyFeR4YBoBoNyADbrOJweqrCHbPhzL9_-1aw5wITFm-RuSFYH9yQxprNsAsnfYR1YJvJo9bFQZAcTIntGGchUep2ZF93ALfFZbIqimW31eg1NA8vysKnvY6riqd-ptyI0CZ5ZWHbH__XHk7V6ClbBm1kcjSgSq98bPpFFv2hjYjLkXaHQeGnT-5N5-CT8d3_KJlGZmcGExwJtC_ov4lD1MF1dlL5FbhTOgvRSSpXiklV4UO7wZZuYCSTWxIiWrJiMNsp7f9F4L70PecEb02qC6pwyE6La86a5389ZZSuvJy_hajx_wF-o245U4nikVeWKZ8LlTpi3OYAUj-iLm-AH7mbRMVPU1Kn3EaT5uBBtNUkHN3Zk42m631SLl5yIy7W24bogCuWgrGgqw_p3qNrmqrdREBMRPhy3oUQ5k1_oPt1NVua_duDt74v47WM2YvKNlpXMDIl9JWM2qeTPgUB4n7kN0TRkfqPk43aZrK-S0gOXKeWWFSdOdhnbZ_ThyD3tIuA7uoeu4ELeR1hw0AOSowbIiCUK2hifja2CUuPpDUuuxQ_stFNnOCJ42A2n53FrnbEGP2yv-QH7ycgFhLAyPiN69RpGA85LdZ7TbnLnn8XxGEdbyFl2V4lgyf6vbUhWrq_t1wCfT2bbdCTd7XbRWME08w0RbYeQzL9IScwocbLLtr7wHPSWPOIoaUMvYWN4JuZtzjjq41JFrddv8OaYwXNQiScrX-qzyXo8Hs4366DPVysK1H2vgsMWntndX4FcGGBnEWkd312xybXT05PePoHgWehX-n6qTHpuBJe8tWEjyQjPKofZa7dTGTiwHRzxoJ_YzI4LM_OlQpnUKshWvYf_mI5QUPKKBBks3AZ_LbufQ1z7AK1apt7NzgNxWBld6hlF46DN4ONMRvc5gkQlCWLELHMVqANa56O2-koVdIuzYnkX00Pj43PBg4VX-YnZcIWVkd2dog0b1qnbWqqzzJx8-KgmcLy4Cdt8cIm52LFlIv_kOSBSnqMG7ov47WlOj-tLeV5mwS5SgrYtE0BPgcv38RccpO33E5N4gvf8rqQwQHveHcH0pLML_v_iv0MfsuqatygLDsxK-_UJ73a7EgTM8C8cER47x_jEXehCTAbHIA6qRpraW9M5j_XcXJ5j2Mka0QBPwMt7OcUAeMJaWTb_PZwj1RBfmS0Me_Pl6oVpTsAC2tlYj9S2uXaSuhaZzhDUmHMpJCkiRqS02Cd56-BWyl1L1MDjd-NCDEYErmQ1PegPoueISdAqoUn9-gIiPg6DCou3paU8NoGI2LcjeN0b8nVHeubcYSD9pihwy7nZh4uEuLGlxeZp6pua-dG3y6a8xFC5u48sQjVWXmg6h6YC4qpcJ0yf8xFgvif3gqiJi_zi29jLVkNM9DkCh9LFP34WhsHIwNlmb3CCeUxyrP0JW9SKYYqlvBjSNEYTeRRoxsrI2_T-rcaWD8TXFtDxhDTqfSLPo4iCpa9B_cGfZDZUpy4Ykrgsz_bNu-1wPEufIFnyKgd0m5-W-zS9hmye1Re5XEqz7tvxWufalhq0LsbLRCDQ6unz_hIH6AHDGcmPX3EDvCUhW3IjQ3",
    "lock": false,
    "flow_render_type": 0,
    "status": "fail"
}

Btw, about the use of session, is it okay if I used global variable that is filled once if it's empty (most likely at the beginning of the run, but there's still a lot to learn on about proper FastAPI usage especially session though)🙏

from typing import Union
from typing import Annotated, Optional
from fastapi import FastAPI, Request, File, UploadFile, Form, HTTPException
from ensta import Host, SessionHost

app = FastAPI()

default_ig_username = "my_dummy_username"
default_ig_password = "my_dummy_password"

session_login = None

def init_login(username: str, password: str) -> Host:
    """
    Login and initialize Ensta Host with the provided credentials.
    """
    print(username, password)
    host = Host(username, password)
    return host.session_data

@app.post("/fetch_user_data")
async def fetch_user_data(
    username: Optional[str] = Form(default_ig_username),
    password: Optional[str] = Form(default_ig_password),
    target_username: str = Annotated[str, Form(..., description="Username to be fetched")],
):
    """
    Endpoint to fetch user data using the initialized Ensta Host.
    """

    global session_login 
    if session_login is None:
        session_login = init_login(default_ig_username, default_ig_password)

    # Initialize the Ensta Host with the provided credentials
    host = SessionHost(session_login.session_data)

    # Fetch the profile data for the provided Instagram username
    profile = host.profile(target_username)

    # Return the relevant profile data
    return {
        "username": profile.user_id,
        "full_name": profile.full_name,
        "biography": profile.biography,
        "follower_count": profile.follower_count,
    }
diezo commented 9 months ago

you must not use a global variable, it'll cause more troubles.

let me clearly describe what i mean:

  1. create a login-only endpoint for the clients which they'll use only once to obtain the session data string. this endpoint should take username & password as argument and return host.session_data which is a string. clients will save this string and not generate a new one until it expires.
  2. now, whenever they need to perform an authenticated request (say fetch profile, follow someone etc), they'll pass that session_data string which they previously obtained through either headers or cookies. the server will use this session_data to initialize SessionHost class.
  3. now that the SessionHost class is initialized, you can use it normally as you would.

in short: you will create a login endpoint which accepts username & password and returns session_data string. clients must pass this string to use other authenticated endpoints.

diezo commented 9 months ago

now talking about the login error that you're facing...

are you using a strong pasword? checkpoint is usually required only when you're using a weak password.

other reason might be that you're using a hosting service which uses an ip address that instagram suspects. which service are you using to host your flask server?

dvjhr commented 9 months ago

you must not use a global variable, it'll cause more troubles.

let me clearly describe what i mean:

1. create a login-only endpoint for the clients which they'll use only once to obtain the session data string. this endpoint should take username & password as argument and return `host.session_data` which is a string. clients will save this string and not generate a new one until it expires.

2. now, whenever they need to perform an authenticated request (say fetch profile, follow someone etc), they'll pass that `session_data` string which they previously obtained through either headers or cookies. the server will use this `session_data` to initialize `SessionHost` class.

3. now that the `SessionHost` class is initialized, you can use it normally as you would.

in short: you will create a login endpoint which accepts username & password and returns session_data string. clients must pass this string to use other authenticated endpoints.

Thanks for the patience and brief explanation. So if I may try again, should I store the session_data in a file just like the other's approach? https://github.com/diezo/Ensta/issues/54#issuecomment-1862504219 and https://github.com/diezo/Ensta/issues/42#issuecomment-1837131793 (which is actually identical with what you stated here 🙂), wish me luck on trying

dvjhr commented 9 months ago

now talking about the login error that you're facing...

are you using a strong pasword? checkpoint is usually required only when you're using a weak password.

other reason might be that you're using a hosting service which uses an ip address that instagram suspects. which service are you using to host your flask server?

This account that I use is created with selenium script with its username is 13 lowercase letters and the password is 12 mixed lower upper case letters and numbers. For the deployment, I use VPS provided by my workplace

diezo commented 9 months ago

So if I may try again, should I store the session_data in a file just like the other's approach? #54 (comment) and #42 (comment)

yes, you can store it anywhere (including a file, local database etc) on the client side.

because what i meant was to not store it on the server side but rather require the clients to store it on their own side locally.

diezo commented 9 months ago

This account that I use is created with selenium script with its username is 13 lowercase letters and the password is 12 mixed lower upper case letters and numbers. For the deployment, I use VPS provided by my workplace

hmm.. have you tried logging in with any other accounts? does the issue still persist or is it only a problem with that specific account you created with selenium?

dvjhr commented 9 months ago

This account that I use is created with selenium script with its username is 13 lowercase letters and the password is 12 mixed lower upper case letters and numbers. For the deployment, I use VPS provided by my workplace

hmm.. have you tried logging in with any other accounts? does the issue still persist or is it only a problem with that specific account you created with selenium?

I just tried this, and it finally worked as intended. However, this required me to obtain session data first from my local machine or another system. Thank you for you guidance 🙏

diezo commented 9 months ago

glad i could help. please do give this repository a star so that other developers can know about ensta as well.

thank you