Windows上利用Python自動切換代理IP的終極方案!

聲明下:不一樣於網絡上千百篇方法,下文是通過各類嚴格測試都經過的,同時也是一個實驗的過程,排除了各類不靠譜的方法。有須要的能夠評論來討論,想要源碼和相關參考文獻或筆記的,也能夠找我。python

思路及啓發

先說一下我這一路實驗的思路吧,這個相當重要。shell

以前一直在用Python作爬蟲抓取數據,發現本機IP的問題不解決,爬蟲至關於白費了。而後各類百度,不論是用urllib2仍是requests的代理設置,都無論用。而後又各類搜索Python更改windows代理的設置,還須要接觸windos底層API,有複雜又很差實現。因而爬蟲的學習就放棄了好長一段時間。windows

最近由於一直在用AutoHotkey大大加快電腦操做效率,各類快捷鍵和代替手動操做一些常規系統設置。突發奇想,想讓它自動打開IE的Internet設置,而後自動點擊「局域網設置」,在自動在代理框裏輸入IP地址,按回車完成設置。這真是個好主意~瀏覽器

不過失敗了。。。由於AHK在IE設置彈出的框框中選擇某一個輸入框,很麻煩,我也無法實現。因此就在想另外一個辦法,由於AHK操做Windows的cmd命令很方便,因此在想能不能用它打開cmd而後用命令設置IE呢?服務器

而後又各類百度。發現這是能夠經過reg add註冊表設置來實現的!因而,就開啓了reg命令的百度之旅。網絡

按照網上各類方法,都指向了註冊表的這個地方:tcp

HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings

你們都說在這個路徑下,有這麼3個項很是重要:編輯器

  • ProxyEnable - 使用代理學習

  • ProxyServer - 代理IP的地址及端口號測試

  • AutoConfigURL - 自動配置腳本(PAC)的地址

因而試着用reg add命令操做:

reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings" /v ProxyEnable /tREG_DWORD /d 1 /f
reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings" /v ProxyServer /d"192.168.1.1:8080" /f

這兩句第一個是打開「代理」,第二個是設置代理的IP地址。

先在命令行裏敲了下命令,而後打開regedit註冊表,刷新下看,還真改了!

而後手動打開IE設置,發現裏面的內容也確實改變了。而後再打開瀏覽器,打開IP查詢的網址,本身的IP真的變了!

至此覺得大功告成了。結果再用時,發現大錯特錯——再次用命令行改我指定的IP地址後,網頁打不開了。。。

來回反覆調試查錯以後,我發現一個「大祕密」:若是不手動打開IE設置裏的局域網設置窗口的話,全部代理設置是不生效的。這是爲何呢?

百度裏搜索不到。

因而我就用英文到Stackoverflow去搜,結果發現實際影響本機代理的註冊表項目並非以前的那幾個!(真懷疑網上那些人說本身用這個項達到定時設置代理的人是否是玩真的。。。)

而是這個位置的項:

HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Connections

其中的DefaultConnectionSettings纔是真正須要改的東西。打開之後各類亂碼,原來是二進制值。
不過用編輯器看二進制值,確實發現代理IP地址和自動配置腳本的地址都在裏面。

那怎麼辦呢?AHK可不會操做二進制,也沒什麼方法能用reg add命令行直接把二進制值注入。而後又進入無盡的百度模式。

註冊表的二進制項修改方式的突發奇想

忘了什麼啓發的我吧,好像是本身無聊到在註冊表上亂點,發現我刻意導出註冊表。

而後導出了下試試,發現是個.reg文件。而後無聊雙擊一下,發現能夠把這個文件導入到註冊表!因而靈光一閃,趕忙用文本編輯器打開這個.reg文件,發現裏面是文字畫的十六進制碼,相似這樣的:

Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Connections]
"DefaultConnectionSettings"=hex:46,00,00,00,03,00,00,00,07,00,00,00,0e,00,00,\
 00,31,39,32,2e,31,36,38,2e,31,2e,31,3a,38,30,00,00,00,00,21,00,00,00,68,74,\
 74,70,3a,2f,2f,78,64,75,6f,74,61,69,2e,63,6f,6d,2f,70,52,73,4f,33,4e,47,52,\
 33,2d,2e,70,61,63,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\
  00,00,00,00,00,00,00,00,00,00,00,00,00
