我有一个tableau 10.0服务器。我在https://example.com/views/SomeReport/Totals
有一个观点。在浏览器中,如果我导航到https://example.com/views/SomeReport/Totals.csv
,系统会提示我登录,然后将视图作为csv文件下载。
我试图使用python
下载同一个文件详细
以下是我的尝试:
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
下载文件的其他方法持开放态度答案 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,这将非常有帮助。