模擬HTTP請(qǐng)求實(shí)現(xiàn)網(wǎng)頁自動(dòng)操作及數(shù)據(jù)采集的方法
前言
網(wǎng)頁可分為信息提供和業(yè)務(wù)操作類,信息提供如新聞、股票行情之類的網(wǎng)站。業(yè)務(wù)操作如網(wǎng)上營(yíng)業(yè)廳、OA之類的。當(dāng)然,也有很多網(wǎng)站同時(shí)具有這兩種性質(zhì),像微博、豆瓣、淘寶這類網(wǎng)站,既提供信息,也實(shí)現(xiàn)某些業(yè)務(wù)。
普通上網(wǎng)方式一般都是手動(dòng)操作(這個(gè)不需要解釋:D)。但有時(shí)候人工手動(dòng)操作的方式可能就無法勝任了,如爬取網(wǎng)絡(luò)上大量數(shù)據(jù),實(shí)時(shí)監(jiān)測(cè)某個(gè)頁面的變化,批量操作業(yè)務(wù)(如批量發(fā)微博,批量淘寶購(gòu)物)、刷單等。由于操作量大,而且都是重復(fù)的操作,人工操作效率低下,且易出錯(cuò)。這時(shí)候就可以使用軟件來自動(dòng)操作了。
本人開發(fā)過多個(gè)這類軟件,有網(wǎng)絡(luò)爬蟲、自動(dòng)批量操作業(yè)務(wù)這類的。其中使用到的一個(gè)核心功能就是模擬HTTP請(qǐng)求。當(dāng)然,有時(shí)會(huì)使用HTTPS協(xié)議,而且網(wǎng)站一般需要登陸后才能進(jìn)一步操作,還有最重要的一點(diǎn)就是弄清楚網(wǎng)站的業(yè)務(wù)流程,即知道為了實(shí)現(xiàn)某個(gè)操作該在什么時(shí)候向哪個(gè)頁面以什么方式提交什么數(shù)據(jù),最后,要提取數(shù)據(jù)或知道操作結(jié)果,就還需要解析HTML。本文將一一闡述。
本文使用C#語言來展示代碼,當(dāng)然也可以用其它語言實(shí)現(xiàn),原理是一樣的。以登陸京東為實(shí)例。
模擬HTTP請(qǐng)求
C#模擬HTTP請(qǐng)求需要使用到如下類:
•WebRequest
•HttpWebRequest
•HttpWebResponse
•Stream
先創(chuàng)建一個(gè)請(qǐng)求對(duì)象(HttpWebRequest),設(shè)置相關(guān)的Headers信息后發(fā)送請(qǐng)求(如果是POST,還要把表單數(shù)據(jù)寫入網(wǎng)絡(luò)流),如果目標(biāo)地址可訪問,會(huì)得到一個(gè)響應(yīng)對(duì)象(HttpWebResponse),從相應(yīng)對(duì)象的網(wǎng)絡(luò)流中就可讀出返回結(jié)果。
示例代碼如下:
String contentType = "application/x-www-form-urlencoded";
String accept = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/x-silverlight, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, application/x-ms-application, application/x-ms-xbap, application/vnd.ms-xpsdocument, application/xaml+xml, application/x-silverlight-2-b1, */*";
String userAgent = "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.116 Safari/537.36";
public String Get(String url, String encode = DEFAULT_ENCODE)
{
HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
InitHttpWebRequestHeaders(request);
request.Method = "GET";
var html = ReadHtml(request, encode);
return html;
}
public String Post(String url, String param, String encode = DEFAULT_ENCODE)
{
Encoding encoding = System.Text.Encoding.UTF8;
byte[] data = encoding.GetBytes(param);
HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
InitHttpWebRequestHeaders(request);
request.Method = "POST";
request.ContentLength = data.Length;
var outstream = request.GetRequestStream();
outstream.Write(data, 0, data.Length);
var html = ReadHtml(request, encode);
return html;
}
private void InitHttpWebRequestHeaders(HttpWebRequest request)
{
request.ContentType = contentType;
request.Accept = accept;
request.UserAgent = userAgent;
}
private String ReadHtml(HttpWebRequest request, String encode)
{
HttpWebResponse response = request.GetResponse() as HttpWebResponse;
Stream stream = response.GetResponseStream();
StreamReader reader = new StreamReader(stream, Encoding.GetEncoding(encode));
String content = reader.ReadToEnd();
reader.Close();
stream.Close();
return content;
}
可以看出,Get和Post方法的代碼大部分都相似,所以代碼進(jìn)行了封裝,提取了相同代碼作為新的函數(shù)。
HTTPS請(qǐng)求
當(dāng)網(wǎng)站使用https協(xié)議時(shí),以上代碼就可能會(huì)出現(xiàn)以下錯(cuò)誤:
The underlying connection was closed: Could not establish trust relationship for
原因是證書錯(cuò)誤,用瀏覽器打開會(huì)出現(xiàn)如下頁面:

當(dāng)點(diǎn)擊繼續(xù)前往xxx.xx(不安全)時(shí),就可繼續(xù)打開網(wǎng)頁。在程序中,也只要模擬這一步就可以繼續(xù)了。C#中只需設(shè)置ServicePointManager.ServerCertificateValidationCallback代理,在代理方法中直接返回true就行了。
private HttpWebRequest CreateHttpWebRequest(String url)
{
HttpWebRequest request;
if (IsHttpsProtocol(url))
{
ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
request = WebRequest.Create(url) as HttpWebRequest;
request.ProtocolVersion = HttpVersion.Version10;
}
else
{
request = WebRequest.Create(url) as HttpWebRequest;
}
return request;
}
private HttpWebRequest CreateHttpWebRequest(String url)
{
HttpWebRequest request;
if (IsHttpsProtocol(url))
{
ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
request = WebRequest.Create(url) as HttpWebRequest;
request.ProtocolVersion = HttpVersion.Version10;
}
else
{
request = WebRequest.Create(url) as HttpWebRequest;
}
return request;
}
這樣,就可正常訪問https網(wǎng)站了。
記錄Cookies實(shí)現(xiàn)身份認(rèn)證
有些網(wǎng)站需要登錄才能執(zhí)行下一步操作,比如在京東購(gòu)物需要先登錄。網(wǎng)站服務(wù)器使用session來記錄客戶端用戶,每一個(gè)session對(duì)應(yīng)一個(gè)用戶,而前面的代碼每次創(chuàng)建一個(gè)請(qǐng)求都會(huì)重新建立一個(gè)session。即使登錄成功,在執(zhí)行下一步操作由于新創(chuàng)建了一個(gè)連接,登錄也是無效的。這時(shí)就得想辦法讓服務(wù)器認(rèn)為這一系列的請(qǐng)求來自同一個(gè)session。
客戶端只有Cookies,為了在下次請(qǐng)求的時(shí)候讓服務(wù)器知道該客戶端對(duì)應(yīng)哪個(gè)session,Cookies中會(huì)有一個(gè)記錄session ID的記錄。所以,只要Cookies相同,對(duì)服務(wù)器來說就是同一個(gè)用戶。
這時(shí)需要使用到CookieContainer,顧名思義,這就是一個(gè)Cookies容器。HttpWebRequest有一個(gè)CookieContainer屬性。只要把每次請(qǐng)求的Cookies都記錄在CookieContainer,下次請(qǐng)求時(shí)設(shè)置HttpWebRequest的CookieContainer屬性,由于Cookies相同,對(duì)于服務(wù)器來說就是同一個(gè)用戶了。
public String Get(String url, String encode = DEFAULT_ENCODE)
{
HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
InitHttpWebRequestHeaders(request);
request.Method = "GET";
request.CookieContainer = cookieContainer;
HttpWebResponse response = request.GetResponse() as HttpWebResponse;
foreach (Cookie c in response.Cookies)
{
cookieContainer.Add(c);
}
}
分析調(diào)試網(wǎng)站
以上就實(shí)現(xiàn)了模擬HTTP請(qǐng)求,當(dāng)然,最重要的還是分析站。一般的情況都是沒有文檔、找不到網(wǎng)站開發(fā)人員,從一個(gè)黑盒子開始探索。分析工具有很多,推薦使用Chrome+插件Advanced Rest Client,Chrome的開發(fā)者工具能讓我們知道打開一個(gè)網(wǎng)頁時(shí)后臺(tái)做了哪些操作與請(qǐng)求,Advanced Rest Client可模擬發(fā)送請(qǐng)求。
比如在登錄京東時(shí),會(huì)提交如下數(shù)據(jù):

我們還能看到京東的密碼居然是明文傳輸,安全性很讓人擔(dān)心?。?/p>
還能看到返回的數(shù)據(jù):

返回的是JSON數(shù)據(jù),不過\u8d26這些是什么?其實(shí)這是Unicode編碼,使用Unicode編碼轉(zhuǎn)換工具,即可轉(zhuǎn)換成可讀的文字,比如這次返回的結(jié)果是:賬戶名與密碼不匹配,請(qǐng)重新輸入。
解析HTML
HTTP請(qǐng)求獲得的數(shù)據(jù)一般是HTML格式,有時(shí)也可能是Json或XML。需要解析才能提取有用數(shù)據(jù)。解析HTML的組件有:
•HTML Parser。多個(gè)平臺(tái)可用,如Java/C#/Python。很久沒用了。
•HtmlAgilityPack。通過通過XPath來解析HMTL。一直使用。 關(guān)于XPath教程,可以看W3School的XPath教程。
結(jié)語
本文介紹了開發(fā)模擬自動(dòng)網(wǎng)頁操作所需要的技能,從模擬HTTP/HTTPS請(qǐng)求,到Cookies、分析網(wǎng)站、解析HTML。代碼旨在說明使用方法,并非完整代碼,可能無法直接運(yùn)行。
以上這篇模擬HTTP請(qǐng)求實(shí)現(xiàn)網(wǎng)頁自動(dòng)操作及數(shù)據(jù)采集的方法就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
asp.net 通過aspnetpager為DataList分頁
今天整了半天才把DataList的分頁搞定,下面把我的設(shè)計(jì)過程給大家講講2009-12-12
如何在 .NET 中使用 Flurl 高效處理Http請(qǐng)求
這篇文章主要介紹了如何在 .NET 中使用 Flurl 高效處理Http請(qǐng)求,幫助大家更好的理解和學(xué)習(xí)使用.net技術(shù),感興趣的朋友可以了解下2021-05-05
微信公眾平臺(tái)開發(fā)教程(八)Session處理問題
本篇文章主要介紹了微信公眾平臺(tái)開發(fā)教程(八)Session處理 ,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。2016-12-12
asp.net 處理原文件中過長(zhǎng)的viewstate代碼
asp.net網(wǎng)頁原文件中總出現(xiàn)一段很長(zhǎng)的viewstate代碼看著就頭痛 所以在網(wǎng)上找了篇文章解決了這個(gè)問題,雖然VIEWSTATE沒有完全隱藏,但大大的改善了網(wǎng)頁源文件中VIEWSTATE的長(zhǎng)度。2010-02-02
js獲取.aspx頁面里面的服務(wù)器控件和.ascx中的服務(wù)器控件值
用js獲取.ascx控件中服務(wù)器控件值時(shí)首先要得到服務(wù)器控件的ClientID再加上.ascx頁面里面的服務(wù)器空間ID并用"_"連接2009-02-02
.net core版 文件上傳/ 支持批量上傳拖拽及預(yù)覽功能(bootstrap fileinput上傳文件)
本篇內(nèi)容主要解決.net core中文件上傳的問題 開發(fā)環(huán)境:ubuntu+vscode.本文給大家介紹的非常詳細(xì),感興趣的朋友一起看看吧2017-03-03
如何給asp.net core寫個(gè)簡(jiǎn)單的健康檢查
這篇文章主要給大家介紹了關(guān)于如何給asp.net core寫個(gè)簡(jiǎn)單的健康檢查的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用asp.net core具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-05-05

