Exemple #1
0
    def __init__(self, rhx_gis='', sessionid='', proxies=[]):
        self.last_response = {}
        proxy_configration = {
            'default': None,
            'proxies': proxies,
            'paths': {
                '/query': 100
            }
        }
        self.gql_api = AnyAPI(self._BASE_URL,
                              default_headers={
                                  'user-agent': self._USER_AGENT,
                                  'cookie': f'sessionid={sessionid}',
                              },
                              proxy_configration=proxy_configration,
                              scoped_call=self._raise_rate_limit_connreset)
        if not rhx_gis:
            rhx_gis = self._get_shared_data()['rhx_gis']
        self.rhx_gis = rhx_gis

        self.gql_api._filter_headers.append(self._set_instagram_gis)
        self.gql_api._filter_response.append(self._raise_rate_limit_exceed)
        self.gql_api._filter_response.append(self._raise_media_not_found)
        self.gql_api._filter_response.append(self._raise_user_not_found)
        self.gql_api._filter_response.append(self._raise_hashtag_not_found)
        self.gql_api._filter_response.append(self._raise_location_not_found)
Exemple #2
0
def test_scoped_call():
    exception = []

    httpbin = AnyAPI(
        "http://httpbin.org",
        scoped_calls=[lambda request: parent_call(request, exception)],
    )
    httpbin.GET(timeout=1e-10)

    assert isinstance(exception[0], ConnectTimeout)
Exemple #3
0
def test_retry():
    """Test retry utility"""
    # I know that I should test retry and retry_until separately
    # But I couldn't find any idea to test retry_until separately
    try:
        invalid_api = AnyAPI("invalidurl", scoped_calls=[retry(2)])
        invalid_api.GET()
    except MissingSchema:
        assert True
    else:
        assert False
Exemple #4
0
    def __init__(self, rhx_gis="", sessionid="", proxies=[], max_retries=3):
        self.last_response = {}
        self.max_retries = max_retries

        self.api = AnyAPI(
            constants.BASE_URL,
            default_headers={
                "user-agent": constants.USER_AGENT,
                "cookie": f"sessionid={sessionid}",
            },
            scoped_call=self.__retry,
            **({
                "proxy_configuration": {
                    "default": None,
                    "proxies": proxies,
                    "paths": {
                        "/query": 100
                    },
                },
                "proxy_handler": RateLimitProxy,
            } if proxies else {}),
        )

        self.api._filter_response = [
            InstagramGraphQL.__rate_limit_exceed,
            InstagramGraphQL.__user_not_found,
            InstagramGraphQL.__hashtag_not_found,
            InstagramGraphQL.__location_not_found,
            InstagramGraphQL.__set_as_json,
            InstagramGraphQL.__media_not_found,
            self.__set_last_response,
        ]

        self.api._filter_request.append(
            lambda kwargs: set_instagram_gis(kwargs, rhx_gis))
from oauth2client.client import flow_from_clientsecrets
from requests_oauth2 import OAuth2BearerToken
from anyapi import AnyAPI

flow = flow_from_clientsecrets(
    'client_secrets.json',
    scope='user-read-email',
    redirect_uri='http://localhost/callback')
print(flow.step1_get_authorize_url())  # Open url in your browser

code = input('Code: ')  # http://localhost/callback?code={CODE}
credentials = flow.step2_exchange(code)

spotify_api = AnyAPI(
    'https://api.spotify.com/v1',
    default_auth=OAuth2BearerToken(credentials.access_token))
