我在Google Play上有一个PNR查询应用程序。运行得很好。但是最近,印度的Railwys在他们的PNR查询部分添加了验证码,因此,我无法将正确的数据传递给服务器以获取正确的响应。如何以imageview的形式在我的应用程序中添加此验证码,并要求用户也输入验证码详细信息,以便我可以发送适当的数据并获得适当的响应。
Indian Railways PNR Inquiry Link
这是我之前使用的PnrCheck.java。请帮助此处应进行哪些修改。
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import org.apache.http.Header;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.entity.InputStreamEntity;
import org.apache.http.impl.DefaultHttpClientConnection;
import org.apache.http.message.BasicHttpEntityEnclosingRequest;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.BasicHttpProcessor;
import org.apache.http.protocol.ExecutionContext;
import org.apache.http.protocol.HttpContext;
import org.apache.http.protocol.HttpRequestExecutor;
import org.apache.http.protocol.RequestConnControl;
import org.apache.http.protocol.RequestContent;
import org.apache.http.protocol.RequestExpectContinue;
import org.apache.http.protocol.RequestTargetHost;
import org.apache.http.protocol.RequestUserAgent;
import org.apache.http.util.EntityUtils;
public class PNRStatusCheck {
public static void main(String args[]) {
try {
String pnr1 = "1154177041";
String reqStr = "lccp_pnrno1=" + pnr1 + "&submitpnr=Get+Status";
PNRStatusCheck check = new PNRStatusCheck();
StringBuffer data = check.getPNRResponse(reqStr, "http://www.indianrail.gov.in/cgi_bin/inet_pnrstat_cgi.cgi");
if(data != null) {
@SuppressWarnings("unused")
PNRStatus pnr = check.parseHtml(data);
}
} catch(Exception e) {
e.printStackTrace();
}
}
public StringBuffer getPNRResponse(String reqStr, String urlAddr) throws Exception {
String urlHost = null;
int port;
String method = null;
try {
URL url = new URL(urlAddr);
urlHost = url.getHost();
port = url.getPort();
method = url.getFile();
// validate port
if(port == -1) {
port = url.getDefaultPort();
}
} catch(Exception e) {
e.printStackTrace();
throw new Exception(e);
}
HttpParams params = new BasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, "UTF-8");
HttpProtocolParams.setUserAgent(params, "HttpComponents/1.1");
HttpProtocolParams.setUseExpectContinue(params, true);
BasicHttpProcessor httpproc = new BasicHttpProcessor();
// Required protocol interceptors
httpproc.addInterceptor(new RequestContent());
httpproc.addInterceptor(new RequestTargetHost());
// Recommended protocol interceptors
httpproc.addInterceptor(new RequestConnControl());
httpproc.addInterceptor(new RequestUserAgent());
httpproc.addInterceptor(new RequestExpectContinue());
HttpRequestExecutor httpexecutor = new HttpRequestExecutor();
HttpContext context = new BasicHttpContext(null);
HttpHost host = new HttpHost(urlHost, port);
DefaultHttpClientConnection conn = new DefaultHttpClientConnection();
context.setAttribute(ExecutionContext.HTTP_CONNECTION, conn);
context.setAttribute(ExecutionContext.HTTP_TARGET_HOST, host);
@SuppressWarnings("unused")
String resData = null;
@SuppressWarnings("unused")
String statusStr = null;
StringBuffer buff = new StringBuffer();
try {
String REQ_METHOD = method;
String[] targets = { REQ_METHOD };
for (int i = 0; i < targets.length; i++) {
if (!conn.isOpen()) {
Socket socket = new Socket(host.getHostName(), host.getPort());
conn.bind(socket, params);
}
BasicHttpEntityEnclosingRequest req = new BasicHttpEntityEnclosingRequest("POST", targets[i]);
req.setEntity(new InputStreamEntity(new ByteArrayInputStream(reqStr.toString().getBytes()), reqStr.length()));
req.setHeader("Content-Type", "application/x-www-form-urlencoded");
req.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.75 Safari/535.7");
req.setHeader("Cache-Control", "max-age=0");
req.setHeader("Connection", "keep-alive");
req.setHeader("Origin", "http://www.indianrail.gov.in");
req.setHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
req.setHeader("Referer", "http://www.indianrail.gov.in/pnr_Enq.html");
//req.setHeader("Accept-Encoding", "gzip,deflate,sdch");
req.setHeader("Accept-Language", "en-US,en;q=0.8");
req.setHeader("Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.3");
httpexecutor.preProcess(req, httpproc, context);
HttpResponse response = httpexecutor.execute(req, conn, context);
response.setParams(params);
httpexecutor.postProcess(response, httpproc, context);
Header[] headers = response.getAllHeaders();
for(int j=0; j<headers.length; j++) {
if(headers[j].getName().equalsIgnoreCase("ERROR_MSG")) {
resData = EntityUtils.toString(response.getEntity());
}
}
statusStr = response.getStatusLine().toString();
InputStream in = response.getEntity().getContent();
BufferedReader reader = null;
if(in != null) {
reader = new BufferedReader(new InputStreamReader(in));
}
String line = null;
while((line = reader.readLine()) != null) {
buff.append(line + "\n");
}
try {
in.close();
} catch (Exception e) {}
}
} catch (Exception e) {
throw new Exception(e);
} finally {
try {
conn.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return buff;
}
public PNRStatus parseHtml(StringBuffer data) throws Exception {
BufferedReader reader = null;
if(data != null) {
reader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(data.toString().getBytes())));
} else {
return null;
}
String line = null;
TrainDetails trainDetails = new TrainDetails();
List<PassengerDetails> passDetailsList = new ArrayList<PassengerDetails>();
PassengerDetails passDetails = null;
int i = 0;
while ((line = reader.readLine()) != null) {
if(line.startsWith("<TD") && line.contains("table_border_both")) {
line = line.replace("<B>", "");
line = line.substring(line.indexOf("\">")+2, line.indexOf("</")).trim();
if(line.contains("CHART")) {
trainDetails.setChatStatus(line);
break;
}
if(i > 7) {//Passenger Details
if(passDetails == null) {
passDetails = new PassengerDetails();
}
switch(i) {
case 8 :
passDetails.setName(line);
break;
case 9 :
passDetails.setBookingStatus(line.replace(" ", ""));
break;
case 10 :
passDetails.setCurrentStatus(line.replace(" ", ""));
i = 7;
break;
}
if(i == 7 ) {
passDetailsList.add(passDetails);
passDetails = null;
}
} else { // Train details
switch(i){
case 0 :
trainDetails.setNumber(line);
break;
case 1 :
trainDetails.setName(line);
break;
case 2 :
trainDetails.setBoardingDate(line);
break;
case 3 :
trainDetails.setFrom(line);
break;
case 4 :
trainDetails.setTo(line);
break;
case 5 :
trainDetails.setReservedUpto(line);
break;
case 6 :
trainDetails.setBoardingPoint(line);
break;
case 7 :
trainDetails.setReservedType(line);
break;
default :
break;
}
}
i++;
}
}
if(trainDetails.getNumber() != null) {
PNRStatus pnrStatus = new PNRStatus();
pnrStatus.setTrainDetails(trainDetails);
pnrStatus.setPassengerDetails(passDetailsList);
return pnrStatus;
} else {
return null;
}
}
}
最佳答案
我在一个要求相同的帖子上找到了这个答案:
如果您检查html代码,它实际上是非常糟糕的验证码。验证码的背景是:http://www.indianrail.gov.in/1.jpg这些数字实际上在输入标签中:
他们正在做的是通过JavaScript使用隐藏输入标签中的数字,并将其放在具有“验证码”背景的范围内。
因此,基本上,您的流程是:
阅读他们的html
从输入字段中获取“验证码”(大声笑,虽然有趣的验证码)值
当用户将数据放在您的PNR字段中并按“获取状态”时
发布表格字段,将PNR设置为适当的值,将验证码设置为适当的值
解析响应
哦,是的,还有一件事。您可以将任何值放在隐藏输入和“验证码”输入中,只要它们相同即可。他们不会通过 session 或其他任何方式对其进行检查。
编辑(用于提交表单的代码示例):为了简化发布表单,我建议从Apache获得HttpClient组件:http://hc.apache.org/downloads.cgi假设您下载了HttpClient 4.3.1。在您的项目中包括客户端库,核心库和mime库(复制到libs文件夹,右键单击项目,属性,Java Build Path,Libraries,Add Jars->添加那些3.)。
代码示例为:
private static final String FORM_TARGET = "http://www.indianrail.gov.in/cgi_bin/inet_pnstat_cgi.cgi";
private static final String INPUT_PNR = "lccp_pnrno1";
private static final String INPUT_CAPTCHA = "lccp_capinp_val";
private static final String INPUT_CAPTCHA_HIDDEN = "lccp_cap_val";
private void getHtml(String userPnr) {
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.addTextBody(INPUT_PNR, userPnr); // users PNR code
builder.addTextBody(INPUT_CAPTCHA, "123456");
builder.addTextBody("submit", "Get Status");
builder.addTextBody(INPUT_CAPTCHA_HIDDEN, "123456"); // values don't
// matter as
// long as they
// are the same
HttpEntity entity = builder.build();
HttpPost httpPost = new HttpPost(FORM_TARGET);
httpPost.setEntity(entity);
HttpClient client = new DefaultHttpClient();
HttpResponse response = null;
String htmlString = "";
try {
response = client.execute(httpPost);
htmlString = convertStreamToString(response.getEntity().getContent());
// now you can parse this string to get data you require.
} catch (Exception letsIgnoreItForNow) {
}
}
private static String convertStreamToString(InputStream is) {
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line = null;
try {
while ((line = reader.readLine()) != null) {
sb.append(line);
}
} catch (IOException ignoredOnceMore) {
} finally {
try {
is.close();
} catch (IOException manyIgnoredExceptions) {
}
}
return sb.toString();
}
另外,请注意,我没有将其包装在
AsyncTask
调用中,因此您必须这样做。关于java - 如何更新印度铁路站点中添加的PNR Capcha,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/21228900/