"SavedLegacySettings"=hex:46,00,00,00,c1,0c,00,00,07,00,00,00,0e,00,00,00,31,\
 39,32,2e,31,36,38,2e,31,2e,31,3a,38,30,00,00,00,00,21,00,00,00,68,74,74,70,\
 3a,2f,2f,78,64,75,6f,74,61,69,2e,63,6f,6d,2f,70,52,73,4f,33,4e,47,52,33,2d,\
 2e,70,61,63,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\
  00,00,00,00,00,00,00,00,00,00,00

因而最終答案就出來了(這裏開始有Python介入)

這個時候我還不知道這是正確答案,只是想試一試:

用Python組成一段有效的二進制碼(實際上是十六進制) -> 把註冊表值封裝爲reg文件 -> 經過命令行的reg import命令導入reg文件 -> 成功!

而後問題就在於怎麼安裝正確的格式組成

DefaultConnectionSettings十六進制值的分析

因而繼續到Stackoverflow上搜索DefaultConnectionSettings這個項中十六進制的讀取問題。
發現有一我的大概總結了每一位字節是表明什麼,不過不夠詳細。地址在這裏【How to set 'automatic configuration script' for a dial-up connection programmatically?

而後開始作筆記:

How to set 'automatic configuration script' for a dial-up connection programmatically?

接着開始嘗試對照着那段二進制值看一看。因而我把這段十六進制碼作成PDF,方便作筆記,大概是這樣的:

Windows代理設置註冊表值的十六進制分析DefaultConnectionSettings

實際的十六進制值果真和網上的不一樣。通過實驗,後面一大段畫刪除線的,都是沒用的,刪除也不要緊。實際上,它只有在你手動打開IE設置面板時,才自動加上的。無論它,實際上有用的十六進制並不長。總結下也就這麼幾位:

46 00 00 00 00 00 00 00 開關 00 00 00 IP長度 00 00 00 IP地址 00 00 00 是否跳過本地代理 21 00 00 00 PAC地址

其中,經過規律發現每一個信息的分隔符是三個00,即00 00 00。上面有7個00的,由於沒什麼用我就不講了(其實第四個表明自增數,直接爲00就行了)

固然,其中漢字的部分是十六進制格式的。

這幾個漢字,是其中最重要的信息,具體以下:

  • 開關(switcher): 主要表明IE設置中複選框的選中狀況,你能夠打開IE設置看看。如下是全部可用的值(括號中是我用的別名):

    • 0F所有開啓(ALL);01所有禁用(Off)

    • 03使用代理服務器(ProxyOnly);05使用自動腳本(PacOnly);

    • 07使用腳本和代理(ProxyAndPac);09打開自動檢測設置(D);

    • 0B打開自動檢測並使用代理(DIP);0D打開自動檢測並使用腳本(DS);

  • IP長度:必須是十六進制的,0就是00,7就是07,10就是0a,11是0b。在Python中,格式是0xa,因此須要把格式統一爲註冊表的標準。

  • IP地址:直接把IP安裝每一個字符轉十六進制就行了。若是IP爲空的話,就直接爲00。這時會看到switcher後面跟了11個00。。。

  • 是否跳過本地代理:這段有點複雜,實際上咱們幾乎不用。若是不用的話直接爲00就行了。可是用的話,就必須寫爲:附加信息長度00 00 00 附加信息這樣的。

    • 附加信息:只能是這句話:<local>

    • 附加信息長度:由於附加信息是固定的,因此共7位,寫爲07就行了。

  • PAC地址:這個簡單,直接把PAC地址翻譯爲十六進制就行了。若是沒有則什麼都不寫。

至此這段十六進制值就所有解析完畢了。

剩下的就是把你須要的代理IP地址和PAC地址做爲參數傳進去就行了。而後把這段值封裝到reg文件中的對應位置就徹底ok了~這步太簡單,就不用多說了。

增長更方便的功能

各類測試成功後,很是高興。可是還有點餘味不足,就想着多添加點方便的功能。

這個Python文件的最後成品能夠作到這些事:

  • 直接經過命令行傳參數達到各類設置代理的效果。這個很自豪~第一次用系統參數功能,哈哈哈!

  • 在文件夾中直接雙擊達到效果

  • 在別的Python文件中(如爬蟲)做爲模塊被使用

  • 被AHK調用

在Autohotkey中調用——極其方便極其傻瓜式操做!

不忘初心嘛~

python處理一切完成後,又回到了AHK中。

這一步可能也就寫了幾分鐘,讓AHK直接帶參數打開python腳本就作到了。好比設置一個代理IP地址:

path = "D:\setRegProxy.py" ;這裏是python腳本的地址,隨便放哪都行。
key   = "0.0.0.0:80"  ;這裏根據須要設置爲代理地址
Run % path " -o ProxyOnly " key

