[ Tor ] 多開 Tor client

之前 "使用 Tor更新 IP位置" 文中提到 Python要透過 Tor爬蟲前,須透過 Tor提供的 Socket port來連接 Tor。
最近因為朋友有需求,稍微花了一點時間研究了一下如何多開 Tor client和獨立更新 IP位置。
當要使用大量 IP同時訪問同一個網站,就有必要讓 Tor提供兩個以上的 Socket port來提供不同的 IP位置。

首先,我在桌面上建立了一個 tor_confs資料夾,內容大概是長下面這樣。
  1. . tor_confs
  2. ├── torrc1.in
  3. └── torrc2.in
要多開 Tor需要為各個 Socket port建立各自的 conf檔。
  1. # torrc1.in
  2.  
  3. SocksPort 9050
  4. ControlPort 9051
  5. DataDirectory /Users/XXXXXXXX/Desktop/tor_confs/tor1
  6. ExitNodes {tw},{jp},{kr},{hk},{sg}
  1. # torrc2.in
  2.  
  3. SocksPort 9060
  4. ControlPort 9061
  5. DataDirectory /Users/XXXXXXXX/Desktop/tor_confs/tor2
  6. ExitNodes {tw},{jp},{kr},{hk},{sg}
DataDirectory需設定絕對路徑,設定相對路徑在更新 IP時會報錯。
ExitNodes則可有可無,因為個人需求需限制 Exit node的國家。各國的代碼可以點擊這裡查詢。
完成後只需要在 tor_confs資料夾內使用 terminal執行
$ tor -f torrc1.in & tor -f torrc2.in
兩個 Socket port會各自連上不同的 IP位置,這樣就算完成了。
執行後 Tor就會自動在 DataDirectory設定的路徑建立所需的檔案,資料夾結構如下。
  1. . tor_confs
  2. ├── tor1
  3.    ├── cached-certs
  4.    ├── cached-microdesc-consensus
  5.    ├── cached-microdescs.new
  6.    ├── lock
  7.    └── state
  8. ├── tor2
  9.    ├── cached-certs
  10.    ├── cached-microdesc-consensus
  11.    ├── cached-microdescs.new
  12.    ├── lock
  13.    └── state
  14. ├── torrc1.in
  15. └── torrc2.in

使用 "killall -HUP tor" 的指令雖然可以更新 IP,但會同時把所有 Tor的 Socket port都分配新的 IP。可是不同的 IP同時斷線和連線,可能會使伺服器端產生懷疑,為避免有這樣的疑慮,有必要讓各個 Socket port視各自的需求來更新 IP位置。
首先開啟新的 Terminal,輸入
$ ps
$
S ps -h  # Ubuntu需要加上 -h
執行完,便會返回正在執行中的指令。
要更新 IP位置只需要針對各指令的 PID輸入
$ kill -s SIGHUP 3968  # 更新 port 9050連接的 IP
$
$ kill -s SIGHUP 3967  # 更新 port 9060連接的 IP
確認各 IP位址可使用下列指令,就會返回目前 Exit node的 IP位置。
$ curl --socks5 127.0.0.1:9050 http://checkip.amazonaws.com/
$
$ curl --socks5 127.0.0.1:9060 http://checkip.amazonaws.com/
最後為了讓 Python能取得各 Socket port的 PID
  1. import os
  2. import re
  3.  
  4. pid_list = os.popen('ps').readlines() # Ubuntu用戶則使用 'ps -h'
  5.  
  6. tor_pids = {}
  7. for pid in pid_list:
  8. if 'tor' in pid:
  9. cmd = re.findall('torrc[0-9]+.in', pid)[0]
  10. pid = re.findall('[0-9]+', pid)[0]
  11. tor_pids[cmd] = pid
  12.  
  13. print(tor_pids) # {'torrc2.in': '3967', 'torrc1.in': '3968'}
執行後,便可透過字典型態以各執行檔的檔名對應各自的 PID。
Regular expression的部份可能要視情形調整。

除了用指令的方式更新 IP,也可以透過 Tor conf檔中設定的 ControlPort來更新 IP。
  1. from stem import Signal
  2. from stem.control import Controller
  3.  
  4. with Controller.from_port(port = 9051) as controller:
  5. controller.authenticate()
  6. controller.signal(Signal.NEWNYM)
用 ControlPort來更新 IP看來比較合乎常理,但我也是後來才知道的 :P

添加 ExitNodes時,有時候會有點秀逗。
比如說,當選擇韓國 IP時,經查詢卻發現得到的是日本的 IP。
或是有時要更新 IP時,得到的卻是原來的 IP。

留言