I'm using requests to compile a custom URL and one parameter includes a pound sign. Can anyone explain how to pass the parameter without encoding the pound sign?
This returns the correct CSV file
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')))
This DOES NOT
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
The issue seems to be that when passing '#results' through requests anything after '#' gets ignored which causes the wrong CSV to be downloaded. If anyone has thoughts on other ways of going about this I would appreciate it.
EDIT2: Also asked this on the python forum https://python-forum.io/Thread-Handling-pound-sign-within-custom-URL?pid=75946#pid75946
Basically, anything after a literal pound-sign in the URL is not sent to the server. This applies to browsers and requests.
The format of your URL suggests that the type=#results part is actually a query parameter.
requests will automatically encode the query parameters, while the browser won't. Below are various queries and what the server receives in each case:
When using the pound-sign in the browser, anything after the pond-sign is not sent to the server:
https://httpbin.org/anything/type=#results
Returns:
{
"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="
}
https://httpbin.org/anything/type=.type= which does not seem to be correct.The <key>=<value> format suggest it might be a query parameter which you are passing. Still, anything after the pound-sign is not sent to the server:
https://httpbin.org/anything?type=#results
Returns:
{
"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="
}
https://httpbin.org/anything?type=.anything.type without a value is received.https://httpbin.org/anything?type=%23results
Returns:
{
"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"
}
https://httpbin.org/anything?type=%23results.anything.type with a value of #results is received.requests will also not send anything after the pound-sign to the server:
import requests
r = requests.get('https://httpbin.org/anything/type=#results')
print(r.url)
print(r.json())
Returns:
https://httpbin.org/anything/type=#results
{
"args": {},
"data": "",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"Host": "httpbin.org",
"User-Agent": "python-requests/2.21.0"
},
"json": null,
"method": "GET",
"origin": "*redacted*",
"url": "https://httpbin.org/anything/type="
}
https://httpbin.org/anything?type=.anything.type without a value is received.requests automatically encodes query parameters:
import requests
r = requests.get('https://httpbin.org/anything', params={'type': '#results'})
print(r.url)
print(r.json())
Returns:
https://httpbin.org/anything?type=%23results
{
"args": {
"type": "#results"
},
"data": "",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"Host": "httpbin.org",
"User-Agent": "python-requests/2.21.0"
},
"json": null,
"method": "GET",
"origin": "*redacted*",
"url": "https://httpbin.org/anything?type=%23results"
}
https://httpbin.org/anything?type=%23results.anything.type with a value of #results is received.If you manually encode the query parameter and then pass it to requests, it will encode the already encoded query parameter again:
import requests
r = requests.get('https://httpbin.org/anything', params={'type': '%23results'})
print(r.url)
print(r.json())
Returns:
https://httpbin.org/anything?type=%23results
{
"args": {
"type": "%23results"
},
"data": "",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"Host": "httpbin.org",
"User-Agent": "python-requests/2.21.0"
},
"json": null,
"method": "GET",
"origin": "*redacted*",
"url": "https://httpbin.org/anything?type=%2523results"
}
https://httpbin.org/anything?type=%2523results.anything.type with a value of %23results is received.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With