Python URLLib / URLLib2 POST - python

I'm trying to create a super-simplistic Virtual In / Out Board using wx/Python. I've got the following code in place for one of my requests to the server where I'll be storing the data:
data = urllib.urlencode({'q': 'Status'})
u = urllib2.urlopen('http://myserver/inout-tracker', data)
for line in u.readlines():
print line
Nothing special going on there. The problem I'm having is that, based on how I read the docs, this should perform a Post Request because I've provided the data parameter and that's not happening. I have this code in the index for that url:
if (!isset($_POST['q'])) { die ('No action specified'); }
echo $_POST['q'];
And every time I run my Python App I get the 'No action specified' text printed to my console. I'm going to try to implement it using the Request Objects as I've seen a few demos that include those, but I'm wondering if anyone can help me explain why I don't get a Post Request with this code. Thanks!
-- EDITED --
This code does work and Posts to my web page properly:
data = urllib.urlencode({'q': 'Status'})
h = httplib.HTTPConnection('myserver:8080')
headers = {"Content-type": "application/x-www-form-urlencoded",
"Accept": "text/plain"}
h.request('POST', '/inout-tracker/index.php', data, headers)
r = h.getresponse()
print r.read()
I am still unsure why the urllib2 library doesn't Post when I provide the data parameter - to me the docs indicate that it should.

u = urllib2.urlopen('http://myserver/inout-tracker', data)
h.request('POST', '/inout-tracker/index.php', data, headers)
Using the path /inout-tracker without a trailing / doesn't fetch index.php. Instead the server will issue a 302 redirect to the version with the trailing /.
Doing a 302 will typically cause clients to convert a POST to a GET request.

Related

Web-scraping on Python

I need to download the response of POST-request on https://www.avast.com/hackcheck/ site as JSON file. But my request to the site return an error 400. My code is:
URL = 'https://identityprotection.avast.com/v1/web/query/site-breaches/unauthorized-data'
params = {'emailAddresses':['xxx#x.ru']}
headers = {'Vaar-Version': '0'}
req = requests.post(URL, params, headers)
req
The request on the site works correctly
The request on the site works correctly
So what am I doing wrong?
Ideally you should include all the other parameters in your request header also (not just the Vaar-Version). See screenshot below of the full POST variables:
Note: Even then it may not necessarily work
Add the following in your header:
headers: {
Accept : "application/json",
}
Also, keep in mind where you put equals (=) and where you put semicolons.

Golang: Get request sends me html contents but works fine from python and curl

I am trying to call a simple api by using golang. But, each time it sends me html content of login page instead of actual data. But same get request works from python and curl.
func main() {
client := &http.Client{}
req, err := http.NewRequest("GET", "https://www.lrn.com", nil)
if err != nil {
os.Exit(1)
}
q := req.URL.Query()
q.Add("phoneList", "XXXXXX")
q.Add("output", "json")
q.Add("version", "5")
//req.URL.RawQuery = q.Encode()
req.Header.Set("loginId", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
fmt.Println(req.URL.String())
resp, err := client.Do(req)
if err != nil {
fmt.Println("Errored when sending request to the server")
return
}
defer resp.Body.Close()
resp_body, _ := ioutil.ReadAll(resp.Body)
fmt.Println(resp.Status)
fmt.Println(string(resp_body))
}
Above script gives me html content of login page. But if i use python, it works just fine.
import requests
r=requests.get("https://www.lrn.com", params = {'version':'5', "phoneList":"XXXXXX", "output":"json"}, headers={"loginId":"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"})
print r.text
Could someone please explain me what might be wrong in my golang script.
//req.URL.RawQuery = q.Encode()
req.Header.Set("loginId", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
fmt.Println(req.URL.String())
The last line outputs the URL it uses. With the code above this will be https://www.lrn.com. Given that you want to have query parameters the expected value would be instead https://www.lrn.com?output=json&... though. So something is clearly missing from your construction of the URL.
When activating the line you've explicitly commented out the result is very different:
req.URL.RawQuery = q.Encode() // activate this line
...
fmt.Println(req.URL.String())
In this case I get https://www.lrn.com?output=json&phoneList=XXXXXX&version=5, which is the expected value. And with this value the result from the server is for me the same as for your Python code.
But this seems to be only the first problem. Based on input in the comments I could track down the second problem, which was caused by a broken server together with header normalization by Golang. Based on the comments I've now used a different URL https://www.dncscrub.com/app/main/rpc/scrub where the Python code worked and the Golang code again did not work.
By comparing the HTTP requests used by both and reducing to their essential difference it showed, that the server erroneously interpreted a HTTP request header in a case-sensitive way. This worked
GET /app/main/rpc/scrub?version=5&phoneList=2123727200 HTTP/1.1
Host: www.dncscrub.com
loginId: 0610A62F
And resulted in the expected HTTP/1.1 401 Invalid credentials. While this did not work
GET /app/main/rpc/scrub?version=5&phoneList=2123727200 HTTP/1.1
Host: www.dncscrub.com
Loginid: 0610A62F
but resulted in a redirect HTTP/1.1 302 Found.
The only difference between these requests is the use of loginId: ... vs. Loginid: .... The server is clearly broken by treating HTTP header fields as case-sensitive, see Are HTTP headers case-sensitive?
which also links to the relevant standards.
Since req.Header.Set will normalize the header field one cannot use it. A work around is to manipulate the dictionary instead, which is usually not a good idea:
req.Header["loginId"] = []string{"0610A62F"}
See also GoLang: Case-sensitive HTTP Headers with net/http for a similar problem.

Python request resulting in blank response

I'm relatively new to Python so would like some help, I've created a script which simply use the request library and basic auth to connect to an API and returns the xml or Json result.
# Imports
import requests
from requests.auth import HTTPBasicAuth
# Set variables
url = "api"
apiuser = 'test'
apipass = 'testpass'
# CALL API
r = requests.get(url, auth=HTTPBasicAuth(apiuser, apipass))
# Print Statuscode
print(r.status_code)
# Print XML
xmlString = str(r.text)
print(xmlString)
if but it returns a blank string.
If I was to use a browser to call the api and enter the cretentials I get the following response.
<Response>
<status>SUCCESS</status>
<callId>99999903219032190321</callId>
<result xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Dummy">
<authorFullName>jack jones</authorFullName>
<authorOrderNumber>1</authorOrderNumber>
</result>
</Response>
Can anyone tell me where I'm going wrong.
What API are you connecting to?
Try adding a user-agent to the header:
r = requests.get(url, auth=HTTPBasicAuth(apiuser, apipass), headers={'User-Agent':'test'})
Although this is not an exact answer for the OP, it may solve the issue for someone having a blank response from python-requests.
I was getting a blank response because of the wrong content type. I was expecting an HTML rather than a JSON or a login success. The correct content-type for me was application/x-www-form-urlencoded.
Essentially I had to do the following to make my script work.
data = 'arcDate=2021/01/05'
headers = {
'Content-Type': 'application/x-www-form-urlencoded',
}
r = requests.post('https://www.deccanherald.com/getarchive', data=data, headers=headers)
print(r.status_code)
print(r.text)
Learn more about this in application/x-www-form-urlencoded or multipart/form-data?
Run this and see what responses you get.
import requests
url = "https://google.com"
r = requests.get(url)
print(r.status_code)
print(r.json)
print(r.text)
When you start having to pass things in your GET, PUT, DELETE, OR POST requests, you will add it in the request.
url = "https://google.com"
headers = {'api key': 'blah92382377432432')
r = requests.get(url, headers=headers)
Then you should see the same type of responses. Long story short,
Print(r.text) to see the response, then you once you see the format of the response you get, you can move it around however you want.
I have an empty response only when the authentication failed or is denied.
The HTTP status is still ≤ 400.
However, in the header you can find :
'X-Seraph-LoginReason': 'AUTHENTICATED_FAILED'
or
'X-Seraph-LoginReason': 'AUTHENTICATED_DENIED'
If the request is empty, not even a status code I could suggest waiting some time between printing. Maybe the server is taking time to return the response to you.
import time
time.sleep(5)
Not the nicest thing, but it's worth trying
How can I make a time delay in Python?
I guess there are no errors during execution
EDIT: nvm, you mentioned that you got a status code, I thought you were literally geting nothing.
On the side, if you are using python3 you have to use Print(), it replaced Print

Python requests library doesn't have all headers

I am using python requests library for a POST request and I expect a return message with an empty payload. I am interested in the headers of the returned message, specifically the 'Location' attribute. I tried the following code:
response=requests.request(method='POST', url=url, headers={'Content-Type':'application/json'}, data=data)
print response.headers ##Displays a case-insensitve map
print response.headers['Location'] ##blows up
Strangely the 'Location' attribute is missing in the headers map. If I try the same POST request on postman, I do get a valid Location attribute. Has anyone else seen this? Is this a bug in the requests library?
Sounds like everything's working as expected? Check your response.history
From the Requests documentation:
Requests will automatically perform location redirection for all verbs except HEAD.
>>> r = requests.get('http://github.com')
>>> r.url
'https://github.com/'
>>> r.status_code
200
>>> r.history
[<Response [301]>]
From the HTTP Location page on wikipedia:
The HTTP Location header field is returned in responses from an HTTP server under two circumstances:
To ask a web browser to load a different web page. In this circumstance, the Location header should be sent with an HTTP status code of 3xx. It is passed as part of the response by a web server when the requested URI has:
Moved temporarily, or
Moved permanently
To provide information about the location of a newly-created resource. In this circumstance, the Location header should be sent with an HTTP status code of 201 or 202.1
The requests library follows redirections automatically.
To take a look at the redirections, look at the history of the requests. More details in the docs.
Or you pass the extra allow_redirects=False parameter when making the request.

how to encode POST data using python's urllib

I'm trying to connect to my Django server using a client side python script. Right now I'm just trying to connect to a view and retrieve the HttpResponse. The following works fine
import urllib2
import urllib
url = "http://localhost:8000/minion/serve"
request = urllib2.Request(url)
response = urllib2.urlopen(request)
html = response.read()
print html
However if I change it to
import urllib2
import urllib
url = "http://localhost:8000/minion/serve"
values = {'name': 'Bob'}
data = urllib.urlencode(values)
request = urllib2.Request(url, data)
response = urllib2.urlopen(request)
html = response.read()
print html
I get urllib2.HTTPError: HTTP Error 500: INTERNAL SERVER ERROR. Am I doing something wrong here? Here are the tutorials I was trying to follow, http://techmalt.com/?p=212 http://docs.python.org/2/howto/urllib2.html.
EDIT: tried to make the following change as per That1Guy's suggestion (other lines left the same)
request = urllib2.Request(url, data)
response = urllib2.urlopen(request, data)
This returned the same error message as before.
EDIT: It seems to work if I change the page I'm viewing so the error isn't in the client side script. So in light of that revelation, here's the server side view that's being accessed:
def serve(request):
return HttpResponse("You've been served!")
As you can see, it's very straight forward.
EDIT: Tested to see if Internal Error might be caused by missing csrf token, but csrf_exempt decorator failed to resolve error.
Finally figured it out with this. How to POST dictionary from python script to django url?
Turns out my url was missing a trailing slash. It's the little things that always get you I guess.

Categories

Resources