嘗試通過HttpWebRequest向TAOBAO批量發布商品及上傳圖片

作者: 野文  來源: 博客園  發布時間: 2009-10-19 10:29  閱讀: 2792 次  推薦: 0   原文鏈接   [收藏]  

  朋友開了個淘寶店,所以經常要將新商品及圖片發布到網店里,而且有時還需要上傳很多商品。如果手工一條一個商品的上傳未免太花時間,所以我就琢磨著能否用WinForm寫個程序通過WebRequest發送POST/GET請求來達到這個目的。由于上傳上品時即有普通的Form字段信息需要提交,還需要上傳圖片,所以在寫HttpWebRequest時參考了這個帖子http://bytes.com/topic/c-sharp/answers/268661-how-upload-file-via-c-codeHow upload file via c# code?

  在淘寶網上發布一個商品大體分為兩個步驟(即兩個頁面,實際都是提交到同各URL進行處理的:http://sell.taobao.com//auction/publish/publish.htm),第一個步驟為選擇商品的分類,第二個步驟為填寫商品的信息及相關照片。

image

 image

  通過IEInspector軟件觀察第二個步驟提交后的http請求的RAW Stream大致為:

POST /auction/publish/publish.htm HTTP/1.1
Accept: image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-fla
sh, application/x-ms-application, application/x-ms-xbap, application/vnd.ms-xpsdocume
nt, application/xaml+xml, application/x-silverlight, application/vnd.ms-excel, application
/msword, application/vnd.ms-powerpoint, */*
Referer: http://sell.taobao.com/auction/publish/publish.htm
Accept-Language: zh-cn
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; .NET CLR 
2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022)
Content-Type: multipart/form-data; boundary=---------------------------7d9da39c0084
Accept-Encoding: gzip, deflate
Host: sell.taobao.com
Content-Length: 217424
Connection: Keep-Alive
Cache-Control: no-cache
Cookie: po=50008882_100.0_14_0.0_%E5%8C%.; sellTbToken=%2Ceee15ee6bb
aee%237856351072575161%2Ce87e3fe110be1%237856331541398694

-----------------------------7d9da39c0084
Content-Disposition: form-data; name="action"

publish/publishAction
-----------------------------7d9da39c0084
Content-Disposition: form-data; name="isMImageUser"

-----------------------------7d9da39c0084
Content-Disposition: form-data; name="_fma.pu._0.ca"

50008882
-----------------------------7d9da39c0084
Content-Disposition: form-data; name="_fma.pu._0.i"

NDczYzE0MjI3Yzc4ZTczOGI2ZGQ3ZjJiYThjMGZkYWEgYjc2MGM1MDBjYWVjYmFlN2I0MzRlZ
jQwZTIzOGI0NWIgMTI1NTc1MDA0NjQwNA==
-----------------------------7d9da39c0084

-----------------------------7d9da39c0084
Content-Disposition: form-data; name="_fma.pu._0.ima"; filename="DSC_6873.JPG"
Content-Type: image/pjpeg

…..

  所以在做這個http請求前,我們需要先準備好幾個東西,即Cookie值、_fma.pu._0.i值和sellTbToken的值。

  獲取Cookie值最理想的辦法就是用WebHttpRequest模擬登錄過程向服務器發出包含用戶名和密碼的Http請求,等服務器登錄成功后HttpResponse里包含的Set-Cookie部分就有我們要找的Cookie值。由于現在TaoBao的登錄頁面輸入密碼部分采用了插件方式,好像在發出請求前插件會生成一個Token之類的,所以簡單的WebHttpRequest發送登錄請求達不到我們的目的,至于他的登錄安全加密過程具體是怎么回事,我也沒有足夠時間去探個究竟,只好放棄了這個獲取Cookie的方式。最后索性用最原始的方法,即在web頁面上登錄TaoBao,然后用IEInspector來跟蹤返回的數據包,將其中的Cookie部分copy出來直接用就可以了。

    image

  接下來就是獲取_frma.pu._0.i的值了,其實這個值是干什么用的我也不知道。通過觀察,發現這個值最初出現的地方是用GET請求URLhttp://sell.taobao.com//auction/publish/publish.htm?auction_type=b&auth_alert=true后返回的HTML文本里,是以hidden的input形式出現的。所以我就在代碼里模擬這個過程并解析出這個值:

    private string GetFmaPu_0i()
    {
        string actionUrl = "http://sell.taobao.com//auction/publish/publish.htm?auction_ty
pe=b&auth_alert=true";
        HttpWebRequest httpWebRequest = WebRequest.Create(actionUrl) as HttpWebR
equest;
        httpWebRequest.Method = "GET";
        httpWebRequest.Headers["Cookie"] = txtCookie.Text; 

           WebResponse webResponse = httpWebRequest.GetResponse();
           Stream stream = webResponse.GetResponseStream();
           StreamReader rd = new StreamReader(stream, Encoding.GetEncoding("gb231
2"));
           string ouptText = rd.ReadToEnd();

           rd.Close();
           webResponse.Close();

           string startStr = "<input type=\"hidden\" name=\"_fma.pu._0.i\" value=\"";
           int startPos = ouptText.IndexOf(startStr) + startStr.Length;
           int endPos = ouptText.IndexOf("\" />", startPos);
           return ouptText.Substring(startPos, endPos - startPos);
       } 

  對于sellTbToken值的意義我也不明白,只是看名字好像是一個Token。雖然在Cookie里我也發現了一個sellTbToken,但他們的值是不一樣的,我沒有發現他們之間的聯系,例如,在Cookie里的sellTbToken值是%2C33d58361b5b7%2312446852732896952%2Ce337766ee471f%2312317842106832544%2Cebd13373eed76%2312317854579307544%2Cfe3e333de58e6%2313206186303479904%efd65353b8377%239822969650842632%2Cb5b5e7bb31ae%2312957211756764136%2Ce7e883bdd77e3%237273521182867360%2Ce8b1374b13bee%2313038885937950800%2C5780d773e5075%2312322949035362088%2C715735e53ed3b%237439832831399704,而第二步請求中Post Data里sellTbToken的值是5be7931b93e57#9260334924738040。我們要找的這個sellTbToken的值是在填寫商品相信信息頁面的hidden input里的,所以還是通過httpWebRequest發出POST請求并解析HTML來得到這個值:

private string GetSellTbToken(string fmaPu_0i)
        {
            string actionUrl = "http://sell.taobao.com/auction/publish/publish.htm";

            NameValueCollection paras = new NameValueCollection();
            paras.Add("_fma.pu._0.ca", "50008882");
            paras.Add("_fma.pu._0.cat", "20000%3A29973");
            paras.Add("action", "publish%2FpublishAction");
            paras.Add("event_submit_do_input_auction_info", "1");
            paras.Add("_fma.pu._0.i", fmaPu_0i);
            paras.Add("_fma.pu._0.x", "");
            paras.Add("_fma.pu._0.a", "b");
            paras.Add("_fma.pu._0.t", "");
            paras.Add("_fma.pu._0.pi", "");
            paras.Add("isEdit", "");
            paras.Add("isHaveImageExtra", "");
            paras.Add("_fma.pu._0.cat", "20000%3A29973");
            paras.Add("_fma.pu._0.d", "");
            paras.Add("_fma.pu._0.q", "10");
            paras.Add("_fma.pu._0.du", "14");
            paras.Add("_fma.pu._0.stu", "5");
            paras.Add("_fma.pu._0.m", "");
            paras.Add("_fma.pu._0.bu", "0");
            paras.Add("_fma.pu._0.in", "0.0");
            paras.Add("_fma.pu._0.pro", "%B1%B1%BE%A9");
            paras.Add("_fma.pu._0.c", "%B1%B1%BE%A9");
            paras.Add("_fma.pu._0.sh", "1");
            paras.Add("_fma.pu._0.se", "0.0");
            paras.Add("_fma.pu._0.sec", "0.0");
            paras.Add("_fma.pu._0.secu", "0.0");
            paras.Add("_fma.pu._0.pa", "%BF%EE%B5%BD%B7%A2%BB%F5");
            paras.Add("_fma.pu._0.h", "0");
            paras.Add("_fma.pu._0.ha", "0");
            paras.Add("_fma.pu._0.secur", "1");
            paras.Add("_fma.pu._0.r", "A");
            paras.Add("_fma.pu._0.auc", "0");
            paras.Add("_fma.pu._0.st", "");
            paras.Add("_fma.pu._0.sto", "");
            paras.Add("_fma.pu._0.e", "false");
            paras.Add("_fma.pu._0.fr", "");
            paras.Add("_fma.pu._0.sho", "%2C143119754%2C");
            paras.Add("_fma.pu._0.aut", "false");
            paras.Add("_fma.pu._0.b", "100.0");
            paras.Add("oldDesc", "");
            paras.Add("oldStory", "");
            paras.Add("productRootCat", "");
            paras.Add("productId", "");
            paras.Add("oldCat", "");
            paras.Add("oldSpuId", "");
            paras.Add("oldCategoryProperty", "");
            paras.Add("_fma.pu._0.isa", "false");
            paras.Add("_fma.pu._0.po", "2047393");
            paras.Add("_fma.pu._0.an", "false");
            paras.Add("_fma.pu._0.o", "");
            paras.Add("_fma.pu._0.auct", "0.0");
            paras.Add("_fma.pu._0.n", "");
            paras.Add("_fma.pu._0.isn", "false");
            paras.Add("_fma.pu._0.iso", "false");
            paras.Add("_fma.pu._0.s", "");
            paras.Add("_fma.pu._0.sk", "");
            paras.Add("_fma.pu._0.gtr", "");
            paras.Add("_fma.pu._0.g", "");

            StringBuilder sbData = new StringBuilder();
            foreach (string key in paras.Keys)
            {
                if (sbData.Length > 0)
                    sbData.Append("&");
                sbData.Append(String.Format("{0}={1}",key,paras[key]));
            }
            sbData.Insert(0, "\r\n");

            HttpWebRequest httpWebRequest2 = (HttpWebRequest)WebRequest.Create
(actionUrl);
            httpWebRequest2.ContentType = "application/x-www-form-urlencoded";
            httpWebRequest2.Method = "POST";
            httpWebRequest2.KeepAlive = true;
            httpWebRequest2.Credentials = System.Net.CredentialCache.DefaultCredentials;
            httpWebRequest2.Headers["Cookie"] = txtCookie.Text;

            Stream memStream = new System.IO.MemoryStream();

            byte[] btData = Encoding.UTF8.GetBytes(sbData.ToString());
            memStream.Write(btData,0,btData.Length);

            httpWebRequest2.ContentLength = memStream.Length;

            Stream requestStream = httpWebRequest2.GetRequestStream();

            memStream.Position = 0;
            byte[] tempBuffer = new byte[memStream.Length];
            memStream.Read(tempBuffer, 0, tempBuffer.Length);
            memStream.Close();
            requestStream.Write(tempBuffer, 0, tempBuffer.Length);
            requestStream.Close();

            WebResponse webResponse2 = httpWebRequest2.GetResponse();

            Stream stream2 = webResponse2.GetResponseStream();
            StreamReader reader2 = new StreamReader(stream2, Encoding.GetEncoding
("gb2312"));

            // Get response
            string ouptText = reader2.ReadToEnd();

            webResponse2.Close();
            httpWebRequest2 = null;
            webResponse2 = null;

            string startStr = "", startPos);
            return ouptText.Substring(startPos, endPos - startPos);
        }

  前面三個值準備好了后(實際上在取后兩個值的時候就需要Cookie的支持),我們就可以模擬發起第二步POST請求了,大致代碼如下:

Code


  不過沒有達到預期的結果,雖然我想了很多辦法折騰了一個晚上和一個上午,還是失敗了。也許是publish.html在服務器端有一個特殊的機制我還沒有在客戶端發現。不過結果并不很重要,重要的是通過這個例子更深入理解一下http請求的格式,例如cookie、header、post data等等。

  失敗之余,也發現了另外一個小小的安慰,在網上找到了‘淘寶助理’這款桌面軟件,也可以很好的批量處理一些事務。

0
0
 
 
 

文章列表

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()