C# 控制操作火狐浏览器部分功能实现

来源:互联网 发布:中国移动数据家庭联盟 编辑:程序博客网 时间:2024/06/11 11:32

 

最近在做了一个网站数据采集,

不过需要登录采集数据,非常恶心的事情是,无法登录, 部分信息加载不到,即便用 webbrowser 也登录不了,这一单让我非常恼火.

最后么有办法只能采用读取本地cookies 达到登录效果。

即先人工在本地登录,程序获取cookies 文件,遍历到该网站获取对应的 cookie信息。完美解雇登录问题。

在 cookies 文件中可以看到很多信息。大部分网站的本地cookie都是保存登录结果的。

一般情况都是用变量进行标记, true 登录 false 未登录大概就是这个意思。具体的需要获取登录未登录然后比对, 也有很多在登录后直接显示用户名, 极少数能看见密码的,罕见情况居然密码是明文, 什么站点我就不说了,不过这个问题确实存在,我见过提交密码用明文的,但是在cookie用明文保存密码我就只能呵呵了。

 

废话不说了先发代码。 对应获取本地cookies文件返回 CookieContainer

以下是firefox浏览器的例子

 public static CookieContainer GetCookie(string url, ref bool islogin)        {            CookieContainer cookiecontainer = newCookieContainer();            try            {                DirectoryInfo di = new DirectoryInfo(System.Environment.GetEnvironmentVariable("AppData")+ @"\Mozilla\Firefox\Profiles\");                DirectoryInfo[] dirs = di.GetDirectories();                if (dirs != null) dbPath =dirs[0].FullName + "\\cookies.sqlite";                DataTable dt = GetTable("select* from moz_cookies where baseDomain=@baseDomain", new SQLiteParameter("baseDomain",url));                foreach (DataRow row in dt.Rows)                {                    try                    {                        if (row["name"].ToString().ToLower()== "liap")                        {                            islogin = row["value"].ToString().ToUpper()== "TRUE" ? true : false;                        }                        cookiecontainer.Add(newCookie                        {                            Name = row["name"].ToString()                            ,                            Value = row["value"].ToString()                            ,                            Path = row["path"].ToString()                            ,                            Domain = row["host"].ToString()                        });                    }                    catch (Exception)                    {                    }                    finally { }                }            }            catch (Exception)            {                throw;            }            return cookiecontainer;        }         public static DataTable GetTable(stringsql, params SQLiteParameter[] pms)        {            using (SQLiteConnection conn = new SQLiteConnection("DataSource =" + dbPath))            {                using (SQLiteDataAdapteradapter = new SQLiteDataAdapter(sql, conn))                {                    DataTable dt = new DataTable();                    if (pms != null)                    {                        adapter.SelectCommand.Parameters.AddRange(pms);                    }                    conn.Open();                    adapter.Fill(dt);                    return dt;                }            }       }


 

以上代码需要引用 SQLite.Interop.dll,System.Data.SQLite.dll 根据系统不同 自行选择版本 x32 x64

 

当解决登录问题后我又遇到另一个棘手的问题,部分页面还是无法用 HttpWebRequest 获取到源码,后台经过调试发现页面在浏览器打开一次后在使用 httpwebrequest 就可以拿到了,没有具体研究到底是什么机制导致这个问题的,  个人感觉应该是cookie取的不全,没办法 想到了另一种折中的解决方案 即先用浏览器求情一次 然后继续执行我的 HttpWebRequest,当然这里的浏览器打开 即可关闭。因为这个请求 不需要有返回结果。只要向服务器发送一次请求即可。所以这里不会影响到采集数据的速度。

 

 

 

当然一定要打开我获取cookie的那个浏览器即 本案例使用到的 firefox,下面代码是 获取本地浏览器安装位置以及创建快捷方式的方法。

PS:创建快捷 一定要记得 设置浏览器默认最下化,该设置在快捷方式设置即可,避免影响用户体验。

调用

 string   firelik = System.AppDomain.CurrentDomain.BaseDirectory+ @"\Mozilla Firefox.lnk";                    if (!File.Exists(firelik)) FirefoxCookie.Shortcuts(firelik); public static void Shortcuts(stringfirelik)        {            try            {                string firepath = "";                // 在这里 获取本机火狐安装目录                              RegistryKey browsersKey;                browsersKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\WOW6432Node\Clients\StartMenuInternet");                if (browsersKey == null)                    browsersKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Clients\StartMenuInternet");                using (browsersKey)                {                    string[] subKeys =browsersKey.GetSubKeyNames();                    string locationPath = @"\shell\open\command";                    foreach (string key insubKeys)                    {                        if (key == "FIREFOX.EXE")                        {                            RegistryKeyappLocationKey = browsersKey.OpenSubKey(key + locationPath);                            firepath =appLocationKey.GetValue(null).ToString().Trim('"');                            appLocationKey.Dispose();                            break;                        }                    }                }                 IWshRuntimeLibrary.WshShellshell = new IWshRuntimeLibrary.WshShellClass();                IWshRuntimeLibrary.IWshShortcutshortcut = (IWshRuntimeLibrary.IWshShortcut)shell.CreateShortcut(firelik);  // 快捷位置                shortcut.TargetPath = firepath;  // 关联文件位置                shortcut.Hotkey = "CTRL+SHIFT+5";  // 设置快捷热键 可选                shortcut.WindowStyle = 7;   // 最小化                shortcut.IconLocation =firepath + ",0";  // 设置 ico 图标 ,                shortcut.Save();            }            catch (Exception ex)            {                //  throw;            }            finally { }       }


 

 

OK  全部搞定了,可以正常采集数据了。但是我又遇到了另一个问题,哎每次打开快捷方式开启浏览器后都会新增一个标签页,页面不停的开标签页…. 

可惜firefox 没有API ,C#控制firefox也基本是不可能的,没办法只能从 系统API着手了。。谁让我最开始选择FF呢。。。

有一个比较不错的工具但是需要 java JKD支持,所以果断放弃了。

Selenium” 有兴趣的同学可以研究下

 


当然 C# 对 IE 还是比较好控制的

 

有困难就要上呀,因为不能有效控制浏览器所以最后的解决方案就是关闭最后打开的标签页。

通过向Firefox Handle 发送按键消息 CTRL+F4 关闭最后一个标签页。

具体代码如下:

下面将FirefoxCookieFirefoxHandle两个完整类贴出来,



   class FirefoxHandle    {         internal const uint GW_OWNER = 4;        internal delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);        [DllImport("User32.dll", CharSet = CharSet.Auto)]        internal static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam);        [DllImport("User32.dll", CharSet = CharSet.Auto)]        internal static extern int GetWindowThreadProcessId(IntPtr hWnd, out IntPtr lpdwProcessId);        [DllImport("User32.dll", CharSet = CharSet.Auto)]        internal static extern IntPtr GetWindow(IntPtr hWnd, uint uCmd);        [DllImport("User32.dll", CharSet = CharSet.Auto)]        internal static extern bool IsWindowVisible(IntPtr hWnd);        public static IntPtr GetMainWindowHandle(int processId)        {            IntPtr MainWindowHandle = IntPtr.Zero;            EnumWindows(new EnumWindowsProc((hWnd, lParam) =>            {                IntPtr PID;                GetWindowThreadProcessId(hWnd, out PID);                if (PID == lParam &&                    IsWindowVisible(hWnd) &&                    GetWindow(hWnd, GW_OWNER) == IntPtr.Zero)                {                    MainWindowHandle = hWnd;                    return false;                }                return true;            }), new IntPtr(processId));            return MainWindowHandle;        }        public static void GetFirefoxHandle()        {            int iProcId = 0;            Process[] procList = new Process[100];            procList = Process.GetProcesses();            foreach (Process p in procList)            {                if ("firefox" == p.ProcessName)                {                    iProcId = p.Id;                    break;                }            }            IntPtr intptr = GetMainWindowHandle(iProcId);            SendCtrlF4(intptr);        }        [DllImport("User32.dll")]        private static extern bool SetForegroundWindow(IntPtr hWnd);        [DllImport("user32.dll", CharSet = CharSet.Auto)]        static public extern IntPtr GetForegroundWindow();        [DllImport("user32.dll")]        static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, uint dwExtraInfo);        private static void SendCtrlF4(IntPtr hWnd)        {            uint KEYEVENTF_KEYUP = 2;            byte VK_CONTROL = 0x11;            SetForegroundWindow(hWnd);            keybd_event(VK_CONTROL, 0, 0, 0);            keybd_event(0x73, 0, 0, 0);            keybd_event(0x73, 0, KEYEVENTF_KEYUP, 0);            keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);        }    }static class FirefoxCookie    {        private static string dbPath = string.Empty;        public static CookieContainer GetCookie(string url, ref bool islogin)        {            CookieContainer cookiecontainer = new CookieContainer();            try            {                DirectoryInfo di = new DirectoryInfo(System.Environment.GetEnvironmentVariable("AppData") + @"\Mozilla\Firefox\Profiles\");                DirectoryInfo[] dirs = di.GetDirectories();                if (dirs != null) dbPath = dirs[0].FullName + "\\cookies.sqlite";                DataTable dt = GetTable("select * from moz_cookies where baseDomain=@baseDomain", new SQLiteParameter("baseDomain", url));                foreach (DataRow row in dt.Rows)                {                    try                    {                        if (row["name"].ToString().ToLower() == "liap")                        {                            islogin = row["value"].ToString().ToUpper() == "TRUE" ? true : false;                        }                        cookiecontainer.Add(new Cookie                        {                            Name = row["name"].ToString()                            ,                            Value = row["value"].ToString()                            ,                            Path = row["path"].ToString()                            ,                            Domain = row["host"].ToString()                        });                    }                    catch (Exception)                    {                    }                    finally { }                }            }            catch (Exception)            {                throw;            }            return cookiecontainer;        }        public static DataTable GetTable(string sql, params SQLiteParameter[] pms)        {            using (SQLiteConnection conn = new SQLiteConnection("Data Source =" + dbPath))            {                using (SQLiteDataAdapter adapter = new SQLiteDataAdapter(sql, conn))                {                    DataTable dt = new DataTable();                    if (pms != null)                    {                        adapter.SelectCommand.Parameters.AddRange(pms);                    }                    conn.Open();                    adapter.Fill(dt);                    return dt;                }            }        }        public static void Shortcuts(string firelik)        {            try            {                string firepath = "";                // 在这里 获取本机火狐安装目录                               RegistryKey browsersKey;                browsersKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\WOW6432Node\Clients\StartMenuInternet");                if (browsersKey == null)                    browsersKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Clients\StartMenuInternet");                using (browsersKey)                {                    string[] subKeys = browsersKey.GetSubKeyNames();                    string locationPath = @"\shell\open\command";                    foreach (string key in subKeys)                    {                        if (key == "FIREFOX.EXE")                        {                            RegistryKey appLocationKey = browsersKey.OpenSubKey(key + locationPath);                            firepath = appLocationKey.GetValue(null).ToString().Trim('"');                            appLocationKey.Dispose();                            break;                        }                    }                }                IWshRuntimeLibrary.WshShell shell = new IWshRuntimeLibrary.WshShellClass();                IWshRuntimeLibrary.IWshShortcut shortcut = (IWshRuntimeLibrary.IWshShortcut)shell.CreateShortcut(firelik);                shortcut.TargetPath = firepath;                shortcut.Hotkey = "CTRL+SHIFT+5";                shortcut.WindowStyle = 7;                shortcut.IconLocation = firepath + ",0";                shortcut.Save();            }            catch (Exception ex)            {                //  throw;            }            finally { }        }    }




PS:以上部分代码片段为借鉴网络资料...

因为是小程序,单人开发,所以我基本就没写注释,这一点有点对不起大家了 、写的有点乱,  罪过罪过! 勿喷勿喷!


0 0
原创粉丝点击