Selenium + Python で Salesforce へ自動ログインして取引先データを取得する

はじめに
===

ここ1年ほど色々立て込んでおりまして、久しぶりの投稿になります。
よろしくお願い致します。

SeleniumとPythonを使って、ChromeからSalesforceへ自動ログインし、Salesforceデータ(取引先と取引先責任者オブジェクトのデータ)を取得・表示するスクリプトを作ってみました。

本記事では、SeleniumとPythonによりSalesforceへログインしてデータを取得する方法をまとめております。

実行環境
===

本記事の実行環境は以下になります。

| 環境         | バージョン |
|:-----------:|:-----------------:|
| MacBook Pro | OS X 10.11.6      |
| Python      | 3.6.5             |
| Selenium    | 3.11.0            |
| pip         | 9.0.3             |


細かいバージョン情報は以下になります。

```
$ uname -a
Darwin *********** 15.6.0 Darwin Kernel Version 15.6.0: Tue Jan  9 20:12:05 PST 2018; root:xnu-3248.73.5~1/RELEASE_X86_64 x86_64
```

```
$ /usr/local/bin/python3 -V
Python 3.6.5
```

```
$ /usr/local/bin/pip3 -V
pip 9.0.3 from /usr/local/lib/python3.6/site-packages (python 3.6)
$ 
```

```
$ pip3 list --format=columns
Package    Version
---------- -------
pip        9.0.3  
selenium   3.11.0 
setuptools 39.0.1 
wheel      0.30.0 
$ 
```

```
$ brew list | grep chrome
chromedriver
```

実行環境の準備
===

以下のコマンドでSelenium + Pythonをインストールして実行環境を準備しました。
今回は例としてホームディレクトリ直下にsample_selenium_salesforceというディレクトリを作成し、そこに実行環境を準備しました。

```bash:実行環境の準備
$ mkdir ~/sample_selenium_salesforce

$ cd ~/sample_selenium_salesforce

$ brew install python
$ pip3 install --upgrade setuptools
$ pip3 install --upgrade pip
$ pip3 install selenium
$ brew install chromedriver
```


SeleniumによるSalesforceへの自動ログイン+取引先データ取得スクリプト
===

Macにログインし、以下のスクリプトを作成します。

```
$ cd ~/sample_selenium_salesforce
$ vi selenium_get_salesforce_data.py
```

作成するスクリプト内容は以下になります。

パラメータでチェックする取引先名、取引先責任者名を指定します。
Salesforceログインユーザ名とパスワードは直接スクリプト内には記載せず、環境変数から取得して動かすようにしました。

実行方法については後述します。

