【问题标题】:Download csv file from https tableau server with python using request and basic authentication使用请求和基本身份验证从带有 python 的 https 画面服务器下载 csv 文件
【发布时间】:2019-02-01 01:27:25
【问题描述】:

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

我正在尝试使用 python 下载相同的文件

详情

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

这是我尝试过的:

        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

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

这适用于普通网页,但在点击 url 提示文件下载时不起作用。如何通过文件下载实现此功能?

注意我对使用 python 下载文件的其他方法持开放态度

【问题讨论】:

  • 状态码 401 表示未经授权(身份验证失败时也是如此)...您确定用户名和密码正确吗?
  • @jatinderjit 肯定的,我直接从代码中复制它们并粘贴到网络表单中,直接进入,没问题
  • 您可以使用 Chrome 或 Firefox 中的 DevTools 来查看浏览器向服务器发送的内容。也许它会发送外部数据、cookie、加密密码等。
  • @furas 我在开发工具中看不到它,因为它下载的文件不是实际页面,但这让我思考。如果我从路径中删除.csv,它会起作用并且我会得到实际的页面。但我需要的不是表格仪表板中的 html 文件
  • @DelightedD0D HTTP live headers 是不错的工具,但如果您不先注销,它不会显示信息。

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


【解决方案1】:

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

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

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

【讨论】:

  • 听起来很合理,即使当我使用仪表板页面 url 时,基本身份验证按预期工作,这是否成立?
  • @DelightedD0D 我认为在这种情况下,除了我所描述的之外,还发生了其他事情。您可能想要检查服务器返回的所有信息。也许响应正文中有更多信息?我会尝试尽可能接近地模拟 Chrome 向 Tableau 发出的请求并且哪个有效 - 这意味着标题、查询参数等,看看是否有效
【解决方案2】:

Tableau 公开了一个 REST API,您可以使用它来下载 csv 文件。 API 端点是https://MY-SERVER/api/VERSION_NUM/auth/signin,其中VERSION_NUM 取决于Tableau Server 的版本,API 版本和Tableau Server 版本的映射可以在here 中找到。要使身份验证成功运行,您需要使用上述 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>

如果有人能指导我如何获取文本/csv 响应而不是 html,那将非常有帮助。

【讨论】:

  • 最后,我使用了 tabcmd 命令行实用程序和一个与之对话并处理所有身份验证和文件的 python 包。
  • @DelightedD0D:是的!我也做了同样的事情
  • @Delighted 我想下载一个视图的完整数据集,而不仅仅是摘要数据。 Populate_csv 仅适用于汇总数据。你有什么建议吗?
  • @PyRar 抱歉,我只为这个项目使用过它,并没有涉足类似的事情
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-08-25
  • 1970-01-01
  • 2019-01-12
  • 1970-01-01
  • 2013-10-06
  • 1970-01-01
相关资源
最近更新 更多