您的位置:知识库 » .NET技术

尝试通过HttpWebRequest向TAOBAO批量发布商品及上传图片

作者: 野文  来源: 博客园  发布时间: 2009-10-19 10:29  阅读: 2895 次  推荐: 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

.NET技术热门文章

    .NET技术最新文章

      最新新闻

        热门新闻