```python:selenium_get_salesforce_data.py 
#####
import sys
import os

from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from time import sleep

## Selectタグ利用
from selenium.webdriver.support.ui import Select

#####
## パラメータからチェックする取引先名を取得

args = sys.argv
argc = len(args)

if ( argc != 3 ):
  print('チェック対象の取引先名と取引先責任者名を指定して下さい。処理を終了します。')
  sys.exit(-1)

## チェック対象の取引先名をパラメータから取得
check_account_name = args[1]

## チェック対象の取引先責任者名をパラメータから取得
check_contact_name = args[2]

#####
## Salesforceログイン画面のURL
login_url = 'https://login.salesforce.com/'

## ~/.bashrcからユーザ名を取得
login_user_name = os.environ["SFDC_LOGIN_USERNAME"]

## ~/.bashrcからログインパスワード名を取得
login_user_passwd = os.environ["SFDC_LOGIN_PASSWORD"]

#####
## ブラウザを開く
driver = webdriver.Chrome()

## Salesforceログイン画面を開く
driver.get(login_url)

## Salesforceログイン画面でログインユーザ名を自動入力する
user_name = driver.find_element_by_id('username')
user_name.send_keys(login_user_name)

## Salesforceログイン画面でログインパスワードを自動入力する
user_passwd = driver.find_element_by_id('password')
user_passwd.send_keys(login_user_passwd)

## ログインボタンをクリックする
try:
  driver.find_element_by_id('Login').click()
  driver.implicitly_wait(2)
except:
  print('Salesforce [' + login_url + '] へのログインに失敗しました。処理を終了します。')
  sys.exit(-1)
else:
  print('Salesforce [' + login_url + '] へのログインに成功しました。')

## Salesforceログイン成功したら、[取引先]タブをクリックする
try:
  driver.find_element_by_id('Account_Tab').click()
  driver.implicitly_wait(2)
except:
  print('[取引先]タブのクリックに失敗しました。処理を終了します。')
  sys.exit(-1)

## [取引先]タブの[Go!]ボタンをクリックする
####driver.find_element_by_name('go').click()

## [取引先]タブにある[ビュー]プルダウンのエレメントを取得する
view_list_element = driver.find_element_by_name('fcf')
driver.implicitly_wait(2)

## [ビュー]プルダウンのエレメントを指定してSelectクラスのインスタンス生成
view_list_select_element = Select(view_list_element)

## ビューのプルダウンから[すべての取引先]を選択する
view_list_select_element.select_by_visible_text('すべての取引先')
driver.implicitly_wait(2)

#####
## チェック対象の取引先詳細画面を開く
print('--------------------------------------------------------------')
print('チェック対象の取引先詳細画面を表示します。')

try:
  driver.find_element_by_link_text(check_account_name).click()
  driver.implicitly_wait(2)
except:
  print('チェック対象の取引先が見つかりませんでした。処理を終了します。')
  sys.exit(-1)

## 取引先詳細画面からデータを取得して画面上に表示する
print('チェック対象の取引先のデータを表示します。\n')

## 取引先詳細画面で取得する各項目のdiv id
get_account_element_id_list = {
  "所有者"      : "acc1_ileinner",
  "取引先名"    : "acc2_ileinner",
  "親取引先名"  : "acc3_ileinner",
  "取引先番号"  : "acc5_ileinner",
  "年間売上"    : "acc8_ileinner",
  "評価"        : "acc9_ileinner",
  "電話"        : "acc10_ileinner",
  "FAX"         : "acc11_ileinner",
  "Webサイト"   : "acc12_ileinner",
  "取引先 部門" : "acc23_ileinner"
}

for key, value in get_account_element_id_list.items():
  print('{} = [{}]'.format(key, driver.find_element_by_id(value).text))
  driver.implicitly_wait(2)

print('\n')
sleep(5)

#####
## チェック対象の取引先詳細画面にある[取引先責任者]を選択して取引先詳細画面を開く
print('--------------------------------------------------------------')
print('チェック対象の取引先に関連する取引先責任者詳細画面を表示します。')

try:
  driver.find_element_by_link_text(check_contact_name).click()
  driver.implicitly_wait(2)
except:
  print('チェック対象の取引先責任者が見つかりませんでした。処理を終了します。')
  sys.exit(-1)

## 取引先責任者詳細画面からデータを取得して画面上に表示する
print('チェック対象の取引先に関連する取引先責任者のデータを表示します。\n')

## 取引先責任者詳細画面で取得する各項目のdiv id
get_contact_element_id_list = {
  "取引先責任者の所有者"  : "con1_ileinner",
  "取引先責任者の名前"    : "con2_ileinner",
  "所属する取引先名"      : "con4_ileinner",
  "役職"                  : "con5_ileinner",
  "部署"                  : "con6_ileinner",
  "電話"                  : "con10_ileinner",
  "FAX"                   : "con11_ileinner",
  "メール"                : "con15_ileinner"
}

for key, value in get_contact_element_id_list.items():
  print('{} = [{}]'.format(key, driver.find_element_by_id(value).text))
  driver.implicitly_wait(2)

print('\n')
sleep(5)

## ブラウザを終了する
driver.close()
```

SeleniumによるSalesforceへの自動ログイン+取引先データ取得手順
===

以下の手順を実行すると、SeleniumによるSalesforceへの自動ログイン+取引先データ取得が開始されます。

## (1) 事前準備

### (1-1) 環境変数にSalesforceログインユーザ名とパスワード情報を追加します。

```
$ vi ~/.bashrc
　(末尾に以下の設定を追記します)

export SFDC_LOGIN_USERNAME="Salesforceへログインするユーザ名を記述"
export SFDC_LOGIN_PASSWORD="Salesforceへログインするユーザのパスワードを記述"
```

