在巨蟒请求中处理磅符号 (#)

共3个回答, 标签: python python-requests

我正在使用请求来编译自定义 URL, 其中一个参数包含磅符号。任何人都可以解释如何在不对磅符号进行编码的情况下传递参数吗?

这将返回正确的 CSV 文件

results_url = 'https://baseballsavant.mlb.com/statcast_search/csv?all=true&hfPT=&hfAB=&hfBBT=&hfPR=&hfZ=&stadium=&hfBBL=&hfNewZones=&hfGT=R%7C&hfC=&hfSea=2019%7C&hfSit=&player_type=batter&hfOuts=&opponent=&pitcher_throws=&batter_stands=&hfSA=&game_date_gt=&game_date_lt=&hfInfield=&team=&position=&hfOutfield=&hfRO=&home_road=&hfFlag=&hfPull=&metric_1=&hfInn=&min_pitches=0&min_results=0&group_by=name&sort_col=pitches&player_event_sort=h_launch_speed&sort_order=desc&min_abs=0&type=#results'
results = requests.get(results_url, timeout=30).content
results_df = pd.read_csv(io.StringIO(results.decode('utf-8')))

这不

URL = 'https://baseballsavant.mlb.com/statcast_search/csv?'

def _get_statcast(params):

     _get = get(URL, params=params, timeout=30)
     _get.raise_for_status()
     return _get.content

问题似乎是, 当通过请求传递 "#results" 时, "#" 之后会被忽略, 导致下载错误的 CSV。如果有人对其他方法有想法, 我会很感激的。

编辑 2: 也在巨蟒论坛上问这个问题 https://python-forum.io/Thread-Handling-pound-sign-within-custom-URL?pid=75946#pid75946

第1个答案

基本上, URL 中的文字符号后的任何内容都不会发送到服务器。这适用于浏览器和 requests

URL 的格式表明 type=#results 部件实际上是一个查询参数。

requests将自动对查询参数进行编码, 而浏览器则不会。以下是各种查询以及服务器在每种情况下接收的内容:


浏览器中的 URL 参数

在浏览器中使用磅符号时, 池塘符号后的任何内容都不会发送到服务器:

https://httpbin.org/anything/type=#results

返回:

{
  "args": {},
  "data": "",
  "files": {},
  "form": {},
  "headers": {
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3",
    "Accept-Encoding": "gzip, deflate, br",
    "Accept-Language": "en-GB,en;q=0.9,en-US;q=0.8,de;q=0.7",
    "Cache-Control": "max-age=0",
    "Host": "httpbin.org",
    "Upgrade-Insecure-Requests": "1",
    "User-Agent": "*redacted*"
  },
  "json": null,
  "method": "GET",
  "origin": "*redacted*",
  "url": "https://httpbin.org/anything/type="
}
  • 服务器接收的 URL 是 https://httpbin.org/anything/type=
  • 被请求的页面被调用, type= 这似乎是不正确的。

浏览器中的查询参数

=格式表明它可能是您正在传递的查询参数。但是, 在磅符号之后的任何内容都不会发送到服务器:

https://httpbin.org/anything?type=#results

返回:

{
  "args": {
    "type": ""
  },
  "data": "",
  "files": {},
  "form": {},
  "headers": {
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3",
    "Accept-Encoding": "gzip, deflate, br",
    "Accept-Language": "en-GB,en;q=0.9,en-US;q=0.8,de;q=0.7",
    "Host": "httpbin.org",
    "Upgrade-Insecure-Requests": "1",
    "User-Agent": "*redacted*"
  },
  "json": null,
  "method": "GET",
  "origin": "*redacted*",
  "url": "https://httpbin.org/anything?type="
}
  • 服务器接收的 URL 是 https://httpbin.org/anything?type=
  • 调用所请求的页面 anything
  • type接收没有值的参数。

浏览器中的编码查询参数

https://httpbin.org/anything?type=%23results

返回:

{
  "args": {
    "type": "#results"
  },
  "data": "",
  "files": {},
  "form": {},
  "headers": {
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3",
    "Accept-Encoding": "gzip, deflate, br",
    "Accept-Language": "en-GB,en;q=0.9,en-US;q=0.8,de;q=0.7",
    "Host": "httpbin.org",
    "Upgrade-Insecure-Requests": "1",
    "User-Agent": "*redacted*"
  },
  "json": null,
  "method": "GET",
  "origin": "*redacted*",
  "url": "https://httpbin.org/anything?type=%23results"
}
  • 服务器接收的 URL 是 https://httpbin.org/anything?type=%23results
  • 调用所请求的页面 anything
  • type接收值为的参数 #results

带有 URL 参数的 Python 请求

requests也不会发送任何东西后, 磅符号到服务器:

import requests

r = requests.get('https://httpbin.org/anything/type=#results')
print(r.url)
print(r.json())

返回:

https://httpbin.org/anything/type=#results
{
    "args":
第2个答案

我只经历了一次试验, 但希望有一个解决方案。我没有通过 "#results", 而是开始了一个与基本 url + 所有其他参数的会话, 加入了 "#results", 然后运行它通过第二个 get。

statcast_url = 'https://baseballsavant.mlb.com/statcast_search/csv?'
results_url = '&type=#results&'

def _get_statcast_results(params):

    s = session()
    _get = s.get(statcast_url, params=params, timeout=30, allow_redirects=True)

    new_url = _get.url+results_url
    data = s.get(new_url, timeout=30)

    return data.content

还需要再经历一些考验, 但我认为这应该是可行的。感谢每一个插话的人。尽管我没有得到直接的答案, 但这些回答还是帮助了一吨。

第3个答案

Cloudomation 的答案提供了很多有趣的信息, 但我认为这可能不是你要找的。假设巨蟒论坛中的这个相同的线程也是由您编写的, 请继续阅读:

从您提供的信息来看, 似乎 type=#results 正在使用这些信息来筛选原始 csv并只返回部分数据。
如果是这种情况, type= 则该部件并不是真正必要的 (尝试没有它的 URL, 并看到您得到相同的结果)。

我会解释:

#URLS 中的符号称为片段标识符, 在不同类型的页面中, 它用于不同的目的。在 text/csv 页面中, 它用于按列、行或两者的某种组合筛选csv 表。你可以在这里阅读更多关于它的信息。

在您的情况下, results 可以是用于以自定义方式筛选 csv 表的查询参数。

遗憾的是, 如 Cloudomation 的答案所示,碎片数据在服务器端不可用, 因此您将无法以您尝试的方式通过巨蟒请求参数访问它。

您可以尝试按照此处的建议在 Javascript 中访问它, 或者只需下载整个 (未经筛选的) CSV 表并自己对其进行筛选。

在巨蟒中可以很容易、更有效地做到这一点。 请在此处查看更多信息, 或者如果您需要更多的控制, 您可以将 CSV 导入到熊猫数据框中。

编辑:

我看到您通过加入字符串并传递第二个请求找到了解决方法。由于这样做是有效的, 你可能会摆脱将参数转换为字符串的方法 (如这里所建议的)。如果它做了你所做的, 这将是一个更有效的, 也许稍微优雅一点的解决方案:

params = {'key1': 'value1', 'key2': 'value2'} // sample params dict

def _get_statcast_results(params):

    // convert params to string - alternatively you can  use %-formatting
    params_str = "&".join(f"{k}={v}" for k,v in payload.items())

    s = session()

    data = s.get(statcast_url, params = params_str, timeout=30)

    return data.content

相关问题

通过随机抽样其他列数据创建新列 如何使用熊猫获得包括每一个组合的计数 如何有效地展开矩阵的值与小块? 在巨蟒请求中处理磅符号 (#)