[ Tor ] 多開 Tor client

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

首先,我在桌面上建立了一個 tor_confs資料夾,內容大概是長下面這樣。
. tor_confs
├── torrc1.in
└── torrc2.in
要多開 Tor需要為各個 Socket port建立各自的 conf檔。
# torrc1.in

SocksPort 9050
ControlPort 9051
DataDirectory /Users/XXXXXXXX/Desktop/tor_confs/tor1
ExitNodes {tw},{jp},{kr},{hk},{sg}
# torrc2.in

SocksPort 9060
ControlPort 9061
DataDirectory /Users/XXXXXXXX/Desktop/tor_confs/tor2
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設定的路徑建立所需的檔案,資料夾結構如下。
. tor_confs
├── tor1
│   ├── cached-certs
│   ├── cached-microdesc-consensus
│   ├── cached-microdescs.new
│   ├── lock
│   └── state
├── tor2
│   ├── cached-certs
│   ├── cached-microdesc-consensus
│   ├── cached-microdescs.new
│   ├── lock
│   └── state
├── torrc1.in
└── 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
import os
import re

pid_list = os.popen('ps').readlines()  # Ubuntu用戶則使用 'ps -h'

tor_pids = {}
for pid in pid_list:
    if 'tor' in pid:
        cmd = re.findall('torrc[0-9]+.in', pid)[0]
        pid = re.findall('[0-9]+', pid)[0]
        tor_pids[cmd] = pid

print(tor_pids)  # {'torrc2.in': '3967', 'torrc1.in': '3968'}
執行後,便可透過字典型態以各執行檔的檔名對應各自的 PID。
Regular expression的部份可能要視情形調整。

除了用指令的方式更新 IP,也可以透過 Tor conf檔中設定的 ControlPort來更新 IP。
from stem import Signal
from stem.control import Controller

with Controller.from_port(port = 9051) as controller:
    controller.authenticate()
    controller.signal(Signal.NEWNYM)
用 ControlPort來更新 IP看來比較合乎常理,但我也是後來才知道的 :P

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

留言