### (1-2) 追加した環境変数を読み込みます。

```
$ source ~/.bashrc
$
```

### (1-3) 環境変数が読み込まれた事を確認します。

```
$ export | grep SFDC
declare -x SFDC_LOGIN_PASSWORD="s******"
declare -x SFDC_LOGIN_USERNAME="s********************.com"
$ 
```

### (1-4) Salesforce側でSeleniumを実行するログイン元のIPアドレスからのアクセスを許可します。

以下のURLへアクセスして、Seleniumを実行するログイン元のIPアドレスを確認します。例えばIPアドレスが以下のIPアドレスだったとします。

http://httpbin.org/ip

```
{
  "origin": "192.0.2.10"
}
```

SeleniumからログインするSalesforceへシステム管理者等の管理権限を持ったユーザでログインします。

「設定」 ->「セキュリティのコントロール」->「ネットワークアクセス」をクリックします。

「ネットワークアクセス」画面が表示されます。「信頼済み IP 範囲」の「新規」をクリックします。

<img width="1175" alt="スクリーンショット 2018-04-10 6.30.12.png" src="https://qiita-image-store.s3.amazonaws.com/0/63647/32804415-2089-901c-3b97-33cba51dc4d7.png">

「信頼済み IP 範囲の編集」画面が表示されます。「開始 IP アドレス」や「終了 IP アドレス」や「説明」に以下のように入力して「保存」をクリックします。

| 環境         | バージョン |
|:-----------:|:-----------------:|
| 開始 IP アドレス | 192.0.2.10     |
| 終了 IP アドレス | 192.0.2.10     |
| 説明           | Seleniumを実行するログイン元のIPアドレス |

<img width="1170" alt="スクリーンショット 2018-04-10 6.32.40.png" src="https://qiita-image-store.s3.amazonaws.com/0/63647/086cdc6e-dad6-70ee-5aa5-2f5876c70553.png">

「ネットワークアクセス」画面が表示されます。「信頼済み IP 範囲」にSeleniumを実行するログイン元のIPアドレスが追加された事を確認します。

<img width="1170" alt="スクリーンショット 2018-04-10 6.36.33.png" src="https://qiita-image-store.s3.amazonaws.com/0/63647/a073574f-f510-25c9-2114-86d55e7c05b3.png">


## (2) Salesforceへの自動ログイン+取引先データ取得

### (2-1) 前述の [[SeleniumによるSalesforceへの自動ログイン+取引先データ取得スクリプト]](https://qiita.com/na0AaooQ/items/d3fe2d63ffcc5e268de4#selenium%E3%81%AB%E3%82%88%E3%82%8Bsalesforce%E3%81%B8%E3%81%AE%E8%87%AA%E5%8B%95%E3%83%AD%E3%82%B0%E3%82%A4%E3%83%B3%E5%8F%96%E5%BC%95%E5%85%88%E3%83%87%E3%83%BC%E3%82%BF%E5%8F%96%E5%BE%97%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%97%E3%83%88) を実行します。

以下のようなコマンドとパラメータでスクリプトを実行します。

スクリプトを実行すると、SeleniumによりChromeが自動起動されて、Salesforceへの自動ログインや取引先及び取引先責任者データの取得・表示が自動実行されます。

```bash:スクリプト実行方法
cd スクリプトを作成したディレクトリ

/usr/local/bin/python3 ./selenium_get_salesforce_data.py "データを取得したい取引先名" "データを取得したい取引先に関連する取引先責任者名"
```

スクリプトの実行例は以下の通りです。
Salesforceに登録されている取引先のデータ、取引先に関連する取引先責任者のデータが取得・表示されます。

