我在做什么:
我正在开发一个“webscraper”(多线程),就是这样,哈哈。
我需要在从页面中提取数据之前提交一个表单,所以布局是这样的:
- 对 example.com/path/doc.jsp(我的数据)的 GET 请求。
- 检查确认表单是否存在于文档源中。如果是则继续步骤 3(我的数据不存在,需要先提交表单),否则返回(因为没有要提交的表单,我的数据在这里)。
- 对 example.com/path/sub/other.jsp 的 GET 请求(必要的键值)。
- 对 example.com/path/submit.jsp 的 POST 请求(发送值)。
- 检查 POST 请求的响应,如果正常则转到 6,否则返回 1。
- 对 example.com/path/doc.jsp 的 GET 请求(我的数据,再次。由于我提交了表单,现在我的数据将出现)。
一切正常,除非来自 POST 请求(第 4 步)的响应告诉我返回第 1 步。
问题:
表单中的值之一我需要从 cookie 中提取它,所以我使用该GetCookies()
函数,但是,就像我说的,如果响应告诉我返回第 1 步,则所有请求(GET 和 POST ) 之后缺少 cookie(并添加了奇怪的 cookie)。见下图:
- 第一个调用是对我的数据所在的 doc.jsp 的 GET 请求。
- 第二个调用是 other.jsp 请求,因为确认表单存在于 doc.jsp 源代码中。
- 第三次调用是当我提交所有值时。
- 第四个调用是再次对 doc.jsp 的 GET 请求,因为提交表单(第三个调用)的响应告诉我重复该过程。基本上,4º ~ 6º 调用与 1º ~ 3º 相同,但带有 cookie fu**ed。
我的代码:
public class CWeb : IDisposable
{
private WebClientEx _wc;
private string _originalUrl;
public CWeb()
{
_wc = new WebClientEx(new CookieContainer());
}
public string downloadPage(string url)
{
_originalUrl = url;
string pgSrc = "error";
int tries = 0;
while (tries < 3 && pgSrc == "error)
{
try
{
pgSrc = _wc.DownloadString(url);
}
catch (Exception err)
{
tries += 1;
pgSrc = "error";
...
}
}
if (needSubmit(pgSrc)) // needSubmit just peform IndexOf on pgSrc
do
{
pgSrc = sendForm(pgSrc);
} while (needSubmit(pgSrc));
return WebUtility.HtmlDecode(pgSrc);
}
public string sendForm(pageSource)
{
// 1- Get Cookie Value
string cookie = _wc.CookieContainer.GetCookies(new Uri(_originalUrl))["JSESSIONID"].Value;
// 2- Get hidden values in pageSource parameter
// skip this, since there's no web request here, only some html parsing
// with Html Agility Pack
...
// 3- Get key value
string tmpStr = _wc.DownloadString("http://example.com/path/sub/other.jsp");
... more html parsing ...
// 4- Build form
NameValueCollection nvc = new NameValueCollection();
nvc["param1"] = cookie;
nvc["param2"] = key;
...
// 5- Send
_wc.UploadValues("example.com/path/submit.jsp", nvc);
// 6- Return
return _wc.DownloadString(_originalUrl);
}
public void Dispose()
{
_wc.Dispose();
}
}
主程序:
static void Main(string[] args)
{
// Load tons of 'doc' url list from database...
List<string> urls = new List<string>();
...
Parallel.ForEach(urls, (url) =>
{
using (CWeb crawler = new CWeb())
{
string pageData = crawler.downloadPage(url);
... parse html data here ...
}
});
}
我的环境: