【问题标题】:Access Lovoo API using Python使用 Python 访问 Lovoo API
【发布时间】:2017-07-01 23:24:48
【问题描述】:

我希望使用 lovoo API,但不知道如何开始。运行Charles代理,查看流量后,得出以下结论:

首先,只要用户通过应用程序 (iPhone) 登录,就会发送 GEThttps://api.lovoo.com/oauth/requestToken?

    GET /oauth/requestToken? HTTP/1.1
Host    api.lovoo.com
User-Agent  LOVOO/612 (iPhone; iOS 10.2; Scale/3.00)
kissapi-app-idfv    1EC7A8E5-DF16-4E14-8EC9-98DD4772F903
tz  Europe/xxx
kissapi-device-model    iPhone 6s Plus
kissapi-app-version 3.17.0
kissapi-new-oauth   1
kissapi-device  iphone
kissapi-app lovoo
wifi    true
kissapi-adv-id  00000000-0000-0000-0000-000000000000
Connection  keep-alive
kissapi-app-id  7F947A460DAFCA88556B2F35A6D78A3E
Authorization   OAuth oauth_callback="oob", oauth_consumer_key="an.email%40gmail.com", oauth_nonce="A32CCA91-FB7A-4AA3-8314-0A9A6E67045E", oauth_signature="Sq8KTg%2FhVIGBaWgWXprPluczOs4%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1487017515", oauth_version="1.0"
Accept-Language en-CH;q=1, de-CH;q=0.9
kissapi-adv-on  false
kissapi-version 1.20.0
kissapi-update-user-hash    6ea2bd15ea41d0dc8c2615589e2d52ec
Accept  */*
kissapi-device-os   10.2
Accept-Encoding gzip, deflate
kissapi-sync-enabled    1

这也给出了以下令牌:oauth_token=44d83e8ef50f&oauth_token_secret=37998f6c6ef2e618

这之后是另一个GEThttps://api.lovoo.com/oauth/accessToken?

GET /oauth/accessToken? HTTP/1.1
Host    api.lovoo.com
User-Agent  LOVOO/612 (iPhone; iOS 10.2; Scale/3.00)
kissapi-app-idfv    1EC7A8E5-DF16-4E14-8EC9-98DD4772F903
tz  Europe/xxx
kissapi-device-model    iPhone 6s Plus
kissapi-app-version 3.17.0
kissapi-new-oauth   1
kissapi-device  iphone
kissapi-app lovoo
wifi    true
kissapi-adv-id  00000000-0000-0000-0000-000000000000
Connection  keep-alive
kissapi-app-id  7F947A460DAFCA88556B2F35A6D78A3E
Authorization   OAuth oauth_consumer_key="an.email%40gmail.com", oauth_nonce="080328C9-0A53-4971-85E7-65A43F12DC09", oauth_signature="Km0vd8xtHaQmRgkrGLsiljel13o%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1487017515", oauth_token="44d83e8ef50f", oauth_version="1.0"
Accept-Language en-CH;q=1, de-CH;q=0.9
kissapi-adv-on  false
kissapi-version 1.20.0
kissapi-update-user-hash    6ea2bd15ea41d0dc8c2615589e2d52ec
Accept  */*
kissapi-device-os   10.2
Accept-Encoding gzip, deflate
kissapi-sync-enabled    1

并提供以下令牌:oauth_token=60c8977c8fe9509f&oauth_token_secret=549619c0ef4c4be7d7cb898e

现在,可以向https://api.lovoo.com/init 发出请求:

GET /init HTTP/1.1
Host    api.lovoo.com
User-Agent  LOVOO/612 (iPhone; iOS 10.2; Scale/3.00)
kissapi-app-idfv    1EC7A8E5-DF16-4E14-8EC9-98DD4772F903
tz  Europe/xxx
kissapi-device-model    iPhone 6s Plus
kissapi-app-version 3.17.0
kissapi-new-oauth   1
kissapi-device  iphone
kissapi-app lovoo
wifi    true
kissapi-adv-id  00000000-0000-0000-0000-000000000000
Connection  keep-alive
kissapi-app-id  7F947A460DAFCA88556B2F35A6D78A3E
Authorization   OAuth oauth_consumer_key="an.email%40gmail.com", oauth_nonce="B622CE9C-DA3D-435C-939A-C58B83DBE85C", oauth_signature="0irvAsilrrdCCdLfu%2F0XSj7THlc%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1487017515", oauth_token="60c8977c8fe9509f", oauth_version="1.0"
Accept-Language en-CH;q=1, de-CH;q=0.9
kissapi-adv-on  false
kissapi-version 1.20.0
kissapi-update-user-hash    6ea2bd15ea41d0dc8c2615589e2d52ec
Accept  */*
kissapi-device-os   10.2
Accept-Encoding gzip, deflate
kissapi-sync-enabled    1

这些是我捕获的标头,但我不知道如何发送它们并让Oauth 身份验证正常工作,尤其是oauth_nonce

requests-oauthlib好像支持,但是不知道哪个token对应哪个变量:

from requests_oauthlib import OAuth1Session

lovoo = OAuth1Session(
    'client_key',
    client_secret='client_secret',
    resource_owner_key='resource_owner_key',
    resource_owner_secret='resource_owner_secret'
)
url = 'https://api.lovoo.com/init'
r = lovoo.get(url)

【问题讨论】:

  • Nonce 由客户端生成,它是随机的,您可能必须匹配预期的格式。您可能需要在 2 次调用中提供相同的随机数。请参阅en.wikipedia.org/wiki/Cryptographic_nonce 似乎这里有 2 个 nonce 值——一个由客户端创建,另一个由服务器创建。
  • OAuth 密钥/秘密呢?
  • 您现在知道如何访问 API 了吗?
  • @Kelvin 这篇文章专门关于访问移动 API 并使用它模拟 iPhone。我已经设法使用请求使用 WebAPI 登录到 Lovoo。提出一个新问题,标记我,我会帮助你。我不想发布整个脚本,因为他们可能会再次更改登录方法。
  • @rhillhouse,你能写出这个问题的答案吗?只是总结一下你的发现和你的解决方案

标签: python python-3.x oauth python-requests


【解决方案1】:

另一种方法是使用 selenium 登录并进一步使用带有请求的会话。

例如

def login(user, pw):
    chrome_options = Options()
    chrome_options.add_experimental_option("detach", True)
    driver = webdriver.Chrome(options=chrome_options)
    driver.get("https://www.lovoo.com/login_check")
    user_agent = driver.execute_script("return navigator.userAgent;")
    iframe = driver.find_element(By.ID,"gdpr-consent-notice")
    driver.switch_to.frame(iframe)
    privacybutton = WebDriverWait(driver, 10).until(
        EC.presence_of_element_located((By.XPATH,"//b[contains(text(),'Accept All')]"))
    )
    privacybutton.click()
    driver.switch_to.default_content()
    loginbutton = WebDriverWait(driver, 4).until(
        EC.presence_of_element_located((By.XPATH, "//button[contains(text(),'Log in')]"))
    )
    loginbutton.click()
    loginbutton2=WebDriverWait(driver, 4).until(
        EC.presence_of_element_located((By.XPATH, "//button[contains(@data-automation-id,'login-submit-button')]"))
    )
    driver.find_element(By.XPATH, '//input[@name="authEmail"]').send_keys(user)
    driver.find_element(By.XPATH, '//input[@name="authPassword"]').send_keys(pw)
    webdriver.ActionChains(driver).move_to_element(loginbutton2).click(loginbutton2).perform()
    element = WebDriverWait(driver, 10).until(
        EC.presence_of_element_located((By.ID, "topmenu"))
    )
    return user_agent, driver.get_cookies()
(lat,lon)=(0.0,0.0)
with requests.Session() as session:
    user_agent, cookies = login(user, pw)
    session.cookies.update({c['name']: c['value'] for c in cookies})
    session.headers.update({'User-Agent': user_agent})
    session.get(f'https://www.lovoo.com/api_web.php/users?ageFrom=0&ageTo=2&latitude={lat}&longitude={lon}')

【讨论】:

    【解决方案2】:

    Lovoo 正在使用 OAuth 1 协议 (https://tools.ietf.org/html/draft-hammer-oauth-10)。

    我以前使用过 Lovoo API。我可以说的一件事是,您的帐户很快就会受到他们的 BOT 检测算法的限制。我没有尝试使用不同的 HTTP 标头组合。因此,这可能值得一试。

    不过,我在 Github 上发布了my work 供其他人尝试。您可以在下面找到进行 API 调用所需的函数。要查看如何使用这些函数的一些示例,请查看上述 repo。

    import urllib.parse
    
    
    # MD5 hashing of an input string
    def md5(data: str):
        import hashlib
        return hashlib.md5(data.encode('utf-8')).hexdigest()
    
    
    def normalize_params(params: dict):
        # Comply with https://tools.ietf.org/html/draft-hammer-oauth-10
        # params must be sorted alphabetically first by keys and then values
        params = dict(sorted(params.items(), key=lambda x: (x[0], x[1]), reverse=False))
        p_encoded = '&'.join(
            ["{}={}".format(urllib.parse.quote_plus(k), urllib.parse.quote_plus(v)) for k, v in params.items() if v != ''])
        # Percent encode
        p_quoted = urllib.parse.quote_plus(p_encoded)
        return p_quoted
    
    
    def generate_base_string(params: str, url: str, method: str = 'GET'):
        # Comply with https://tools.ietf.org/html/draft-hammer-oauth-10
        base_str = method + '&' + urllib.parse.quote_plus(url) + '&' + params
        return base_str
    
    
    # Secret hashing used in Lovoo
    def secret_hash(pwd: str) -> str:
        pwd = md5("SALTforPW" + pwd)
        return md5("SALTforSecret" + pwd)
    
    
    def sign_request(client_identifier: str, client_secret: str, token: str, token_secret: str, url: str, nounce: str,
                     timestamp: str, method: str = 'GET', payload: dict = None, callback_url: str = '', oauth_version: str = '1.0'):
        from hashlib import sha1
        import hmac
        import base64
    
        params = {
            'oauth_callback': callback_url,
            'oauth_consumer_key': client_identifier,
            'oauth_nonce': nounce,
            'oauth_signature_method': 'HMAC-SHA1',
            'oauth_timestamp': timestamp,
            'oauth_token': token,
            'oauth_version': oauth_version
        }
    
        # Normalize parameters
        if payload is not None:
            params = {**params, **payload}
        np = normalize_params(params)
        # Generate base string
        base_string = generate_base_string(np, url, method)
    
        if token != '':
            key = (f"{client_secret}&{token_secret}").encode()
        else:
            key = (client_secret + '&').encode()
    
        raw = base_string.encode()
    
        hashed = hmac.new(key, raw, sha1)
    
        # The signature
        return base64.b64encode(hashed.digest()).decode().rstrip('\n')
    

    请注意,我测试该代码已经有一段时间了,Lovoo 的 API 可能会有一些变化。如果它不起作用,请告诉我,我会看看。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-15
      • 2017-11-08
      • 2017-10-21
      • 1970-01-01
      相关资源
      最近更新 更多