print(spotify_api.me.GET().json())
Exemple #6
0
class InstagramGraphQL:
    _IG_URL = 'https://www.instagram.com'
    _BASE_URL = f'{_IG_URL}/graphql/'
    _QUERY_HASHES = {
        'get_media': '49699cdb479dd5664863d4b647ada1f7',
        'load_more_comments': 'f0986789a5c5d17c2400faebf16efd0d',
        'load_liked_by': 'e0f59e4a1c8d78d0161873bc2ee7ec44',
        'load_more_timeline_media': 'e6a78c2942f1370ea50e04c9a45ebc44',
        'load_more_hashtag_recent_media': 'f92f56d47dc7a55b606908374b43a314',
        'load_more_location_recent_media': '1b84447a4d8b6d6d0426fefb34514485',
    }
    _USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
    ' (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'
    _FORBIDDEN_USERNAMES = ['graphql', 'explore']

    def __init__(self, rhx_gis='', sessionid='', proxies=[]):
        self.last_response = {}
        proxy_configration = {
            'default': None,
            'proxies': proxies,
            'paths': {
                '/query': 100
            }
        }
        self.gql_api = AnyAPI(self._BASE_URL,
                              default_headers={
                                  'user-agent': self._USER_AGENT,
                                  'cookie': f'sessionid={sessionid}',
                              },
                              proxy_configration=proxy_configration,
                              scoped_call=self._raise_rate_limit_connreset)
        if not rhx_gis:
            rhx_gis = self._get_shared_data()['rhx_gis']
        self.rhx_gis = rhx_gis

        self.gql_api._filter_headers.append(self._set_instagram_gis)
        self.gql_api._filter_response.append(self._raise_rate_limit_exceed)
        self.gql_api._filter_response.append(self._raise_media_not_found)
        self.gql_api._filter_response.append(self._raise_user_not_found)
        self.gql_api._filter_response.append(self._raise_hashtag_not_found)
        self.gql_api._filter_response.append(self._raise_location_not_found)

    def get_media(self, shortcode):
        params = {
            'query_hash':
            self._QUERY_HASHES['get_media'],
            'variables':
            json.dumps(
                {
                    'shortcode': shortcode,
                    'child_comment_count': 0,
                    'fetch_comment_count': 40,
                    'parent_comment_count': 0,
                    'has_threaded_comments': False
                },
                separators=(',', ':'))
        }

        self.last_response = self.gql_api.query.GET(
            params=params).json()['data']['shortcode_media']

        return Media(self.last_response, self)

    def get_user(self, username, fetch_data=False):
        self.last_response = self._get_shared_data(
            username)['entry_data']['ProfilePage'][0]['graphql']['user']

        return User(self.last_response, self, fetch_data=fetch_data)

    def get_hashtag(self, name, fetch_data=False):
        self.last_response = self._get_shared_data(f'explore/tags/{name}/')[
            'entry_data']['TagPage'][0]['graphql']['hashtag']

        return Hashtag(self.last_response, self, fetch_data=False)

    def get_location(self, location_id, fetch_data=False):
        self.last_response = self._get_shared_data(
            f'explore/locations/{location_id}/'
        )['entry_data']['LocationsPage'][0]['graphql']['location']

        return Location(self.last_response, self, fetch_data=False)

    def search(self, query):
        return self.gql_api.GET(
            url='https://www.instagram.com/web/search/topsearch/',
            params={
                'query': query
            }).json()

    def _get_shared_data(self, path='instagram'):
        self.last_response = self.gql_api.GET(url=f'{self._IG_URL}/{path}')
        self.last_response = self.last_response.text.split(
            'window._sharedData = ')[1]
        self.last_response = self.last_response.split(';</script>')[0]
        self.last_response = json.loads(self.last_response)

        return self.last_response

    def _set_instagram_gis(self, params, headers, **kwargs):
        if not params.get('variables'): return headers
        return {
            **headers, 'x-instagram-gis':
            md5((self.rhx_gis + ':' +
                 params['variables']).encode()).hexdigest()
        }

    def _raise_rate_limit_exceed(self, response, **kwargs):
        if response.status_code == 429 and response.json(
        )['message'] == 'rate limited':
            raise RateLimitExceed('Rate limit exceed!')

        return response

    def _raise_media_not_found(self, response, params, **kwargs):
        if response.status_code == 200 and params.get(
                'query_hash'
        ) == self._QUERY_HASHES['get_media'] and not response.json(
        )['data'].get('shortcode_media'):
            raise NotFound('Media not found!')

        return response

    def _raise_user_not_found(self, response, url, path, **kwargs):
        if response.status_code == 404 and path.split(
                '/')[1] not in self._FORBIDDEN_USERNAMES:
            raise NotFound('User not found!')

        return response

    def _raise_hashtag_not_found(self, response, path, **kwargs):
        if response.status_code == 404 and path.startswith('/explore/tags/'):
            raise NotFound('Hashtag not found!')

        return response

    def _raise_location_not_found(self, response, path, **kwargs):
        if response.status_code == 404 and path.startswith(
                '/explore/locations/'):
            raise NotFound('Location not found!')

        return response

    def _raise_rate_limit_connreset(self, request):
        try:
            return request()
        except ChunkedEncodingError:
            raise RateLimitExceed('Rate limit exceed!')
Exemple #7
0
def test_params():
    """Test passing params to Session"""
    httpbin = AnyAPI("http://httpbin.org", auth=("user", "password"))

    assert httpbin("basic-auth").user.password.GET().json()["authenticated"]
Exemple #8
0
def test_passing_url():
    """Test passing URL directly"""
    httpbin = AnyAPI("http://httpbin.org")

    assert (httpbin.GET(url="http://httpbin.org/anything").json()["url"] ==
            "https://httpbin.org/anything")
Exemple #9
0
def httpbin():
    return AnyAPI("http://httpbin.org")