這樣就齊活了~

固然,個人AHK腳本實現的功能比這個還要爽快——彈出一個小輸入框,直接粘貼一個ip地址,按回車就能實現代理設置。

Python腳本的源碼(setProxy.py)

只要機器上安裝了Python 2.x版本就行,不須要依賴安裝和設置其餘任何東西。

# coding:utf-8
'''
  # Title   : setRegProxy
  # Author  : Solomon Xie
  # Utility : Via Registry key of windows, change proxy settings of IE on Windows.
  # Require : Python 2.x, Windows 7
  # Reg Path: HKUC\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Connections
  # Anlysis : 註冊表的二進制值(及關鍵信息)以下:"46 00 00 00 00 00 00 00 開關 00 00 00 IP長度 00 00 00 IP地址 00 00 00 是否跳過本地代理 21 00 00 00 PAC地址"
  # Method  : 經過在cmd中導入reg文件的方式執行並當即生效。
  # Notes   : - 二進制值的設置選項在代碼中已經體現了。本代碼能夠根據須要自動設置代理。
  # switcher: 開關:0F所有開啓(ALL);01所有禁用(Off)
              03使用代理服務器(ProxyOnly);05使用自動腳本(PacOnly);
              07使用腳本和代理(ProxyAndPac);09自動檢測設置(D);
              0B自動檢測並使用代理(DIP);0D自動檢測並使用腳本(DS);
'''
import os, sys, re, getopt

def regIESettings(op, noLocal=False, ip='', pac=''):
  '''
    # 根據需求生成Windows代理設置註冊表的.reg文件內容
    # DefaultConnectionSettings項是二進制項
    # 而具體這個二進制文件怎麼解析,在收藏的PDF中有詳細解釋。
  '''
  if not op : return
  # 若是是設置IP代理的模式 則檢查IP地址的有效性(容許爲空,但不容許格式錯誤)
  if 'Proxy' in op and not ip == '': 
    # if len(extractIp(ip))==0
    if 1 > len(re.findall('([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})\s*:{0,1}\s*([0-9]{1,5}){0,1}',ip)) :
      print '---Unexpected IP Address:%s---'%ip
      return
  options = {'On':'0F','Off':'01','ProxyOnly':'03','PacOnly':'05','ProxyAndPac':'07','D':'09','DIP':'0B','DS':'0D'}
  if op == 'Off':
    reg_value = '46,00,00,00,00,00,00,00,01'
  else:
    switcher = options.get(op)
    if not switcher:
      print '\n---Unexpected Option. Please check the value after [-o]---\n'
      return
    skipLocal = '07,00,00,00,%s'%__toHex('<local>') if noLocal else '00'
    reg_value = '46,00,00,00,00,00,00,00,%(switcher)s,00,00,00,%(ipLen)s,00,00,00,%(ip)s00,00,00,%(skipLocal)s,21,00,00,00%(pac)s' % ({ 'switcher':switcher,'ipLen':__toHex(len(ip)),'ip':__toHex(ip)+',' if ip else '','infoLen':__toHex(len('<local>')),'skipLocal':skipLocal,'pac':','+__toHex(pac) if pac else '' })
  settings = 'Windows Registry Editor Version 5.00\n[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Connections]\n"DefaultConnectionSettings"=hex:%s' % reg_value
  # print 'Using proxy address: %s' % ip
  print op, ip, pac
  print options[op] +'\n'+ __toHex(ip) +'\n'+ __toHex(pac)
  print settings
  # === 生成reg文件並導入到註冊表中 ===
  filePath = '%s\DefaultConnectionSettings.reg'%os.getcwd() 
  with open(filePath, 'w') as f:
    f.write( settings )
  cmd = 'reg import "%s"' %filePath
  result  = os.popen(cmd)
  if len(result.readlines()) < 2 :
    print '---Successfully import proxy into Registry on this machine.---'
  return 

def __toHex(obj):
  if   obj == '': return ''
  elif obj == 0 or obj == '0' or obj == '00': return '00'
  if isinstance(obj, str):
    rehex = [str(hex(ord(s))).replace('0x','') for s in obj]
    return ','.join(rehex)
  elif isinstance(obj, int):
    num = str(hex(obj)).replace('0x', '')
    return num if len(num)>1 else '0'+num # 若是是一位數則自動補上0,7爲07,e爲0e

