使用Python发送HTTP POST请求(尝试从PHP转换)

4

我正在试图将这段PHP代码转换为Python (编程新手),但发现难度较大:

我要转换的PHP代码如下:

$fp = fsockopen($whmcsurl, 80, $errno, $errstr, 5);
if ($fp) {
$querystring = "";
foreach ($postfields AS $k=>$v) {
$querystring .= "$k=".urlencode($v)."&";
}
$header="POST ".$whmcsurl."modules/servers/licensing/verify.php HTTP/1.0\r\n";
$header.="Host: ".$whmcsurl."\r\n";
$header.="Content-type: application/x-www-form-urlencoded\r\n";
$header.="Content-length: ".@strlen($querystring)."\r\n";
$header.="Connection: close\r\n\r\n";
$header.=$querystring;
$data="";
@stream_set_timeout($fp, 20);
@fputs($fp, $header);
$status = @socket_get_status($fp);
while (!@feof($fp)&&$status) {
$data .= @fgets($fp, 1024);
$status = @socket_get_status($fp);
}
@fclose ($fp);
}

我写的相应Python代码如下:

对应的Python代码如下:

fp = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
                fp.connect(("my ip", 80))
                if (fp):
                        querystring = ""
                        #print postfields
                        for key in postfields:
                                querystring = querystring+key+"="+urllib.quote(str(postfields[key]))+"&"
                header = "POST "+whmcsurl+"modules/servers/licensing/verify.php HTTP/1.0\r\n"
                header+="Content-type: application/x-www-form-urlencoded\r\n"
                header+="Content-length: "+str(len(querystring))+"\r\n"
                header+="Connection: close\r\n\r\n"
                #header+=querystring
                data=""
                request = urllib2.Request(whmcsurl,querystring,header)
                response = urllib2.urlopen(request)
                data = response.read()

我面临以下错误:

request = urllib2.Request(whmcsurl,querystring,header)
  File "/usr/lib64/python2.6/urllib2.py", line 200, in __init__
    for key, value in headers.items():
AttributeError: 'str' object has no attribute 'items'

我猜Python希望使用字典格式的标头,但PHP发送的是字符串格式。请问该如何解决这个问题?
提前致谢。
2个回答

7
你过于复杂化了事情,Python已经为你处理好了大部分内容。没有必要自己打开套接字,也不需要构建头信息和HTTP开头行。
使用urllib.requesturllib.parse模块来替你完成这个工作:
from urllib.parse import urlopen
from urllib.request import urlopen

params = urlencode(postfields)
url = whmcsurl + 'modules/servers/licensing/verify.php'
response = urlopen(url, params)
data = response.read()

urlopen()是一个函数,它有第二个参数,用于在POST请求中发送数据;该库负责计算正文的长度并设置适当的标头。最重要的是,在内部它使用另一个库httplib来处理套接字连接,并生成有效的标头和HTTP请求行。

POST正文使用urllib.parse.urlencode()进行编码,它还会为您进行正确的引号处理。

您可能还想查看外部的 requests,它提供了更易于使用的API:

import requests

response = requests.post(whmcsurl + 'modules/servers/licensing/verify.php', params=params)
data = response.content  # or response.text for decoded content, or response.json(), etc.

那么,在这种情况下,我不需要为标题编写代码吗?这是由params = urlencode(postfields)处理的吗? - rahuL
头部信息完全由urlopen()处理。因为您发送了一个正文(第二个参数),所以会发送一个POST请求,并设置内容类型和内容长度头部信息。主机头部信息始终被设置。 - Martijn Pieters

2

你的标题应该像这样

headers = { "Content-type" : "application/x-www-form-urlencoded" };

这里有更多的问题。例如,POST ... HTTP/1.0 行不是一个头部,无论如何都不需要构建它。 - Martijn Pieters

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接