使用python使用请求和基本身份验证从https tableau服务器下载csv文件

时间:2016-10-17 11:07:30

标签: python python-requests basic-authentication tableau-server

我有一个tableau 10.0服务器。我在https://example.com/views/SomeReport/Totals有一个观点。在浏览器中,如果我导航到https://example.com/views/SomeReport/Totals.csv,系统会提示我登录,然后将视图作为csv文件下载。

我试图使用python

下载同一个文件

详细

  • tableau 10.0
  • python 2.7
  • 在Windows上运行的画面
  • python在mac OSX El capitan上运行

以下是我的尝试:

        tableau_file_path = '{tableau_path}{tableau_view}{file_ext}'.format(**cur_file)
        local_path = cur_file['local_path']
        user = 'xxxx'
        password = 'xxxx'

        # print tableau_file_path  # outputs https://example.com/views/SomeReport/Totals.csv
        # print local_path         # outputs ../generated_resources/Some Folder Name/Totals.csv 

        r = requests.get(tableau_file_path, auth=HTTPBasicAuth(user, password), stream=True, timeout=5)
        # also tried auth=(user, password)
        print r.status_code   # outputs 401
        if r.status_code == 200:
            with open(local_path, 'wb') as f: 
                f.write(r.content)

我觉得应该工作,但事实并非如此。我得到401状态

如果我从路径中移除.csv,它就能正常工作,我会获得实际的画面仪表板页面。但我需要csv文件而不是tableau仪表板中的html

我直接从我的代码中复制了用户名和密码,并将其粘贴到我浏览器中弹出的表单中,并且信用卡工作似乎排除了错误信用的问题。

这适用于普通网页,但在点击网址提示文件下载时不起作用。如何使用文件下载来完成这项工作?

注意我对使用python

下载文件的其他方法持开放态度

2 个答案:

答案 0 :(得分:1)

我会在这里说出Tableau没有进行HTTP基本身份验证,而是拥有自己的方法。因此,当您尝试通过请求访问该事物时,它拒绝它,因为它不知道如何认证。

当您以人的身份访问它时,它知道将您重定向到他们的登录页面并执行整个"登录流程"最后将您重定向到正确的下载页面。但是,请求尝试将自己清楚地标识为机器人,并使用特殊的UserAgent字符串(只是"请求"我相信),这就是服务器决定直接返回401的原因。

根据您的使用情况,您可以手动登录,并查看Tableau正在设置哪些Cookie,并将其包含在您的请求中。 您也可以将用户代理更改为浏览器(他们以&#34开头; Mozilla 5.0 /"绝大多数情况下),并查看是否下载了登录页面。如果是这种情况,您可以对其部分登录过程进行逆向工程 - 足以了解他们如何提交用户和密码,以及他们如何重定向到您想要的页面。在此之后,您很可能会使用该数据和所需的重定向对其登录基础结构进行POST。

答案 1 :(得分:1)

Tableau公开了一个REST API,可用于下载csv文件。 API端点为https://MY-SERVER/api/VERSION_NUM/auth/signin,其中VERSION_NUM取决于tableau服务器的版本,可以在here中找到API版本和Tableau Server版本的映射。为了使身份验证成功进行,您需要使用上述API端点获取令牌。然后,您可以在标头参数'X-tableau-auth'中传递此令牌。这是代码:

import requests, json
from config import USERNAME, PASSWORD, SERVER_NAME

# NOTE! Substitute your own values for the following variables
server_name = SERVER_NAME # Name or IP address of your installation of Tableau Server
user_name = USERNAME    # User name to sign in as (e.g. admin)
password = PASSWORD
site_url_id = ""          # Site to sign in to. An empty string is used to specify the default site.

signin_url = "http://{}/api/3.1/auth/signin".format(server_name)

csv_url = "https://{}/#/views/Test/Dash/A.csv".format(server_name)

payload = { "credentials": { "name": user_name, "password": password, "site": {"contentUrl": site_url_id }}}

headers = {
  'accept': 'text/csv,application/json',
  'content-type': 'application/json'
}

# Send the request to the server
req = requests.post(signin_url, json=payload, headers=headers)
req.raise_for_status()

# Get the response
response = json.loads(req.content)

# Parse the response JSON. The response body will look similar
# to the following example:
#
# {
#    "credentials": {
#        "site": {
#            "id": "xxxxxxxxxx-xxxx-xxxx-xxxxxxxxxx",
#            "contentUrl": ""
#        },
#        "user": {
#            "id": "xxxxxxxxxx-xxxx-xxxx-xxxxxxxxxx"
#        },
#         "token": "AUTH-TOKEN"
#    }
# }


# Get the authentication token from the <credentials> element
token = response["credentials"]["token"]

# Get the site ID from the <site> element
site_id = response["credentials"]["site"]["id"]

print('Sign in successful!')
print('\tToken: {token}'.format(token=token))
print('\tSite ID: {site_id}'.format(site_id=site_id))

# Set the authentication header using the token returned by the Sign In method.
headers['X-tableau-auth']=token


csv_req = requests.get(csv_url, headers=headers)
# ... Make other calls here ...

csv_req.raise_for_status() 
print(csv_req.status_code) #200

with open('something.csv', 'wb') as f:
  f.write(csv_req.content)

这通过了身份验证问题,但是我在响应中获取了页面源而不是CSV文件

页面来源:

<!DOCTYPE html><html xmlns:ng="" xmlns:tb=""><head ng-csp><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=1024, maximum-scale=2"><meta name="format-detection" content="telephone=no"><meta name="vizportal-config" data-buildId="6m6iytne3n8" data-staticAssetsUrlPrefix=""><link rel="stylesheet" type="text/css" href="vizportal.css?6m6iytne3n8"><script src="/javascripts/api/tableau-2.2.2.min.js?6m6iytne3n8"></script><script src="vizportalMinLibs.js?6m6iytne3n8"></script><script src="vizportal.min.js?6m6iytne3n8"></script></head><body class="tb-body"><div ng-app="VizPortalRun" id="ng-app" tb-window-resize class="tb-app"><div ui-view="" class="tb-app-inner"></div><tb:react-toaster></tb:react-toaster><script type="text/ng-template" id="inline_stackedElement.html"><div tb-window-resize tb-left="left" tb-top="top" tb-right="right" tb-bottom="bottom" tb-visible="visible" class="tb-absolute"></div></script><tb:stacked-elements></tb:stacked-elements></div></body></html>

如果有人可以指导我如何获得text / csv响应而不是html,这将非常有帮助。