• delphi 利用HTTP的POST方法做个在线翻译的小工具 good


    最近做了一个英汉小翻译的东东,用的是VC,ADO + Access访问数据库,单词数据库是从金山打字通2002弄来的。后来想了想,想再加个在线翻译的功能,记得经常使用GOOGLE翻译网站的在线翻译,也蛮好用的。于是用Ethereal抓包工具抓了一下它的包,发现浏览器发出去的包格式如下:

    POST /translate_t?langpair=en|zh-CN HTTP/1.1
    Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, application/x-silverlight, application/QVOD, */*
    Referer: http://www.google.cn/language_tools
    Accept-Language: zh-cn
    Content-Type: application/x-www-form-urlencoded
    Accept-Encoding: gzip , deflate 
    User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; InfoPath.1; .NET CLR 2.0.50727)
    Host: translate.google.com
    Content-Length: 46
    Connection: Keep-Alive
    cache-Control: no-cache
    Cookie: __utmc=195145449; __utma=195145449.421253565.1205461371.1205592024.1205592348.11; __utmz=195145449.1205585337.9.8.utmccn=(referral)|utmcsr=hao123.com|utmcct=/ss/fy.htm|utmcmd=referral; __utmb=195145449

    hl=zh-CN&ie=UTF-8&text=bad&langpair=en%7Czh-CN

    以前也曾接触过一点HTTP协议的知识,HTTP协议并不难,实际上只不过是互相发送些命令,这些命令都是ASCII码的字符串。不过也还总是有些地方模糊不清。现在就来做个笔记,把已经清楚的一些东西记下来,日积月累就好了:

    上面的这段HTTP协议请求包数据其实是由两部分组成的:分别是HTTP请求协议头和HTTP用户数据段。HTTP请求协议头和HTTP用户数据段之间用空行隔开。另外还有一个要注意的地方是每一行的结尾都有个回车换行符(VC中 或者是VB中的vbCrlf),不然怎样叫做一行呢?呵呵。

    POST /translate_t?langpair=en|zh-CN HTTP/1.1
    方法 处理该HTTP请求的页面URL(相对路径) 协议版本号

    POST表示用HTTP协议的POST方法,HTTP协议常用的方法还有GET,我们来看一个GET方法的HTTP请求包格式:

    GET /search?hl=zh-CN&q=%E4%B8%AD%E5%9B%BD%E4%BA%BA&btnG=Google+%E6%90%9C%E7%B4%A2&meta=&aq=f HTTP/1.1
    Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, application/x-silverlight, application/QVOD, */*
    Referer: http://www.google.cn/
    Accept-Language: zh-cn
    Accept-Encoding: gzip, deflate
    User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; InfoPath.1; .NET CLR 2.0.50727)
    Host: www.google.cn
    Connection: Keep-Alive
    Cookie: PREF=ID=77ecc97ca62c7506:NW=1:TM=1205461328:LM=1205461328:S=J2uiHSrM9WZw7SBK; NID=8=Y8WD-oZWm6VqlKQPJn4NAaFJ6OZH9m7DHwGuYHa4NTczuMmCjOlnCn7WYxLAYJq-ZsGKGBSRWTZdQAwbt7zuzIPPxVqKp3zCb93z5GuHHxxblzwcTGQUmcMADxh7v3eX

    这是在www.google.cn搜索页面输入了“中国人”之后,浏览器发送出来的HTTP请求包。

    GET /search?hl=zh-CN&q=%E4%B8%AD%E5%9B%BD%E4%BA%BA&btnG=Google+%E6%90%9C%E7%B4%A2&meta=&aq=f HTTP/1.1
    方法 处理该HTTP请求的页面URL(相对路径) 协议版本号

    可以发现,www.google.cn搜索页面使用的GET方法(每个页面所使用的方法可以从该网页的源代码中查看到)。
    可以看到,两个方法之间的区别是GET方法不带HTTP用户数据段,GET方法的HTTP用户数据段包含在了这里
    /search?hl=zh-CN&q=%E4%B8%AD%E5%9B%BD%E4%BA%BA&btnG=Google+%E6%90%9C%E7%B4%A2&meta=&aq=f

    解释一下上面这个URL:
    /search是处理该GET请求的页面地址,使用的是相对路径,?开始后面的就是发送的用户数据段了,其实就是该页面中各元素的值。它们之间用&分隔。

    hl=zh-CN
    q=%E4%B8%AD%E5%9B%BD%E4%BA%BA
    btnG=Google+%E6%90%9C%E7%B4%A2
    meta=
    aq=f

    你可以用IE浏览器打开www.google.cn这个网页,然后点IE里的查看菜单,再点源文件,在打开的脚本文件中分别查找hl、q、btnG、meta、aq等字符串。可以发现,

    <input name=hl type=hidden value=zh-CN> 名字为hl的隐藏(type=hidden)输入框,值value为zh-CN

    <input autocomplete="off" maxlength=2048 name=q size=55 title="Google 搜索" value=""> 名字为q的输入框,这个就是你在搜索时输入的那个框,初始值value为空,当你输入若干字符后点“Google 搜索”按钮,该控件的value值就为你输入的字符了。

    <input name=btnG type=submit value="Google 搜索"> 名字为btnG的提交按钮(submit),就是那个“Google 搜索”按钮。

    <input name=btnI type=submit value="手气不错"> 另外一个名字为btnI的提交按钮,“手气不错”按钮。

    <input id=all type=radio name=meta value="" checked><label for=all>所有网页  </label> 名字为meta的单选钮(radio),值value为空。旁边还有几个单选钮就不列出了。

    <form action="/search" name=f> 以上这些控件都是包含在一个form中的,当用户单击这个form中的submit按钮时,这个form中的数据(各控件的值)就会被浏览器提交到action="/search"这个页面去处理。

    好了,我们理解了GET方法,回到我们POST中来。跑题了,呵呵。

    Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash,

    application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, application/x-silverlight, application/QVOD, */*
    接收的数据类型,格式为:主类型/子类型

    Referer: http://www.google.cn/language_tools
    应该是从哪个页面转向过来的(也就是提交该HTTP请求的页面)

    Accept-Language: zh-cn
    接收方使用的语言,zh-cn应该代表简体中文

    Content-Type: application/x-www-form-urlencoded
    网页内容(用户数据段)所属的类型

    Accept-Encoding: gzip, deflate
    接收方的数据编码方式,gzip经过压缩的

    User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; InfoPath.1; .NET CLR 2.0.50727)
    用户浏览器类型

    Host: translate.google.com
    主机名字

    Content-Length: 46
    网页内容(用户数据段)的长度

    Connection: Keep-Alive
    连接状态,Keep-Alive保持连接

    cache-Control: no-cache
    不使用cache

    Cookie: __utmc=195145449; __utma=195145449.421253565.1205461371.1205592024.1205592348.11; __utmz=195145449.1205585337.9.8.utmccn=(referral)|utmcsr=hao123.com|utmcct=/ss/fy.htm|utmcmd=referral; __utmb=195145449
    Cookie内容

    (注意:以上这些都是我个人的理解,并不一定正确。需要正确的解释请参考HTTP协议的介绍。)

    最关键的还是用户数据段这地方,改动一下就可以模拟IE浏览器POST数据到GOOGLE翻译网站了。
    hl=zh-CN&ie=UTF-8&text=bad&langpair=en%7Czh-CN

    hl=zh-CN
    ie=UTF-8
    text=bad
    langpair=en%7Czh-CN

    <input type=hidden name=hl value="zh-CN"> 名字为hl的隐藏(type=hidden)输入框,值value为zh-CN

    <input type=hidden name=ie value="UTF8"> 名字为ie的隐藏(type=hidden)输入框,值value为UTF8

    <textarea name=text wrap=SOFT dir="ltr" id=source>bad</textarea> 名字为text的文本框(textarea),就是我们输入需要翻译的原文的那个框

    <select name=langpair>
    <option value="ar|en">阿拉伯文到英语</option>
    ......
    <option value="en|zh-CN" selected>英语到中文(简体)</option>
    ......
    </select>
    名字为langpair的列表组合框,当我们选择英语到中文(简体)的时候它的值value就等于en|zh-CN了,上面langpair=en%7Czh-CN这里的%7C就是|的百分号加十六进制编码。

    好了,介绍到这里,我们下面来做个例子试验一下!



    #include <stdio.h> 
    #include <winsock2.h> //winsock库头文件
    #include <windows.h> 

    #pragma comment(lib,"WS2_32.lib") //连接winsock库文件

    int main()

    WSADATA stWsaData = {0};
    SOCKET hSocket = 0;
    sockaddr_in stRemoteAddr = {0};
    char cSendData[4096] = {0}; //发送数据缓冲区
    char cRecvData[10240] = {0}; //接收数据缓冲区
    intnRetBytes = 0;

    ::WSAStartup(MAKEWORD(2,0),&stWsaData); //初始化winsock库

    hSocket = ::socket(AF_INET,SOCK_STREAM,0); //创建TCP套接字
    if(hSocket == INVALID_SOCKET)
    return 0;

    stRemoteAddr.sin_family = AF_INET; //填充sockaddr_in结构
    //64.233.189.104为ping www.google.com得到的IP,暂时懒得写转换IP函数了
    stRemoteAddr.sin_addr.S_un.S_addr = inet_addr("64.233.189.104"); 
    stRemoteAddr.sin_port = htons(80);

    if(::connect(hSocket,(sockaddr *)&stRemoteAddr,sizeof stRemoteAddr) == -1) //连接到服务器
    ...{
    ::closesocket(hSocket); //关闭TCP套接字
    ::WSACleanup(); //释放winsock库
    return 0;
    }

    //构造HTTP请求数据包的请求头
    strcpy(cSendData,"POST /translate_t?langpair=en|zh-CN HTTP/1.1 "); 
    strcat(cSendData,"Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, application/x-silverlight, application/QVOD, */* "); 
    strcat(cSendData,"Referer: http://www.google.cn/language_tools "); 
    strcat(cSendData,"Accept-Language: zh-cn "); 
    strcat(cSendData,"Content-Type: application/x-www-form-urlencoded "); 
    //strcat(cSendData,"Accept-Encoding: gzip ,deflate "); 
    strcat(cSendData,"User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; InfoPath.1; .NET CLR 2.0.50727) "); 
    strcat(cSendData,"Host: translate.google.com "); 
    strcat(cSendData,"Content-Length: 46 ");
    strcat(cSendData,"Connection: Keep-Alive "); 
    strcat(cSendData,"cache-Control: no-cache "); 
    //strcat(cSendData,"Cookie: __utmc=195145449; __utma=195145449.421253565.1205461371.1205592024.1205592348.11; __utmz=195145449.1205585337.9.8.utmccn=(referral)|utmcsr=hao123.com|utmcct=/ss/fy.htm|utmcmd=referral; __utmb=195145449 "); 

    //请求头与用户数据段之间的分隔行
    strcat(cSendData," ");

    //构造HTTP请求数据包的用户数据段
    strcat(cSendData,"hl=zh-CN&ie=UTF-8&text=bad&langpair=en%7Czh-CN");

    printf("HTTP协议请求头包格式: %s",cSendData);

    ::send(hSocket,cSendData,sizeof cSendData,0); //发送

    nRetBytes = ::recv(hSocket,cRecvData,sizeof cRecvData,0); 
    printf(" 总共收到了%d数据!",nRetBytes);

    //保存网页到文件(注意:返回的数据中包含HTTP响应头,而HTTP网页文件是不应该有这个的,应该去掉,这里我省略了)
    FILE * fp = fopen("C:翻译结果网页.htm","wb");
    fwrite(cRecvData,nRetBytes,1,fp); 
    fclose(fp); 

    ::closesocket(hSocket); //关闭TCP套接字
    ::WSACleanup(); //释放winsock库
    return 0; 



    上面这个仅仅是翻译英文单词“bad”的功能,实现完整的例子还是由读者自己来做吧。^_^需要做的只是修改text字段的值,另外还有就是相应的Content-Length也应该改为你用户数据段实际的长度。

    还有两个问题:1,我为什么把上面的两段注释呢?Accept-Encoding: gzip , deflate是返回的网页的内容是经过压缩了的,我们就要自己解压缩,偷懒的做法是让服务器返回不压缩的网页。另外那句Cookie要不要无关紧要。

    2,当你尝试着用中文去翻译成英文的时候,你会遇到URL编码的问题,直接发送中文过去是错误的,必须经过URL编码(%E4%B8%AD%E5%9B%BD%E4%BA%BA的形式),这个还不止,还加上网页编码的问题,像百度和GOOGLE就是个样例:百度网页使用的是GB2313编码,而GOOGLE使用的却是UTF-8编码,针对不同的网页编码需要根据不同的编码进行转换。

    像在搜索页面输入“中国人”三个中文,

    百度的编码是:http://www.baidu.com/s?wd=%D6%D0%B9%FA%C8%CB&cl=3。

    “中国人”的GB2312编码:D6 D0 B9 FA C8 CB(16进制,一个中文两个字节)

    而GOOGLE的编码却是:http://www.google.cn/search?hl=zh-CN&q=%E4%B8%AD%E5%9B%BD%E4%BA%BA&meta=&aq=f

    “中国人”的UTF-8编码:E4 B8 AD E5 9B BD E4 BA BA(16进制,一个中文三个字节)

    呵呵,这些就先搁着了,留待以后解决。

    //*********************************以下内容为转成Delphi 源码:

    unit uSocket;

    interface

    uses
    Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
    Dialogs, IdWinSock2;

    function getStr(): string;

    implementation

    function getStr(): string;
    var
    stWsaData: TWSAData;
    hSocket: TSocket;
    stRemoteAddr: TSockAddr;
    cSendData: Pchar; //array[0..4095] of Char;
    cRecvData: Pchar; //array[0..10239] of Char;
    nRetBytes: integer;
    iReturn: integer;
    pData: string;
    begin
    Result := '';
    iReturn := WSAStartup(MAKEWORD(2, 0), stWsaData); //初始化winsock库
    hSocket := socket(AF_INET, SOCK_STREAM, 0); //创建TCP套接字
    if (hSocket = INVALID_SOCKET) then exit;
    ZeroMemory(@stRemoteAddr, sizeof(stRemoteAddr));
    stRemoteAddr.sin_family := AF_INET; //填充sockaddr_in结构
    //64.233.189.104为ping www.google.com得到的IP,暂时懒得写转换IP函数了
    stRemoteAddr.sin_addr.S_addr := inet_addr('64.233.189.104');
    stRemoteAddr.sin_port := htons(80);
    if connect(hSocket, @stRemoteAddr, sizeof(stRemoteAddr)) = -1 then //连接到服务器
    begin
    closesocket(hSocket); //关闭TCP套接字
    WSACleanup(); //释放winsock库
    exit;
    end;
    GetMem(cSendData, 4096);
    ZeroMemory(cSendData, 4096);
    GetMem(cRecvData, 10240);
    ZeroMemory(cRecvData, 10240);
    try
    //构造HTTP请求数据包的请求头
    pData := 'POST /translate_t?langpair=en|zh-CN HTTP/1.1' + #13#10 +
    'Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, application/x-silverlight, application/QVOD, */*' + #13#10 +
    'Referer: http://www.google.cn/language_tools' + #13#10 +
    'Accept-Language: zh-cn' + #13#10 +
    'Content-Type: application/x-www-form-urlencoded' + #13#10 +
    //'Accept-Encoding: gzip ,deflate'+ #13#10 +
    'User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; InfoPath.1; .NET CLR 2.0.50727)' + #13#10 +
    'Host: translate.google.com' + #13#10 +
    'Content-Length: 46' + #13#10 +
    'Connection: Keep-Alive' + #13#10 +
    'cache-Control: no-cache' + #13#10 +
    //'Cookie: __utmc=195145449; __utma=195145449.421253565.1205461371.1205592024.1205592348.11; __utmz=195145449.1205585337.9.8.utmccn=(referral)|utmcsr=hao123.com|utmcct=/ss/fy.htm|utmcmd=referral; __utmb=195145449' + #13#10 +
    //请求头与用户数据段之间的分隔行
    #13#10 +
    // 构造HTTP请求数据包的用户数据段
    'hl=zh-CN&ie=UTF-8&text=bad&langpair=en%7Czh-CN';
    StrPCopy(cSendData, pData);
    send(hSocket, cSendData^, Length(cSendData), 0); //发送
    nRetBytes := recv(hSocket, cRecvData^, 10240, 0);
    Result :=StrPas(cRecvData);
    //释放pchar变量
    finally
    FreeMem(cSendData);
    FreeMem(cRecvData);
    closesocket(hSocket); //关闭TCP套接字
    WSACleanup(); //释放winsock库
    end;
    end;

    end.

    http://hi.baidu.com/liu494021458/blog/item/841ccbefd2f22c202cf5345b.html 

    http://www.delphitop.com/html/wangluo/1344.html

    另一个例子:

    http://www.experts-exchange.com/questions/26208481/Delphi-7-Google-Translate-API-UTF-8-response-issue.html

  • 相关阅读:
    48音标
    business expressions(二)
    Pick up lines搭讪
    Greetings
    business expressions(一)
    analyzing problems
    business meeting
    idea缓存目录mac cache
    Sublime 3156 LICENSE key
    React从0到1
  • 原文地址:https://www.cnblogs.com/findumars/p/5236628.html
Copyright © 2020-2023  润新知