PythonでTorを使用する

## はじめに
スクレイピングの勉強として、pythonを使ってあるサイトから情報を抜き出すコーディングを試していたところ、急にレスポンスが遅くなったり、アクセスを拒否されたりしたことがあった。
テザリングでインターネットに接続したら元に戻ったので、同じIPから何度もリクエストが来ている事が理由と理解したのだが、その時色々と調べて`Tor`という接続経路の匿名化を実現するソフトウェアを知ったので、試しにそれもどんな感じなのか使ってみた。今回の記事では、その時の構築内容や確認内容をメモとして残す。



## 実行環境

- Ubuntu 20.04LTS（GCP上）
- Tor version 0.4.2.7.
- Python 3.8.5



## メモ内容　

```shell:
$ sudo apt update 
$ sudo apt upgrade -y
```

#### `tor` のインストール
```shell:
$ sudo apt install tor
$ tor --version
Tor version 0.4.2.7.
```


#### `tor`の設定

`sudo nano /etc/tor/torrc` で以下の様に追記。

```shell:/etc/tor/torrc
# 除外する中継ノード
ExcludeNodes {jp},{us},{gb},{ca},{au},{nz},{dk},{fr},{nl},{no},{de},{be},{it},{es},{il},{sg},{kr},{se},127.0.0.1

# 除外する出口ノードについて
ExcludeExitNodes {jp},{us},{gb},{ca},{au},{nz},{dk},{fr},{nl},{no},{de},{be},{it},{es},{il},{sg},{kr},{se},{cn},{ru},127.0.0.1

# 経由するサーバーの数
NumEntryGuards 4

# 設定を確実に守るかどうか（`1`の場合は絶対に接続しない `0`の場合は接続する場合がある。）
StrictNodes 1
```
　※所謂【スパイ協定】5-Eyes, 9-Eyes, 14-Eyes, 41-Eyesの中で、14-Eyesの国は中継ノードとして今回は除外。詳しく知りたい人は、このサイトとか参考になるかもしれないです。[【参考１】](https://ja.wizcase.com/blog/vpn%E3%82%92%E9%81%B8%E3%81%B6%E5%89%8D%E3%81%AB5%E3%80%81%EF%BC%99%E3%80%8114%E3%82%A2%E3%82%A4%E3%82%BA%E5%90%8C%E7%9B%9F%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6%E3%81%97%E3%81%A3%E3%81%8B%E3%82%8A/)[【参考２】](https://bestvpn.jp/what-is-5-eyes/)


#### `Python` 関連のインストール

```shell:
$ python3 -V
Python 3.8.5

$ sudo apt install -y python3-pip
$ sudo apt install -y jupyter-notebook

# python から tor のSOCKSポートにアクセスするため
$ pip3 install pysocks

# Python を使ったスクレピング関連のテストをしたかったので以下のパッケージをインストール
$ pip3 install numpy  pandas  beautifulsoup4
$ pip3 install selenium
$ pip3 install chromedriver-binary==89.0.4389.23
```

#### Chrome のインストール
　※今回は`selenium`でGoogle操作も試したかったので

```shell:
$ sudo sh -c 'echo "deb http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list'

# 公開鍵をダウンロードして登録する
$ sudo wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add -

# ここで一旦、パッケージリストを最新化
$ sudo apt update

# ダウンロードできる一覧を確認
$ apt list google*

# Chromeのダウンロード
$ sudo apt install google-chrome-stable
```

#### `Jupyter notebook` の設定

```shell:
# 設定ファイルの作成
$ jupyter notebook --generate-config

# 初期ディレクトリとする場所を作成する
$ mkdir ./workspace   # sudo で作るとユーザーの書き込み権限が付かなくなる可能性がある 


# 設定ファイルの編集
$ sudo nano /home/【アカウント名】/.jupyter/jupyter_notebook_config.py

# 以下を追記内容（jupyter_notebook_config.py）
c.NotebookApp.ip = '0.0.0.0'                            # 外部からアクセスできる様にする。
c.NotebookApp.notebook_dir = '/home/【アカウント名】/workspace'   # 上記で作成した初期ディレクトリを指定。
```

#### GCPコンソール側でFW設定をする（やり方は割愛）
　jupyter-notebookのデフォルトポートが8888なので、今回はそこを開けておいた。

#### 各サービスの起動

```shell:
# Torサービスの起動
$ sudo service tor start
$ sudo service tor status

# 現状のIPアドレス確認
$ wget -qO - https://api.ipify.org; echo
***.***.***.***

# Tor経由のIPアドレス確認
$ torsocks wget -qO - https://api.ipify.org; echo
***.***.***.***
```
上記により、一旦`tor`が正常に動いているところは確認できた。



#### JupyterNotebookを起動して、ローカル⇒GCP上のVM(notebook)に接続

```shell:
$ jupyter notebook

#~~~~~~~省略~~~~~~~~~~~~~~~~~~~
http://localhost:8888/?token=d09865b1c31d039b59789f0071d4dfc53e0912d68a0c6363
     or http://127.0.0.1:8888/?token=d09865b1c31d039b59789f0071d4dfc53e0912d68a0c6363
```
上記の様に、`jupyter-notebook`の起動が問題なくできていれば、ローカルPCより適当なブラウザで`【GCP上のVMの外部IPアドレス】:8888`に接続して、notebook画面に入るはず。
　※初回はTokenの入力を求められるので、上記の`token=`より先の英数字をコピペすればOK。



## テスト用の `.ipynb` ファイルを作成

jupyter-notebookで以下のファイルを作成して、実行してみると`tor`経由でIPが変更されていることが分かる。

```py:test.ipynb
import requests
import subprocess

proxies = {
    'http': 'socks5://localhost:9050',
    'https': 'socks5://localhost:9050'
}

# torを経由する場合と経由しない場合のIPアドレスをチェック
res = requests.get('https://ipinfo.io').json()
print('torを経由しない場合（GCP上のVM外部IPと同じはず）：\n', res)

res = requests.get('https://ipinfo.io', proxies=proxies).text
print('\n\ntorを経由する場合（IPが変わるはず）：\n', res)


# torの再起動（これをするとtor経由のIPアドレスが変更される）
args = ['sudo', 'service', 'tor','restart']
subprocess.call(args)
```

Tor経由でChromeを使うことも、以下の記事を参考に試してみたのでご参考まで。
https://qiita.com/___xxx_/items/419a86ea2d3d1ab9f415

```py:test2.ipynb
# Chromeを使ったスクレイピング
import requests
from selenium import webdriver
import chromedriver_binary
from selenium.webdriver.common.keys import Keys
from bs4 import BeautifulSoup

# オプションでPROXYを設定
PROXY = "socks5://localhost:9050"
options = webdriver.ChromeOptions()
options.add_argument('--headless')
options.add_argument('--lang=ja-JP')
options.add_argument('--no-sandbox')
options.add_argument('--disable-gpu')
options.add_argument('--proxy-server=%s' % PROXY)
driver = webdriver.Chrome(chrome_options=options)

# Torを経由できているかの確認
driver.get("http://check.torproject.org")
temp = BeautifulSoup(driver.page_source)
print(temp)
```

## 最後に
今回の記事はあくまで、`tor`の構築のメモと動きの確認が目的なので、`tor` の技術を悪用することは**絶対にしないようにしましょう！**
（基本的に悪い事したらバレます。）