在 Delphi 中使用 idHTTP 发布表单数据
Posting Form Data With idHTTP in Delphi
我正在使用 Delphi 和 IdHTTP 库从这个 URL (http://apply.dataprocessors.com.au) 中获取一个表单,处理这个谜题并 post 给出正确答案。但是,显然我没有正确处理方法 POST,一旦检索到的响应是:"Problem with submission. Please try again."
下面是Delphi源代码:
procedure TForm1.Button1Click(Sender: TObject);
var
sGET, sPOST, sGET_count: String;
countCircles: integer;
parameters: TStringList;
begin
parameters := TStringList.Create;
sGET := http.Get('http://apply.dataprocessors.com.au');
sGET_count := StringReplace(sGET, '$', ' ', [rfReplaceAll, rfIgnoreCase]);
sGET_count := StringReplace(sGET_count, 'unfilled', '$', [rfReplaceAll, rfIgnoreCase]);
countCircles := 120 - sGET_count.CountChar('$');
parameters.Add('title=submit');
parameters.Add('value=' + countCircles.ToString());
parameters.Add('submit=Submit');
http.Request.ContentType := 'application/x-www-form-urlencoded';
sPOST := http.Post('http://apply.dataprocessors.com.au/?', parameters);
txtPost.Lines.Add(sPOST);
end;
HTML代码:
<html>
<head>
</head>
<body>
<form action="" method="POST">
<input type="hidden" name="title" value="submit">
<p>How many filled circles do you see:? <br><img src="unfilled_O.gif" height="12" width="12"><br></p>
<p>Answer: <input type="text" name="value" value="" size="10"></p>
<p><input type="Submit" value="Submit">
</form></body>
</html>
从 POST 方法检索到的响应:
<html>
<head>
</head>
<body>
<p>Problem with submission. Please try again.</p></body>
</html>
使用 F12(或 HTTP 代理)捕获您的浏览器通信并查看 "working" 请求的样子。
工作请求是否使用cookies?如果是,请为 IdHttp 启用 cookie 支持。
我认为您的 TIdHTTP
代码没有问题(尽管 Post()
的 URL 末尾的 /?
不是必需的). 您的 TIdHTTP
代码中缺少步骤。详情见下文。
我还发现您的 StringReplace()
代码有问题:
sGET := http.Get('http://apply.dataprocessors.com.au');
sGET_count := StringReplace(sGET, '$', ' ', [rfReplaceAll, rfIgnoreCase]);
sGET_count := StringReplace(sGET, 'unfilled', '$', [rfReplaceAll, rfIgnoreCase]);
注意第二个StringReplace()
的第一个参数。在第二个调用中,您正在搜索 TIdHTTP.Get()
返回的 原始 HTML。您不是在搜索第一个 StringReplace()
的结果。然后当您 re-assign sGET_count
时,您将完全丢弃第一个 StringReplace()
的结果,有效地使第一个调用成为 no-op。您可能打算改为这样做:
sGET := http.Get('http://apply.dataprocessors.com.au');
sGET_count := StringReplace(sGET, '$', ' ', [rfReplaceAll, rfIgnoreCase]);
sGET_count := StringReplace({sGET}sGET_count, 'unfilled', '$', [rfReplaceAll, rfIgnoreCase]);
更新:当我在我的网络浏览器中访问 URL 时,我发现您的代码没有考虑到一些事情。第一,网络表单包含一个 jobref
字段,您未将其包含在 POST
提交中。但更重要的是,当网页被真实的网络浏览器检索时,相关网页会调用 JavaScript 函数,但当您当前的 TIdHTTP
设置检索时则不会。 Javascript 位于 http://apply.dataprocessors.com.au/funcs1.js
并包含一个动态添加 cookie 到网络浏览器的命令:
function init() {
document.cookie = 'pc3o=d2r22; path=';
}
此命令由 HTML:
<html>
<head>
...
<script type="text/javascript" src="funcs1.js"></script>
</head>
<body onLoad="init()">
...
</html>
当网络浏览器提交网络表单时,除了在 HTML被检索。您需要将 TIdHTTP.AllowCookies
属性 设置为 True(默认情况下为 False),以便 TIdHTTP.Post()
可以发回 cookie,但是 Post()
只会发送 PHP cookie,而不是 Javascript cookie,原因很明显(TIdHTTP
不调用 client-side 脚本)。
如果您更改 TIdHTTP.Request.UserAgent
属性 以模仿真实的网络浏览器,而不是使用 Indy 的默认设置 UserAgent
,下载的 HTML 将包含 JavaScript 参考。这是可选的,因为您可以手动添加 Javascript cookie(幸运的是它是静态的,因此您不需要实际解析 Javascript,但如果您愿意,可以)到 TIdHTTP.CookieManager
不管 UserAgent
,Post()
仍会发送它,服务器似乎并不关心 HTML 是否包含 JavaScript 引用。
话虽如此,以下代码对我有用(我让服务器向 POST
发送成功响应):
procedure TForm1.Button1Click(Sender: TObject);
var
sGET, sPOST, sGET_count: String;
countCircles: integer;
parameters: TStringList;
begin
parameters := TStringList.Create;
try
http.AllowCookies := True;
// optional: http.Request.UserAgent := 'Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko';
sGET := http.Get('http://apply.dataprocessors.com.au');
http.CookieManager.AddServerCookie('pc3o=d2r22; path=', http.URL);
sGET_count := StringReplace(sGET, '$', '', [rfReplaceAll, rfIgnoreCase]);
sGET_count := StringReplace(sGET_count, '"filled_O.gif"', '$', [rfReplaceAll, rfIgnoreCase]);
countCircles := sGET_count.CountChar('$');
parameters.Add('title=submit');
parameters.Add('jobref=');
parameters.Add('value=' + countCircles.ToString());
http.Request.ContentType := 'application/x-www-form-urlencoded';
http.Request.Referer := 'http://apply.dataprocessors.com.au';
sPOST := http.Post('http://apply.dataprocessors.com.au', parameters);
ShowMessage(sPOST);
finally
parameters.Free;
end;
end;
我正在使用 Delphi 和 IdHTTP 库从这个 URL (http://apply.dataprocessors.com.au) 中获取一个表单,处理这个谜题并 post 给出正确答案。但是,显然我没有正确处理方法 POST,一旦检索到的响应是:"Problem with submission. Please try again."
下面是Delphi源代码:
procedure TForm1.Button1Click(Sender: TObject);
var
sGET, sPOST, sGET_count: String;
countCircles: integer;
parameters: TStringList;
begin
parameters := TStringList.Create;
sGET := http.Get('http://apply.dataprocessors.com.au');
sGET_count := StringReplace(sGET, '$', ' ', [rfReplaceAll, rfIgnoreCase]);
sGET_count := StringReplace(sGET_count, 'unfilled', '$', [rfReplaceAll, rfIgnoreCase]);
countCircles := 120 - sGET_count.CountChar('$');
parameters.Add('title=submit');
parameters.Add('value=' + countCircles.ToString());
parameters.Add('submit=Submit');
http.Request.ContentType := 'application/x-www-form-urlencoded';
sPOST := http.Post('http://apply.dataprocessors.com.au/?', parameters);
txtPost.Lines.Add(sPOST);
end;
HTML代码:
<html>
<head>
</head>
<body>
<form action="" method="POST">
<input type="hidden" name="title" value="submit">
<p>How many filled circles do you see:? <br><img src="unfilled_O.gif" height="12" width="12"><br></p>
<p>Answer: <input type="text" name="value" value="" size="10"></p>
<p><input type="Submit" value="Submit">
</form></body>
</html>
从 POST 方法检索到的响应:
<html>
<head>
</head>
<body>
<p>Problem with submission. Please try again.</p></body>
</html>
使用 F12(或 HTTP 代理)捕获您的浏览器通信并查看 "working" 请求的样子。
工作请求是否使用cookies?如果是,请为 IdHttp 启用 cookie 支持。
我认为您的 您的 TIdHTTP
代码没有问题(尽管 Post()
的 URL 末尾的 /?
不是必需的).TIdHTTP
代码中缺少步骤。详情见下文。
我还发现您的 StringReplace()
代码有问题:
sGET := http.Get('http://apply.dataprocessors.com.au'); sGET_count := StringReplace(sGET, '$', ' ', [rfReplaceAll, rfIgnoreCase]); sGET_count := StringReplace(sGET, 'unfilled', '$', [rfReplaceAll, rfIgnoreCase]);
注意第二个StringReplace()
的第一个参数。在第二个调用中,您正在搜索 TIdHTTP.Get()
返回的 原始 HTML。您不是在搜索第一个 StringReplace()
的结果。然后当您 re-assign sGET_count
时,您将完全丢弃第一个 StringReplace()
的结果,有效地使第一个调用成为 no-op。您可能打算改为这样做:
sGET := http.Get('http://apply.dataprocessors.com.au');
sGET_count := StringReplace(sGET, '$', ' ', [rfReplaceAll, rfIgnoreCase]);
sGET_count := StringReplace({sGET}sGET_count, 'unfilled', '$', [rfReplaceAll, rfIgnoreCase]);
更新:当我在我的网络浏览器中访问 URL 时,我发现您的代码没有考虑到一些事情。第一,网络表单包含一个 jobref
字段,您未将其包含在 POST
提交中。但更重要的是,当网页被真实的网络浏览器检索时,相关网页会调用 JavaScript 函数,但当您当前的 TIdHTTP
设置检索时则不会。 Javascript 位于 http://apply.dataprocessors.com.au/funcs1.js
并包含一个动态添加 cookie 到网络浏览器的命令:
function init() {
document.cookie = 'pc3o=d2r22; path=';
}
此命令由 HTML:
<html>
<head>
...
<script type="text/javascript" src="funcs1.js"></script>
</head>
<body onLoad="init()">
...
</html>
当网络浏览器提交网络表单时,除了在 HTML被检索。您需要将 TIdHTTP.AllowCookies
属性 设置为 True(默认情况下为 False),以便 TIdHTTP.Post()
可以发回 cookie,但是 Post()
只会发送 PHP cookie,而不是 Javascript cookie,原因很明显(TIdHTTP
不调用 client-side 脚本)。
如果您更改 TIdHTTP.Request.UserAgent
属性 以模仿真实的网络浏览器,而不是使用 Indy 的默认设置 UserAgent
,下载的 HTML 将包含 JavaScript 参考。这是可选的,因为您可以手动添加 Javascript cookie(幸运的是它是静态的,因此您不需要实际解析 Javascript,但如果您愿意,可以)到 TIdHTTP.CookieManager
不管 UserAgent
,Post()
仍会发送它,服务器似乎并不关心 HTML 是否包含 JavaScript 引用。
话虽如此,以下代码对我有用(我让服务器向 POST
发送成功响应):
procedure TForm1.Button1Click(Sender: TObject);
var
sGET, sPOST, sGET_count: String;
countCircles: integer;
parameters: TStringList;
begin
parameters := TStringList.Create;
try
http.AllowCookies := True;
// optional: http.Request.UserAgent := 'Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko';
sGET := http.Get('http://apply.dataprocessors.com.au');
http.CookieManager.AddServerCookie('pc3o=d2r22; path=', http.URL);
sGET_count := StringReplace(sGET, '$', '', [rfReplaceAll, rfIgnoreCase]);
sGET_count := StringReplace(sGET_count, '"filled_O.gif"', '$', [rfReplaceAll, rfIgnoreCase]);
countCircles := sGET_count.CountChar('$');
parameters.Add('title=submit');
parameters.Add('jobref=');
parameters.Add('value=' + countCircles.ToString());
http.Request.ContentType := 'application/x-www-form-urlencoded';
http.Request.Referer := 'http://apply.dataprocessors.com.au';
sPOST := http.Post('http://apply.dataprocessors.com.au', parameters);
ShowMessage(sPOST);
finally
parameters.Free;
end;
end;