内容简介:用 WebClient 爬網頁抓內容已是老生常談,但最近發現抓 ASP.NET WebForm 網頁的特殊眉角,忍不住又想分享。 (是的,「我種了一棵葱,大家快來嚐嚐」的毛病又犯了)主要關鍵在於當 WebForm 邏輯寫在 Server-Side Event,例如 Button_OnClick(),單純用 POST Request 是不會觸發的。例如以下示範,假設有個簡單的 WebForm 網頁,有一個 DropDownList 放選項,一個 Label 顯示結果,Button 在 Server-Side
用 WebClient 爬網頁抓內容已是老生常談,但最近發現抓 ASP.NET WebForm 網頁的特殊眉角,忍不住又想分享。 (是的,「我種了一棵葱,大家快來嚐嚐」的毛病又犯了)
主要關鍵在於當 WebForm 邏輯寫在 Server-Side Event,例如 Button_OnClick(),單純用 POST Request 是不會觸發的。例如以下示範,假設有個簡單的 WebForm 網頁,有一個 DropDownList 放選項,一個 Label 顯示結果,Button 在 Server-Side OnClick 事件中依 DropDownList 選取值在 Label 顯示不同文字:
<%@Page Language="C#"%> <script runat="server"> void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { ddlCatg.Items.Clear(); ddlCatg.Items.Add(new ListItem("筆電", "Notebook")); ddlCatg.Items.Add(new ListItem("手機", "Mobile")); } } void btnQuery_OnClick(object sender, EventArgs e) { lblDisplay.Text = ddlCatg.SelectedItem.Value == "Notebook" ? "ThinkPad X21" : "Nokia 3310"; } </script> <html> <body> <form runat="server"> <asp:DropDownList runat="server" id="ddlCatg" Height="23"></asp:DropDownList> <asp:Button runat="server" id="btnQuery" text="查詢" OnClick="btnQuery_OnClick"></asp:Button> <div class="result"> <asp:Label runat="server" id="lblDisplay" Text="請按查詢" ></asp:Label> </div> </form> </body> </html>
實際操作如下:
依照直覺,反正就是個 POST 傳送表單內容,用 WebClient.UploadValues 應該就可以搞定:
static void Main(string[] args) { var wc = new WebClient(); var form = new NameValueCollection(); form.Add("ddlCatg", "Mobile"); var resp = Encoding.UTF8.GetString( wc.UploadValues("http://localhost/aspnet/webform.aspx", form)); var m = Regex.Match(resp, @"(?ims)ID=""lblDisplay"">(?<t>.*?)</span>"); if (m.Success) Console.WriteLine("Result=" + m.Groups["t"].Value); Console.Read(); }
很不幸地,雖然成功發出 POST 請求取回網頁,但並沒有觸發 btnQuery_OnClick,只會得到 Result=請按查詢
。
原因是這樣的,ASP.NET WebForm 有自己的一套機制,網頁包含了 __VIEWSTATE、__EVENTVALIDATION 等隱藏欄位:(延伸閱讀:這也成了 WebForm 的原罪,例如UpdatePanel招誰惹誰?)
而在 POST 送出表單時,這些欄位需一併傳送才會進入 PostBack 流程觸發 Server-Side Event:
因此網路爬蟲必須模擬相同的行為才能得到正確結果,我的解法是先發一個 GET Request 拿到 HTML 從中取出 __VIEWSTATE 及 __EVENTVALIDATION 欄位值,當成 POST Form 的一部分 。另外有一點要注意,上圖中標註為紅色的 btnQuery: "查詢",對後端執行並無作用,但對 ASP.NET WebForm 是必須的,需包含在傳送內容中。
修改後的程式如下:
static void Main(string[] args) { var wc = new WebClient(); var url = "http://localhost/aspnet/webform.aspx"; var html = wc.DownloadString(url); var mViewState = Regex.Match(html, @"(?ims)id=""__VIEWSTATE"" value=""(?<v>.+?)"""); var mEventVald = Regex.Match(html, @"(?ims)id=""__EVENTVALIDation"" value=""(?<v>.+?)"""); var form = new NameValueCollection(); form.Add("__VIEWSTATE", mViewState.Groups["v"].Value); form.Add("__EVENTVALIDATION", mEventVald.Groups["v"].Value); form.Add("btnQuery", "查詢"); form.Add("ddlCatg", "Mobile"); var resp = Encoding.UTF8.GetString( wc.UploadValues(url, form)); var m = Regex.Match(resp, @"(?ims)ID=""lblDisplay"">(?<t>.*?)</span>"); if (m.Success) Console.WriteLine("Result=" + m.Groups["t"].Value); Console.Read(); }
實測結果為 Result=Nokia 3310
,成功!
同場加映,在 .NET Core 裡 WebClient 已被 HttpClient 取代,在此一併示範用 HttpClient 的寫法。主要差異在於 HttpClient 改用 GetStringAync()/PostAsync()+new FormUrlEncodedContent(Dictionary<string, string>) 取代 WebCient DownloadString()、UploadValues(),其餘原理相同。
static void Main(string[] args) { var hc = new HttpClient(); var url = "http://localhost/aspnet/webform.aspx"; var html = hc.GetStringAsync(url).Result; var mViewState = Regex.Match(html, @"(?ims)id=""__VIEWSTATE"" value=""(?<v>.+?)"""); var mEventVald = Regex.Match(html, @"(?ims)id=""__EVENTVALIDation"" value=""(?<v>.+?)"""); var form = new Dictionary<string, string>(); form.Add("__VIEWSTATE", mViewState.Groups["v"].Value); form.Add("__EVENTVALIDATION", mEventVald.Groups["v"].Value); form.Add("btnQuery", "查詢"); form.Add("ddlCatg", "Mobile"); var resp = hc.PostAsync(url, new FormUrlEncodedContent(form)) .Result.Content.ReadAsStringAsync().Result; var m = Regex.Match(resp, @"(?ims)ID=""lblDisplay"">(?<t>.*?)</span>"); if (m.Success) Console.WriteLine("Result=" + m.Groups["t"].Value); Console.Read(); }
When crawling ASP.NET WebForm page, __VIEWSTATE and __EVENTVALIDATION hidden fields are required in the POST request to trigger server-side event.
以上所述就是小编给大家介绍的《小技巧 - 抓取 ASP.NET WebForm 網頁 PostBack 結果》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 渗透技巧——利用netsh抓取连接文件服务器的NTLMv2 Hash
- 如何使用代理IP进行数据抓取,PHP爬虫抓取亚马逊商品数据
- 抓取 Grafana Panel 视图
- 常用 Windows 抓取Hash
- Python爬虫:抓取新浪新闻数据
- Python抓取花瓣网高清美图
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
机器学习基础教程
(英)Simon Rogers,、Mark Girolami / 郭茂祖、王春宇 刘扬 刘晓燕、刘扬、刘晓燕 / 机械工业出版社 / 2014-1 / 45.00
本书是一本机器学习入门教程,包含了数学和统计学的核心技术,用于帮助理解一些常用的机器学习算法。书中展示的算法涵盖了机器学习的各个重要领域:分类、聚类和投影。本书对一小部分算法进行了详细描述和推导,而不是简单地将大量算法罗列出来。 本书通过大量的MATLAB/Octave脚本将算法和概念由抽象的等式转化为解决实际问题的工具,利用它们读者可以重新绘制书中的插图,并研究如何改变模型说明和参数取值。......一起来看看 《机器学习基础教程》 这本书的介绍吧!