模拟网页行为之实践篇
2016-11-18 19:10
337 查看
无论是模拟网页点击还是直接协议发包,都有其适用的环境。不同的需求选择不同的方案。如果只是简单的获取类似网页IP地址的需求,实际上协议发包是最简单的。但如果是用户名网页登陆等稍微复杂的登陆要求,则直接填写表单,并获取按钮元素来模拟点击这个方案来讲相对简单。但需求若稍微再变化一点,要求效率多线程,这个时候又是协议发包会作为首选,哪怕需要用户名网页登陆。没有最好的方案只有更合适的方案。这点很重要。
先说模拟网页点击方式,一般我采用的是继承MFC里面的CDHtmlDialog类自己命名为CWebLoginDlg,选择MFC并不是说有多好用,而是本人对于MFC使用更熟悉,学习成本更低,仅此而已。
模拟网页逻辑就是个状态机的处理,而状态的获取,一个可以通过获取网页源码判断特征字符串的方式,还有个可以通过XMLHttpRequest的回包判断数据的方式,再有也可以通过获取网页元素com组件对象是否存在的方式。
先说获取网页源码,基本原理是先获取网页DOC对象, 然后遍历DOC里面的元素,找到TAG为html的元素 get_outerHTML,c++代码如下:
再说XMLHttpRequest, XMLHttpRequest是对ajax技术的实现,重点体现在包头的Content-Type字段,这个字段值为application/x-www-form-urlencoded,例如网页代码:
这种方式的ajax还会多个X-Requested-With字段,值为XMLHttpRequest,回包数据都为json格式,还有一种网页代码:
这种方式ajax没有X-Requested_With字段,回包数据为网页数据。c++实现方式如下:
这里提供一个技巧,找到ajax代码的实现,可以先抓包得到http header里面的request url的url字符串,然后在脚本里面去查找字符串,一般字符串就在ajax代码
url : getDomain() + "rest/user"里面搜索到,搜索到后可以看代码对于返回值的处理,这样才好方便写逻辑。
最后说下获取网页元素,一般来说网页元素都会带有ID或者带有ClassName,例如网页代码:
如果想通过ID获取网页对象,简单的可以直接通过GetElement函数来实现,C++代码如下:
以上就是模拟网页中获取网页状态的基本函数,有了这几个函数网页模拟方式的基本框架基本都可以搭建起来了。
先说模拟网页点击方式,一般我采用的是继承MFC里面的CDHtmlDialog类自己命名为CWebLoginDlg,选择MFC并不是说有多好用,而是本人对于MFC使用更熟悉,学习成本更低,仅此而已。
模拟网页逻辑就是个状态机的处理,而状态的获取,一个可以通过获取网页源码判断特征字符串的方式,还有个可以通过XMLHttpRequest的回包判断数据的方式,再有也可以通过获取网页元素com组件对象是否存在的方式。
先说获取网页源码,基本原理是先获取网页DOC对象, 然后遍历DOC里面的元素,找到TAG为html的元素 get_outerHTML,c++代码如下:
std::wstring CWebLoginDlg::GetHtmlSource() { CComPtr<IHTMLDocument2> sphtmlDoc; CComPtr<IHTMLElementCollection> pIHTMLElementCollect; GetDHtmlDocument(&sphtmlDoc); if (!sphtmlDoc) { return L""; } sphtmlDoc->get_all(&pIHTMLElementCollect); long iCount; pIHTMLElementCollect->get_length(&iCount); CComBSTR data; for (int i = 0; i < iCount; i++) { CComVariant v3,v4; v3=(long)i; v4.vt=VT_I4; v4=(long)0; CComPtr<IDispatch> pDisp; HRESULT hr = pIHTMLElementCollect->item(v3,v4,&pDisp); if (!SUCCEEDED(hr)) { continue; } CComQIPtr<IHTMLElement, &IID_IHTMLElement> pHTMLElement(pDisp); if(pHTMLElement == NULL) { continue; } CComBSTR strTagName; hr = pHTMLElement->get_tagName(&strTagName); if(!SUCCEEDED(hr)) { continue; } CString strTag=strTagName; strTag.MakeLower(); if(strTag!="html") { continue; } hr = pHTMLElement->get_outerHTML(&data); if(!SUCCEEDED(hr)) { return L""; } break; } std::wstring source = data.m_str; return source; }
再说XMLHttpRequest, XMLHttpRequest是对ajax技术的实现,重点体现在包头的Content-Type字段,这个字段值为application/x-www-form-urlencoded,例如网页代码:
function syncGameInfoAgent () {$.ajax({url : "/api/web/syncGameInfoAgent",type : "GET",cache : false,async : false,success : function(data, textStatus, jqXHR) {}});}
这种方式的ajax还会多个X-Requested-With字段,值为XMLHttpRequest,回包数据都为json格式,还有一种网页代码:
var loadLoginInfo = function() { $.ajax({ url : getDomain() + "rest/user", type : "GET", data : {"fields" : "isNameCheck,charCount,isBlocked,isGameBlocked,extAccountInfo"}, cache : false, async : true, dataType : "jsonp", success : function(response) { ...
这种方式ajax没有X-Requested_With字段,回包数据为网页数据。c++实现方式如下:
MSXML2::IXMLHTTPRequestPtr m_pIXMLHTTPRequest; m_pIXMLHTTPRequest.CreateInstance("Msxml2.XMLHTTP.6.0"); std::wstring CWebLoginDlg::XMLHttpRequest( std::wstring url , std::string requestType/* = "GET"*/) { BSTR bstrString = NULL; HRESULT hr=m_pIXMLHTTPRequest->open(requestType.c_str(), url.c_str(), false); SUCCEEDED(hr) ? 0 : throw hr; m_pIXMLHTTPRequest->setRequestHeader("X-Requested-With", "XMLHttpRequest"); //这里第二种情况则不能带有此字段 m_pIXMLHTTPRequest->setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); hr=m_pIXMLHTTPRequest->send(); SUCCEEDED(hr) ? 0 : throw hr; bstrString=m_pIXMLHTTPRequest->responseText; //第二种情况则m_pIXMLHTTPRequest->responseBody std::wstring freePayString = bstrString; if (bstrString) { SysFreeString(bstrString); bstrString = NULL; } return freePayString; }
这里提供一个技巧,找到ajax代码的实现,可以先抓包得到http header里面的request url的url字符串,然后在脚本里面去查找字符串,一般字符串就在ajax代码
url : getDomain() + "rest/user"里面搜索到,搜索到后可以看代码对于返回值的处理,这样才好方便写逻辑。
最后说下获取网页元素,一般来说网页元素都会带有ID或者带有ClassName,例如网页代码:
<input type="password" id="pwd" name="password" class="user_pw" maxlength="16" size="12" autocomplete="off" title="???? ??">
如果想通过ID获取网页对象,简单的可以直接通过GetElement函数来实现,C++代码如下:
IHTMLElement *id = NULL; this->GetElement(TEXT("id"), &id);如果想通过ClassName类名来获取网页对象,C++代码如下:
CComQIPtr< IHTMLElement > CWebLoginDlg::GetElementByClassName( std::wstring className ) { CComPtr<IHTMLDocument2> pIHTMLDocument2; GetDHtmlDocument(&pIHTMLDocument2); HRESULT hr; CComQIPtr< IHTMLElementCollection > spElementCollection; hr = pIHTMLDocument2->get_all( &spElementCollection ); //取得表单集合 if ( FAILED( hr ) ) { ATLTRACE("获取集合 IHTMLElementCollection 错误"); } long nFormCount=0; hr = spElementCollection->get_length( &nFormCount ); if ( FAILED( hr ) ) { ATLTRACE("获取数目错误"); } IDispatch *pDisp = NULL; CComQIPtr< IHTMLElement > ret = pDisp; for(long i=0; i<nFormCount; i++) { pDisp = NULL; hr = spElementCollection->item( CComVariant( i ), CComVariant(), &pDisp ); if ( FAILED( hr ) ) { continue; } CComQIPtr< IHTMLElement > pElement = pDisp; pDisp->Release(); CComBSTR varRet; hr = pElement->get_className(&varRet); if (FAILED(hr)) { continue; } if (varRet == NULL) { continue; } LPCTSTR lpName = OLE2CT( varRet ); if (std::wstring(lpName) == className) { ret = pElement; break; } } return ret; }
以上就是模拟网页中获取网页状态的基本函数,有了这几个函数网页模拟方式的基本框架基本都可以搭建起来了。
相关文章推荐
- 模拟网页行为之实践篇三
- 模拟网页行为之实践四
- 模拟网页行为之实践篇二
- 模拟网页行为之工具篇二
- 在事件触发的时候,有时我们需要一些模拟用户行为的操作。例如:当网页加载完毕后 自行点击一个按钮触发一个事件,而不是用户去点击。
- 模拟用户行为,post数据到网页
- 通过Mechanize模拟自然的浏览器行为来完成与网页之间的交互.
- 模拟网页行为之工具篇
- 用python模拟一个文本浏览器来抓取网页
- 模拟网页访问的工具-htmlunit
- JQuery 模拟youtube的网页加载特效
- 多个账户模拟登录---c#异步模拟登录网站并采集网页
- 毫秒必争,前端网页性能最佳实践
- steering behaviors 转向行为 集群模拟 小结
- 文档视图结构中,定制其行为的一次实践
- 【转】详解抓取网站,模拟登陆,抓取动态网页的原理和实现(Python,C#等)
- 分析用户的网页浏览行为与习惯
- 修改网页超链接的默认行为 <a> _blank _self _parent
- 湘潭大学2017年下学期程序设计实践-模拟测试2 题解
- python基础实践(一)模拟用户登录