if __name__ == '__main__':
  # 獲取文件外部參數
  # 用法:在命令行中輸入setRegProxy.py -o "ProxyOnly" -l --proxy"0.0.0.0:80" -l
  opts, args = getopt.getopt(sys.argv[1:], 'o:p:a:l',['option=','proxy=','pac=','local'])
  print opts, args #調試用
  if len(opts) > 0:
    op, ip, pac = '', '', ''
    noLocal = False
    for o,a in opts:
      if   o == '-o' or o == '--option':  op = a
      elif o == '-p' or o == '--proxy' :  ip = a
      elif o == '-a' or o == '--pac'   : pac = a
      elif o == '-l' or o == '--local' : noLocal = False
    pac = 'http://xduotai.com/pRsO3NGR3-.pac' if not pac else pac
    if op == 'ProxyOff':
      regIESettings(op='Off', ip=ip, pac=pac, noLocal=noLocal)
      regIESettings(op='PacOnly', ip=ip, pac=pac, noLocal=noLocal)
    elif op == 'PacOff':
      regIESettings(op='Off', ip=ip, pac=pac, noLocal=noLocal)
      regIESettings(op='ProxyOnly', ip=ip, pac=pac, noLocal=noLocal)
    else:
      regIESettings(op=op, ip=ip, pac=pac, noLocal=noLocal)

Autohotkey源碼

Autohotkey怎麼用呢?太簡單了,傻到爆!

直接官網下載安裝一個Autohotkey軟件,也就幾M。而後呢,新建一個文本文件,把下面內容粘貼進去。把文件名後綴改成.ahk,而後雙擊就啓動了腳本哈哈!

這時你試着按一下鍵盤上的ScrollLock鍵,就會彈出來一個對話框。效果是這樣的:

按下ScrollLock鍵後彈出的框框

你能夠在這裏輸入改代理的命令~ 我設計的命令都很是簡單,以下:

  • 輸入proxy,就會打開IE設置的窗口

  • 輸入proxy 192.168.1.1:8080 ,就會把代理設置爲這個IP

  • 輸入proxy on,就會打開代理(可是IP爲空)

  • 輸入proxy off,就會關閉代理

  • 輸入pac http://abc.com/123.pac,就開啓某自動代理設置腳本

  • 輸入pac off,就會關閉自動腳本

輸入指令的樣子

注意:

  1. 我這裏註冊的鍵是鍵盤上的ScrollLock按鈕,按一下就有了。也能夠本身設定一個。

  2. 下面的代碼是處理過的,實際上這個按鍵遠比它要方便的多:它是個人快速操做殺手鐗,一條命令實現巨多功能。若有感興趣的能夠聯繫我討論,或者看個人下一篇專門針對AHK的文章(若是我不犯懶寫了的話)。

  3. 我設定的指令是proxy ??這樣的,若是嫌長或者不方便,能夠改成別的本身用着舒服的。甚至不用彈出框,直接按一下F1之類的就完成設置均可以。不過這就須要稍微瞭解下AHK語法啦~(也不難)

ScrollLock:: 
{
    ; --- 獲取指令及關鍵詞 ---
    InputBox, fullCommand, (Command Line Interface), Please give me a command:, , 600, 130 ;獲取命令
    if (fullcommand = "")
        Return
    ; -- 解析命令 ---
    split  := " " 
    StringGetPos , posi, fullCommand, %split%
    if (posi > 0) {
        StringMid, eng, fullCommand, 0 , posi ;
        StringMid, key, fullCommand, posi+2 , StrLen(fullCommand)
    }
    else {
        eng := fullCommand
        key := ""
    }
        ; === 打開IE設置窗口的命令 ===
        ieSettings := "rundll32.exe shell32.dll, Control_RunDLL inetcpl.cpl, ,4L"
        ; === python腳本的地址 ===
    path  := "D:\Solomon Xie\Workspace\setRegProxy.py" ;Python設置代理腳本,可接收命令行參數
    ; ---開始執行操做---
    if      (eng = "" and fullcommand != "")
        Run % ieSettings
    else if (eng = "Proxy"){
        if (key = "")
            Return
        else if (key = "Off")
            Run % path " -o Off "
        else{
            if (key = "On")
                key := "" ;「獲取」歷史IP值太麻煩 先爲空吧
            else
                key = "--proxy " %key%
            Run % path  " -o ProxyOnly " key
        }
    }
    else if (eng = "Pac" and key != "") {
        if (key = "" or key = "On")
            key = "http://xduotai.com/pRsO3NGR3-.pac"
        if (key = "Off")
            Run % path  " -o Off "
        else {
            key = "%key%"
            Run % path " -o PacOnly --pac " key
        }
    }
    Return
}
相關文章
相關標籤/搜索