```bash:実行例
$ cd ~/sample_selenium_salesforce/

$ /usr/local/bin/python3 ./selenium_get_salesforce_data.py "テスト株式会社" "テスト 太郎"
Salesforce [https://login.salesforce.com/] へのログインに成功しました。
--------------------------------------------------------------
チェック対象の取引先詳細画面を表示します。
チェック対象の取引先のデータを表示します。

所有者 = [salesforce_testuser [変更]]
取引先名 = [テスト株式会社 [階層の表示]]
親取引先名 = [テスト親会社]
取引先番号 = [ ]
年間売上 = [￥1,000]
評価 = [Hot]
電話 = [1111111111]
FAX = [2222222222]
Webサイト = [http://www.example.com/]
取引先 部門 = [営業本部]


--------------------------------------------------------------
チェック対象の取引先に関連する取引先責任者詳細画面を表示します。
チェック対象の取引先に関連する取引先責任者のデータを表示します。

取引先責任者の所有者 = [salesforce_testuser [変更]]
取引先責任者の名前 = [テスト 太郎]
所属する取引先名 = [テスト株式会社]
役職 = [ ]
部署 = [営業1部 営業1課]
電話 = [00-3333-4444]
FAX = [00-7777-8888]
メール = [example@example.com]


$ 
```

SeleniumによるSalesforceへの自動ログイン+取引先データ取得中の注意点
===

前述のスクリプトを実行すると、Seleniumにより自動的にChromeが起動されて、Salesforceへのログインやデータ取得操作が自動実行されます。

処理が完了すれば、Seleniumが起動したChromeは自動終了しますので、Chromeウィンドウが終了するまで待ちます。

・ユーザ名とパスワードの入力、ログインボタンのクリック、Salesforceへのログイン処理が動きます。

<img width="1190" alt="スクリーンショット 2018-04-08 2.52.07.png" src="https://qiita-image-store.s3.amazonaws.com/0/63647/1603908e-bfbc-9386-a1b8-6f7bdb268f26.png">

・Salesforceへのログインが成功すると「取引先」タブが自動クリックされます。

<img width="1201" alt="スクリーンショット 2018-04-08 2.52.29.png" src="https://qiita-image-store.s3.amazonaws.com/0/63647/e4670e06-942c-bdd9-3ae7-d7e7e8302c5c.png">

<img width="1201" alt="スクリーンショット 2018-04-08 2.52.48.png" src="https://qiita-image-store.s3.amazonaws.com/0/63647/17d0e51a-b145-c01c-b218-e6a7991de660.png">

<img width="1193" alt="スクリーンショット 2018-04-08 2.53.09.png" src="https://qiita-image-store.s3.amazonaws.com/0/63647/e66aaf0e-7597-ff1d-8546-2ae67c511cf0.png">

・取引先詳細画面のデータ取得と表示処理が動きます。

<img width="1192" alt="スクリーンショット 2018-04-08 2.53.17.png" src="https://qiita-image-store.s3.amazonaws.com/0/63647/42ff7661-8f03-5e0c-b957-74d59ac9f89c.png">

・取引先詳細画面の「取引先責任者」に指定した取引先責任者が登録されている場合、取引先責任者名が自動クリックされて、取引先責任者の詳細画面が表示されます。

<img width="1214" alt="スクリーンショット 2018-04-08 3.11.26.png" src="https://qiita-image-store.s3.amazonaws.com/0/63647/7492360f-79a2-6e97-2836-34627a6fb0b3.png">

・取引先責任者詳細画面のデータ取得と表示処理が動きます。

<img width="1201" alt="スクリーンショット 2018-04-08 2.53.36.png" src="https://qiita-image-store.s3.amazonaws.com/0/63647/2de05809-a86e-b6f3-fd79-8851bd394b14.png">

これらの処理が完了すると、起動したChromeのウィンドウが自動終了します。

最後に
===

Salesforceには [[Data Loader]](https://developer.salesforce.com/docs/atlas.ja-jp.dataLoader.meta/dataLoader/data_loader.htm) や [[Force.com CLI](https://force-cli.heroku.com/) といったデータ操作ツールが用意されております。

システム管理者等の権限を持ったSalesforceユーザなら、これらのツールを使う事でも、取引先オブジェクトのデータ自体は取得可能です。


今回はとある理由から、特定のプロファイルを割り当てたSalesforceユーザが実際にSalesforceへログインした際、取引先オブジェクトの特定項目のデータが正常に閲覧できているかどうかも確認したいと考えて、Selenium + Python で Salesforce へ自動ログインして取引先データを取得する方法をまとめてみました。

以上になります。

***