def user_info_gql(self, user_id: str) -> User: """ Get user object from user id Parameters ---------- user_id: str User id of an instagram account Returns ------- User An object of User type """ user_id = str(user_id) try: # GraphQL haven't method to receive user by id return self.user_info_by_username_gql( self.username_from_user_id_gql(user_id)) except JSONDecodeError as e: raise ClientJSONDecodeError(e, user_id=user_id)
def _send_private_request( self, endpoint, data=None, params=None, login=False, with_signature=True, headers=None, extra_sig=None, ): self.last_response = None self.last_json = last_json = {} # for Sentry context in traceback self.private.headers.update(self.base_headers) if headers: self.private.headers.update(headers) if not login: time.sleep(self.request_timeout) if self.user_id and login: raise Exception(f"User already login ({self.user_id})") try: if not endpoint.startswith('/'): endpoint = f"/v1/{endpoint}" api_url = f"https://{config.API_DOMAIN}/api{endpoint}" if data: # POST # Client.direct_answer raw dict # data = json.dumps(data) if with_signature: # Client.direct_answer doesn't need a signature data = generate_signature(json.dumps(data)) if extra_sig: data += "&".join(extra_sig) response = self.private.post(api_url, data=data, params=params) else: # GET response = self.private.get(api_url, params=params) self.logger.debug("private_request %s: %s (%s)", response.status_code, response.url, response.text) self.request_log(response) self.last_response = response response.raise_for_status() # last_json - for Sentry context in traceback self.last_json = last_json = response.json() self.logger.debug("last_json %s", last_json) except JSONDecodeError as e: self.logger.error( "Status %s: JSONDecodeError in private_request (user_id=%s, endpoint=%s) >>> %s", response.status_code, self.user_id, endpoint, response.text, ) raise ClientJSONDecodeError( "JSONDecodeError {0!s} while opening {1!s}".format( e, response.url), response=response, ) except requests.HTTPError as e: try: self.last_json = last_json = response.json() except JSONDecodeError: pass message = last_json.get("message", "") if e.response.status_code == 403: if message == "login_required": raise LoginRequired(response=e.response, **last_json) raise ClientForbiddenError(e, response=e.response, **last_json) elif e.response.status_code == 400: error_type = last_json.get("error_type") if message == "challenge_required": raise ChallengeRequired(**last_json) elif message == "feedback_required": raise FeedbackRequired(**dict( last_json, message="%s: %s" % (message, last_json.get("feedback_message")), )) elif error_type == "sentry_block": raise SentryBlock(**last_json) elif error_type == "rate_limit_error": raise RateLimitError(**last_json) elif error_type == "bad_password": raise BadPassword(**last_json) elif "Please wait a few minutes before you try again" in message: raise PleaseWaitFewMinutes(e, response=e.response, **last_json) elif "VideoTooLongException" in message: raise VideoTooLongException(e, response=e.response, **last_json) elif error_type or message: raise UnknownError(**last_json) # TODO: Handle last_json with {'message': 'counter get error', 'status': 'fail'} self.logger.exception(e) self.logger.warning( "Status 400: %s", message or "Empty response message. Maybe enabled Two-factor auth?") raise ClientBadRequestError(e, response=e.response, **last_json) elif e.response.status_code == 429: self.logger.warning("Status 429: Too many requests") if "Please wait a few minutes before you try again" in message: raise PleaseWaitFewMinutes(e, response=e.response, **last_json) raise ClientThrottledError(e, response=e.response, **last_json) elif e.response.status_code == 404: self.logger.warning("Status 404: Endpoint %s does not exists", endpoint) raise ClientNotFoundError(e, response=e.response, **last_json) elif e.response.status_code == 408: self.logger.warning("Status 408: Request Timeout") raise ClientRequestTimeout(e, response=e.response, **last_json) raise ClientError(e, response=e.response, **last_json) except requests.ConnectionError as e: raise ClientConnectionError( "{e.__class__.__name__} {e}".format(e=e)) if last_json.get("status") == "fail": raise ClientError(response=response, **last_json) elif "error_title" in last_json: """Example: { 'error_title': 'bad image input extra:{}', <------------- 'media': { 'device_timestamp': '1588184737203', 'upload_id': '1588184737203' }, 'message': 'media_needs_reupload', <------------- 'status': 'ok' <------------- }""" raise ClientError(response=response, **last_json) return last_json
def _send_public_request(self, url, data=None, params=None, headers=None, return_json=False): self.public_requests_count += 1 if headers: self.public.headers.update(headers) if self.request_timeout: time.sleep(self.request_timeout) try: if data is not None: # POST response = self.public.data(url, data=data, params=params) else: # GET response = self.public.get(url, params=params) expected_length = int(response.headers.get("Content-Length") or 0) actual_length = response.raw.tell() if actual_length < expected_length: raise ClientIncompleteReadError( "Incomplete read ({} bytes read, {} more expected)".format( actual_length, expected_length), response=response, ) self.request_logger.debug("public_request %s: %s", response.status_code, response.url) self.request_logger.info( "[%s] [%s] %s %s", self.public.proxies.get("https"), response.status_code, "POST" if data else "GET", response.url, ) self.last_public_response = response response.raise_for_status() if return_json: self.last_public_json = response.json() return self.last_public_json return response.text except JSONDecodeError as e: if "/login/" in response.url: raise ClientLoginRequired(e, response=response) self.request_logger.error( "Status %s: JSONDecodeError in public_request (url=%s) >>> %s", response.status_code, response.url, response.text, ) raise ClientJSONDecodeError( "JSONDecodeError {0!s} while opening {1!s}".format(e, url), response=response, ) except requests.HTTPError as e: if e.response.status_code == 403: raise ClientForbiddenError(e, response=e.response) if e.response.status_code == 400: raise ClientBadRequestError(e, response=e.response) if e.response.status_code == 429: raise ClientThrottledError(e, response=e.response) if e.response.status_code == 404: raise ClientNotFoundError(e, response=e.response) raise ClientError(e, response=e.response) except requests.ConnectionError as e: raise ClientConnectionError("{} {}".format(e.__class__.__name__, str(e)))