我第一次是用ChtmlView做的,很简单:
IHTMLElementCollection *objAllElement=NULL;
IHTMLDocument2 *objDocument=NULL;
objDocument=(IHTMLDocument2 *)this->GetHtmlDocument();; //由控件得到IHTMLDocument2接口指针
objDocument->get_all(&objAllElement); //得到网页所有元素的集合
另外要注意的就是那个CComBSTR/CComVariant还需要学习。
[自动登录]|[模拟鼠标]|[自动投票]|[填写表单]
每天登录签到确实挺麻烦的:
1)打开网页,登录,经过一些步骤进入签到框,然后点击。。。
2)有的时候会忘了签退,这可要扣饭补地。。。
3)啥时候有急事儿,可以让他自己签退。。。
所以,我就看了一些自动填写表单,自动投票机的程序;发现在MFC中可以利用一些控件和接口来实现。实际上,采用模拟鼠标的方法就不用任何接口了, 只需要把操作步骤给程序;但是这样需要去计算那些控件的坐标,同时模拟的还有键盘输入等,总而言之,虽然易懂,却是繁琐。所以,这里采用接口。
1)头文件 #include "mshtml.h" 库 #pragma comment(lib,"Wininet.lib")
2)控件 MS Web Browser变量 CWebBrowser m_WebBrowser
3)利用WebBrowser可以得到网页的内容,然后采用它的GetDocument方法得到网页文件;再把文件中的元素取出来,就可以操作这些元素了,比如填写表狂,点击按钮等。
// Connect the website
CString szConnectString = http://www.xxx.com/xxx.aspx;
m_WebBrowser.Navigate(szConnectString,NULL,NULL,NULL,NULL);
// Get the doc and elments
IDispatch * pDispatch = NULL;
IHTMLDocument2 * pDoc = NULL;
IHTMLElementCollection * objAllElement = NULL; // element collections
long nElementCount; // the count of elements
pDispatch = m_WebBrowser.GetDocument();
ASSERT(pDispatch);
HRESULT hr = pDispatch->QueryInterface(IID_IHTMLDocument2,(void**)&pDoc);
pDoc->get_all(&objAllElement);
ASSERT(objAllElement);
objAllElement->get_length(&nElementCount);
// Handle each element
VARIANT name;
name.vt = VT_I4;
for(int i = 0;i < nElementCount;i ++)
{
name.lVal = i;
IDispatch * pDispatch = NULL;
objAllElement->item(name,name,&pDispatch);
IHTMLElement* spElement = NULL;
pDispatch->QueryInterface(IID_IHTMLElement, (void**)&spElement);
// Attibute
CComVariant varAttribute;
CComBSTR bstrName("NAME");
CComBSTR bstrValue;
spElement->getAttribute(bstrName,0,&varAttribute);
if (SUCCEEDED(varAttribute.ChangeType(VT_BSTR)))
{
bstrValue = varAttribute.bstrVal;
if (bstrValue == _T("id"))
{
bstrValue = _T(szUser.GetBuffer(0)); // szUser是用户名
spElement->put_innerText(bstrValue);
}
else if(bstrValue == _T("passwd"))
{
bstrValue = _T(szPass.GetBuffer(0));// szPass是密码
spElement->put_innerText(bstrValue);
}
}
// Click
bstrName = _T("VALUE");
spElement->getAttribute(bstrName,0,&varAttribute);
if (SUCCEEDED(varAttribute.ChangeType(VT_BSTR)))
{
bstrValue = varAttribute.bstrVal;
if (bstrValue == _T("登录"))// 这里是个按钮,如果是个图标也做类似的处理
{
spElement->click();
}
}
spElement->Release();
}
其它的步骤都类似了,比如进入某个填表的网页,也是先Navigate->GetDoc->GetElements->...,这样就完成自动登录,自动。。。了。
这是我写的 可以运行哦
- {
- // TODO: Add your command handler code here
- // TODO: Add your command update UI handler code here
- using namespace std;
- ofstream pFile(_T("C:/MYTXT.txt"));
- IHTMLElementCollection *objAllElement=NULL;
- IHTMLDocument2 *objDocument=NULL;
- objDocument=(IHTMLDocument2 *)this->GetHtmlDocument();; //由控件得到IHTMLDocument2接口指针
- objDocument->get_all(&objAllElement); //得到网页所有元素的集合
- IHTMLElement * pElem = NULL;
- VARIANT name;
- CComBSTR tag;
- long a;
- objAllElement->get_length(&a);
- name.vt=VT_I4;
- IHTMLElement* spElement;
- for(int i=0;i<a;i++)//遍历所有元素
- {
- name.lVal = i;
- IDispatch * pDispatch=NULL;
- objAllElement->item(name,name,&pDispatch);
- pDispatch->QueryInterface(IID_IHTMLElement, (void**)&spElement);
- /*
- CComBSTR tag;
- //spElement->get_outerText(&tag);
- //spElement->get_innerText(&tag);
- //spElement->toString(&tag);
- //spElement->get_tagName(&tag);
- //spElement->get_title(&tag);
- CComVariant ve2;
- CComBSTR bstrValue;
- spElement-> getAttribute(CComBSTR("name"),0,&ve2);
- if (SUCCEEDED(ve2.ChangeType(VT_BSTR)))
- { //ve2.ChangeType(VT_BSTR);
- //CString ss(ve2.bstrVal);
- bstrValue=ve2.bstrVal;
- if (bstrValue == _T("wd"))
- {
- pFile<<"wd"<<endl;
- }
- }
- //CString ss;
- //if(ss=="")
- // spElement->click();
- //MessageBox((LPCSTR)ss);
- }
- //CComPtr pDisp;
- //pobjAllElement->item(COleVariant(strName),COleVariant((long)0),&pDisp);
- //CComQIPtr<IHTMLElement, &IID_IHTMLElement>pElement;
- /*
- CComPtr pDisp;
- CString strName="wd";
- objAllElement->item(COleVariant(strName),COleVariant((long)0),&pDisp);
- CComQIPtr<IHTMLElement, &IID_IHTMLElement>pElement;
- if(pDisp==NULL)
- {
- AfxMessageBox(strName + "没有找到!");
- }
- else
- {
- pElement=pDisp;
- //pElement->click();
- }*/
- CComVariant varAttribute;
- CComBSTR bstrName("name");
- CComBSTR bstrValue;
- spElement->getAttribute(bstrName,0,&varAttribute);
- if (SUCCEEDED(varAttribute.ChangeType(VT_BSTR)))
- {
- bstrValue = varAttribute.bstrVal;
- if (bstrValue == _T("wd"))
- {
- bstrValue = _T("Yeah!成功了!"); // szUser是用户名
- spElement->put_innerText(bstrValue);
- }
- }
- // Click
- bstrName = _T("value");
- spElement->getAttribute(bstrName,0,&varAttribute);
- if (SUCCEEDED(varAttribute.ChangeType(VT_BSTR)))
- {
- bstrValue = varAttribute.bstrVal;
- if (bstrValue == _T("百度一下"))// 这里是个按钮,如果是个图标也做类似的处理
- {
- spElement->click();
- }
- }
- }
- //ATLTRACE(L"%s",ve2.bstrVal);
- spElement->Release();
- }
千方百计得到IHTMLDocument2的接口指针
根据IE浏览器的运行方式,有多种不同的方式可以获取文档指针。
<1> 如果你在程序中使用MFC的 CHtmlView 视来浏览网页。
取得文档的方法最简单,调用 CHtmlView::GetHtmlDocument() 函数。
<2> 如果你的程序中使用了“Web 浏览器” 的ActiveX 控件。
取得文档的方法也比较简单,调用 CWebBrowser2::GetDocument() 函数。
<3> 如果你的程序是用 ATL 写的 ActiveX 控件。
那么需要调用 IOleClientSite::GetContainer 得到 IOleContainer 接口,然后就可以通过 QueryInterface() 查询得到 IHTMLDocument2 的接口。主要代码如下:
CComPtr < IOleContainer > spContainer;
m_spClientSite->GetContainer( &spContainer );
CComQIPtr < IHTMLDocument2 > spDoc = spContainer;
if ( spDoc )
{
// 已经得到了 IHTMLDocument2 的接口指针
}