模拟网页行为之实践篇二

在模拟网页行为中,最常用的就是提交表单了,其次就是获取验证图片数据,再次hook网页中的js代码的实现。


先说具体的应用场景,简单的场景,如填写用户名密码登陆,这里就涉及到获取表单,填写表单数据,提交表单三个过程。

在网页数据中,表单的形式一般都会带有名字,ID,提交的处理网页的url和其拥有的几个IHTMLInputElement元素,具体网页代码如下:

<form name="loginFrm1" id="loginFrm1" method="post" action="https://mlogin.plaync.com/login/signin"><input type="hidden" name="return_url" value="http://lineage.plaync.com/"><fieldset><legend>로그인</legend><div class="selectId"><select name="game_id"><option value="13">통합계정</option><option value="31">게임계정</option></select></div><div class="login_input"><input type="text" id="id" name="login_name" maxlength="64" size="12" class="user_id" autocomplete="off" title="아이디 또는 이메일 입력"><input type="password" id="pwd" name="password" class="user_pw" maxlength="16" size="12" autocomplete="off" title="비밀번호 입력"><input type="button" name="login" value="로그인" class="submit"></div></fieldset><ul class="member"><li class="join"><a href="http://go.plaync.co.kr/Account/Join">회원가입</a></li><li class="find"><a href="http://go.plaync.co.kr/Account/SearchAccount">계정</a>/<a href="http://go.plaync.co.kr/Account/SearchPassword">비밀번호찾기</a></li></ul><div class="custom"><a class="new" href="http://lineage.plaync.com/service/freepay/index"><i></i>처음이신가요?</a><a class="comming" href="http://lineage.plaync.com/service/returnbrave/index"><i></i>오랜만이신가요?</a></div></form>
可以看到,表单名字为loginFrm1,ID为loginFrm1,提交的url为https://mlogin.plaync.com/login/signin,拥有的几个元素login_name, password,login。

首先获取表单,基本原理也是找到DOC,然后通过get_forms找到表单的集合,然后遍历表单找到名字为loginfrm1的表单对象IHTMLFormElement将之返回。c++代码如下:

CComQIPtr< IHTMLFormElement > CWebLoginDlg::GetFormByName( std::wstring name )
{
	IDispatch *pDisp = NULL;
	CComQIPtr< IHTMLFormElement > ret = pDisp;

	CComPtr<IHTMLDocument2> pIHTMLDocument2;
	GetDHtmlDocument(&pIHTMLDocument2);
	if (pIHTMLDocument2 == NULL)
	{
		return ret;
	}
	HRESULT hr;  
	CComBSTR bstrTitle;  
	pIHTMLDocument2->get_title( &bstrTitle );

	CComQIPtr< IHTMLElementCollection > spElementCollection;  
	hr = pIHTMLDocument2->get_forms( &spElementCollection ); //取得表单集合  
	if ( FAILED( hr ) )  
	{
		ATLTRACE("获取表单的集合 IHTMLElementCollection 错误");
	}  

	long nFormCount=0;
	hr = spElementCollection->get_length( &nFormCount );  
	if ( FAILED( hr ) )  
	{
		ATLTRACE("获取表单数目错误");
	}  

	for(long i=0; i<nFormCount; i++)  
	{  
		pDisp = NULL;
		hr = spElementCollection->item( CComVariant( i ), CComVariant(), &pDisp );  
		if ( FAILED( hr ) )  
		{
			continue;
		}
		CComQIPtr< IHTMLFormElement > spFormElement = pDisp;
		pDisp->Release();

		long nElemCount=0; 
		hr = spFormElement->get_length( &nElemCount );
		if ( FAILED( hr ) )  
		{
			continue;
		}
		CComBSTR formName;
		hr = spFormElement->get_name(&formName);
		if (FAILED(hr))
		{
			continue;
		}

		LPCTSTR lpName = OLE2CT(formName);
		if (std::wstring(lpName) == name)
		{
			ret = spFormElement;
		}
	}
	return ret;
}

其次填写表单,基本原理是通过get_length获取表单域个数,然后遍历表单域元素,通过GetpropertyByName找到需要填写的元素,然后用PutPropertyByName填写表单值,具体c++实现如下:

void CWebLoginDlg::InputFormElement( CComQIPtr< IHTMLFormElement > spFormElement, std::map<std::wstring, std::wstring> formDataList )
{
	if (spFormElement != NULL)
	{
		long nElemCount=0; 
		HRESULT hr = spFormElement->get_length( &nElemCount );
		for(long j=0; j<nElemCount; j++)  
		{  
			CComDispatchDriver spInputElement; //取得第 j 项表单域  
			hr = spFormElement->item( CComVariant( j ), CComVariant(), &spInputElement );  
			if ( FAILED( hr ) ) continue;

			CComVariant vName,vVal,vType;  //取得表单域的 名,值,类型  
			hr = spInputElement.GetPropertyByName( L"name", &vName );  
			if( FAILED( hr ) ) continue;
			hr = spInputElement.GetPropertyByName( L"value", &vVal ); 
			if( FAILED( hr ) ) continue;
			hr = spInputElement.GetPropertyByName( L"type", &vType );  
			if( FAILED( hr ) ) continue; 

			LPCTSTR lpName = vName.bstrVal?  OLE2CT( vName.bstrVal ) : _T("NULL");
			LPCTSTR lpVal  = vVal.bstrVal?  OLE2CT( vVal.bstrVal  ) : _T("NULL");
			LPCTSTR lpType = vType.bstrVal?  OLE2CT( vType.bstrVal ) : _T("NULL");

			ATLTRACE(L"old name:%s, lpVal:%s lpType:%s", lpName, lpVal, lpType);

			if (formDataList.find(lpName) != formDataList.end())
			{
				CComVariant vContent(formDataList[lpName].c_str());
				spInputElement.PutPropertyByName(L"value", &vContent);
			}

			hr = spInputElement.GetPropertyByName( L"name", &vName );  
			if( FAILED( hr ) ) continue;  
			hr = spInputElement.GetPropertyByName( L"value", &vVal ); 
			if( FAILED( hr ) ) continue;  
			hr = spInputElement.GetPropertyByName( L"type", &vType );  
			if( FAILED( hr ) ) continue; 

			lpName = vName.bstrVal?  OLE2CT( vName.bstrVal ) : _T("NULL");
			lpVal  = vVal.bstrVal?  OLE2CT( vVal.bstrVal  ) : _T("NULL");
			lpType = vType.bstrVal?  OLE2CT( vType.bstrVal ) : _T("NULL");

			ATLTRACE(L"new name:%s, lpVal:%s lpType:%s", lpName, lpVal, lpType);
		}
	}
}

最后提交表单,这个很简单,首先找到提交按钮对象,然后调用对象接口click,即可实现提交表单,具体c++代码实现如下:

CComQIPtr< IHTMLElement > pButton = GetElementByClassName(L"login");
if (pButton != NULL)
{
    ATLTRACE("dologin");
    pButton->click();
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值