qq邮箱自动登录
最近想写一个自动登录邮箱的程序,比如qq邮箱(https://mail.qq.com/cgi-bin/loginpage?flowid=186679953232973719)
一下子感觉无从下手,特别是怎么自动识别验证码,让人头大,求大神给个思路,最好能给出可用的代码,谢谢!
[解决办法]
先用图像算法对验证码进行去噪、分割、识别,获取验证码值,然后用webbrowser获取邮箱接口,提交账号、密码和验证码值即可。
下面的代码希望对你有用,GoodLuck!
- C/C++ code
// IEDoingDlg.h : 头文件//#pragma once#include "explorer1.h"// 所以声明它是必须的#include <atlcom.h> #include <mshtmhst.h>#include <mshtml.h>// CIEDoingDlg 对话框class CIEDoingDlg : public CDialog{// 构造public:CIEDoingDlg(CWnd* pParent = NULL); // 标准构造函数// 对话框数据enum { IDD = IDD_IEDOING_DIALOG };protected:virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持// 实现protected:HICON m_hIcon;// 生成的消息映射函数virtual BOOL OnInitDialog();afx_msg void OnPaint();afx_msg HCURSOR OnQueryDragIcon();DECLARE_MESSAGE_MAP()public:CExplorer1 m_web;DECLARE_EVENTSINK_MAP()void DocumentCompleteExplorer1(LPDISPATCH pDisp, VARIANT* URL);//浏览器全部加载完全afx_msg void OnBnClickedOk();// 设置名字void OnSetName(void);void SetName(IHTMLDocument2 * pIHTMLDocument2);// 模拟输入密码void OnPass(void);void OnSetPass(IHTMLDocument2 * pIHTMLDocument2);// 点击按扭void OnClickRegBtn(IHTMLElementCollection * pElemColl, CString strElementId);// 类型转化VARIANT StringToVariant(CString str);// 认证码图片取得void OnGetCode(void);afx_msg void OnEnChangeEdit1();// 调用验证码输入void OnCode(void);// 传递验证码void OnSetPassCode(IHTMLDocument2 * pIHTMLDocument2);// 输入的验证码CString m_code;afx_msg void OnBnClickedButton1();};BOOL CIEDoingDlg::OnInitDialog(){CDialog::OnInitDialog();// 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动// 执行此操作SetIcon(m_hIcon, TRUE); // 设置大图标SetIcon(m_hIcon, FALSE); // 设置小图标// TODO: 在此添加额外的初始化代码 m_web.Navigate(_T("https://mail.qq.com/cgi-bin/loginpage?flowid=186679953232973719"),NULL,NULL,NULL,NULL);return TRUE; // 除非将焦点设置到控件,否则返回 TRUE}// 如果向对话框添加最小化按钮,则需要下面的代码// 来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,// 这将由框架自动完成。void CIEDoingDlg::OnPaint(){if (IsIconic()){ CPaintDC dc(this); // 用于绘制的设备上下文 SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0); // 使图标在工作区矩形中居中 int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // 绘制图标 dc.DrawIcon(x, y, m_hIcon);}else{ CDialog::OnPaint();}}//当用户拖动最小化窗口时系统调用此函数取得光标//显示。HCURSOR CIEDoingDlg::OnQueryDragIcon(){return static_cast<HCURSOR>(m_hIcon);}BEGIN_EVENTSINK_MAP(CIEDoingDlg, CDialog)ON_EVENT(CIEDoingDlg, IDC_EXPLORER1, 259, CIEDoingDlg::DocumentCompleteExplorer1, VTS_DISPATCH VTS_PVARIANT)END_EVENTSINK_MAP()void CIEDoingDlg::DocumentCompleteExplorer1(LPDISPATCH pDisp, VARIANT* URL){// TODO: 在此处添加消息处理程序代码 CString strUrl;HRESULT hr;IUnknown* pUnk;LPDISPATCH lpWBDisp;pUnk = m_web.GetControlUnknown();ASSERT(pUnk);hr = pUnk->QueryInterface(IID_IDispatch, (void**)&lpWBDisp);ASSERT(SUCCEEDED(hr));strUrl=URL->bstrVal;int iurl; iurl=strUrl.Find(_T("cctrydefault"));if (iurl!=-1){ OnPass(); OnGetCode();}else{ if (pDisp == lpWBDisp){ OnSetName();}}}
[解决办法]
汗,内容过长,接着发。
- C/C++ code
void CIEDoingDlg::OnBnClickedOk(){ // TODO: 在此添加控件通知处理程序代码 OnOK();}// 设置名字void CIEDoingDlg::OnSetName(void){::CoInitialize(NULL); //初始化 COM 公寓CComQIPtr < IHTMLDocument2 > spDoc =m_web.get_Document();SetName(spDoc);::CoUninitialize();}//输入名字void CIEDoingDlg::SetName(IHTMLDocument2 * pIHTMLDocument2){if( !pIHTMLDocument2 ) { return; } HRESULT hr; CComBSTR bstrTitle; pIHTMLDocument2->get_title( &bstrTitle ); //取得文档标题 CComQIPtr< IHTMLElementCollection > spElementCollection; hr = pIHTMLDocument2->get_forms( &spElementCollection ); //取得表单集合 CComQIPtr< IHTMLElement > pIHTMLEle; hr =pIHTMLDocument2->get_body(&pIHTMLEle); //读取文档 if ( FAILED( hr ) ) { return; } long nFormCount=0; //取得表单数目 hr = spElementCollection->get_length( &nFormCount ); if ( FAILED( hr ) ) { return; } CString str; for(long i=0; i<nFormCount; i++) { IDispatch *pDisp = NULL; //取得第 i 项表单 hr = spElementCollection->item( CComVariant( i ), CComVariant(), &pDisp ); if ( FAILED( hr ) ) continue;//表单是<input type="text" default_txt="QQ号或邮箱帐号" id="uin" name="uin" value="" tabindex="1" style="ime-mode: disabled;" class="text" /> CComQIPtr< IHTMLFormElement > spFormElement = pDisp; pDisp->Release(); long nElemCount=0; //取得表单中 域 的数目 hr = spFormElement->get_length( &nElemCount ); if ( FAILED( hr ) ) continue; USES_CONVERSION; for(long j=0; j<nElemCount; j++) { CComDispatchDriver spInputElement; //取得第 j 项表单域 hr = spFormElement->item( CComVariant( j ), CComVariant(), &spInputElement ); if ( FAILED( hr ) ) continue;//表单域是 type="text" default_txt="QQ号或邮箱帐号" id="uin" name="uin" value="" tabindex="1" style="ime-mode: disabled;" class="text" CComVariant vID, vType; hr = spInputElement.GetPropertyByName( L"id", &vID ); if( FAILED( hr ) ) continue; hr = spInputElement.GetPropertyByName( L"type", &vType ); if( FAILED( hr ) ) continue; LPCTSTR lpVID = vID.bstrVal ? OLE2CT( vID.bstrVal ) : _T("NULL"); LPCTSTR lpType = vType.bstrVal ? OLE2CT( vType.bstrVal ) : _T("NULL"); CString strID(lpVID), strType(lpType); if (strID.CompareNoCase(_T("uin")) == 0 && strType.CompareNoCase(_T("text")) == 0){ //是邮箱编辑框 CComVariant vSetValue(_T("cctrydefault")); spInputElement.PutPropertyByName(L"value", &vSetValue ); //填写表单域 } spFormElement->submit();//刷新窗体 } pDisp->Release(); }}// 模拟输入密码void CIEDoingDlg::OnPass(void){ ::CoInitialize(NULL); //初始化 COM 公寓 CComQIPtr < IHTMLDocument2 > spDoc =m_web.get_Document(); OnSetPass(spDoc); ::CoUninitialize();}void CIEDoingDlg::OnSetPass(IHTMLDocument2 * pIHTMLDocument2){ IHTMLElementCollection* pElemColl = NULL; HRESULT hr1 = pIHTMLDocument2->get_all( &pElemColl ); //取得框架frame的集合 if( !pIHTMLDocument2 ) { return; } HRESULT hr; CComBSTR bstrTitle; pIHTMLDocument2->get_title( &bstrTitle ); //取得文档标题 CComQIPtr< IHTMLElementCollection > spElementCollection; hr = pIHTMLDocument2->get_forms( &spElementCollection ); //取得表单集合 CComQIPtr< IHTMLElement > pIHTMLEle; hr =pIHTMLDocument2->get_body(&pIHTMLEle); if ( FAILED( hr ) ) { return; } long nFormCount=0; //取得表单数目 hr = spElementCollection->get_length( &nFormCount ); if ( FAILED( hr ) ) { return; } for(long i=0; i<nFormCount; i++) { IDispatch *pDisp = NULL; //取得第 i 项表单 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; USES_CONVERSION; for(long j=0; j<nElemCount; j++) { CComDispatchDriver spInputElement; //取得第 j 项表单域 hr = spFormElement->item( CComVariant( j ), CComVariant(), &spInputElement ); if ( FAILED( hr ) ) continue; CComVariant vID, vType; hr = spInputElement.GetPropertyByName( L"id", &vID ); if( FAILED( hr ) ) continue; hr = spInputElement.GetPropertyByName( L"type", &vType ); if( FAILED( hr ) ) continue; LPCTSTR lpVID = vID.bstrVal ? OLE2CT( vID.bstrVal ) : _T("NULL"); LPCTSTR lpType = vType.bstrVal ? OLE2CT( vType.bstrVal ) : _T("NULL"); CString strID(lpVID), strType(lpType); if (strID.CompareNoCase(_T("pp")) == 0 && strType.CompareNoCase(_T("password")) == 0){ //是确认密码编辑框 //GetUserNameFocus(); CComVariant vSetValue(_T("cctry123")); spInputElement.PutPropertyByName(L"value", &vSetValue ); } OnClickRegBtn(pElemColl,_T("btlogin")); } pDisp->Release(); } //OnEnChangeEdit1();}// 点击按扭void CIEDoingDlg::OnClickRegBtn(IHTMLElementCollection * pElemColl, CString strElementId){ IDispatch *pDisp; HRESULT hr; VARIANT index; VARIANT varID; V_VT(&index) = VT_I4; V_I4(&index) = 0; varID = StringToVariant(strElementId); hr = pElemColl->item(varID, index, &pDisp); // 获得按钮位置 if ( (hr == S_OK) && (pDisp != NULL) ) { IHTMLElement* pElem = NULL; // 获得按钮元素接口 hr = pDisp->QueryInterface(IID_IHTMLElement, (void**)&pElem); if ( (hr == S_OK) && (pElem != NULL) ) { pElem->click(); // 点击按钮 pElem->Release(); } pDisp->Release(); }}// 类型转化VARIANT CIEDoingDlg::StringToVariant(CString str){ VARIANT variant; VariantInit(&variant); variant.vt = VT_BSTR; variant.bstrVal = str.AllocSysString(); return variant;}// 认证码图片取得void CIEDoingDlg::OnGetCode(void){ CString path; GetCurrentDirectory(MAX_PATH,path.GetBuffer(MAX_PATH)); path+=_T("\\Num.BMP"); URLDownloadToFile(NULL,_T("https://mail.qq.com/cgi-bin/getverifyimage?aid=23000101&f=html&ck=1&41202"),path ,0,NULL); CString strPath =path; CImage img; HRESULT hr; hr = img.Load(strPath); if(!img.IsNull()) { HBITMAP hBitmap = img.Detach(); CStatic* pStatic = (CStatic*)GetDlgItem(IDC_STATIC); if (pStatic != NULL) { pStatic->SetBitmap(hBitmap); } }}