PythonでSalesforceのスクリーンショットを取得する

今のお仕事では業務の効率化のための自動化ツールの作成を行っています。

SalesforceからデータをExcelフォーマットに転記してSFのキャプチャをメールに貼って送るという業務が週に1回行われているのですが、この業務の自動化を依頼されました。

RPAで実行できるものはRPAで作成するのですが、RPAでダッシュボードやレポートのみのキャプチャをとるのが難しく、Pythonで実装することになりました。
（Win + Shift + SをSendKeysしてフルサイズのスクリーンショットをとったあとに座標をもとにトリミングしても良かったのですが、端末が変わると意図した場所でトリミングできなかったりしたので断念しました・・・）


実装したのがこちら↓
```python:utils.py
from selenium import webdriver
from selenium.webdriver.common.by import By
def take_screenshot(url, identifier, output_filename):
    try:
        driver = webdriver.Edge()
        driver.get(url)  
        driver.maximize_window()

        time.sleep(1)

        # Salesforce login
        # Read username and password from file
        with open(r'filepath', 'r') as file:
            lines = file.readlines()
            sfusername = lines[0].strip()
            sfpw = lines[1].strip()

        username = driver.find_element(By.NAME, 'username')
        pw = driver.find_element(By.NAME, 'pw')

        username.clear()
        pw.clear()

        username.send_keys(sfusername)
        pw.send_keys(sfpw)

        username.submit()

        time.sleep(5)

        # Determine if the identifier is an ID or a class
        element = None
        if identifier.startswith('#'):
            element = driver.find_element(By.ID, identifier[1:])
            # Click the refresh button
            refresh = driver.find_element(By.NAME, 'refresh')
            refresh.click()
            time.sleep(120)
        elif identifier.startswith('.'):
            element = driver.find_element(By.CLASS_NAME, identifier[1:])
        else:
            raise ValueError("Identifier must start with '#' for ID or '.' for class")

        # Get the location and size of the element
        location = element.location 
        size = element.size 

        # Take a screenshot of the webpage
        driver.save_screenshot('full_page_screenshot.png') 

        # Crop the screenshot to the specified element
        left = location['x'] 
        top = location['y'] 
        right = location['x'] + size['width'] 
        bottom = location['y'] + size['height'] 

        from PIL import Image 
        # Open the full page screenshot
        image = Image.open('full_page_screenshot.png') 
        # Crop the screenshot to the specified element
        element_screenshot = image.crop((left, top, right, bottom)) 
        # Save the screenshot
        element_screenshot.save(output_filename) 
        # Delete the temporary file
        os.remove('full_page_screenshot.png')
        #driver.quit()

    finally:
        # Quit the WebDriver
        if driver:
            driver.quit()
```

## 解説

1\. HTMLの要素(element)を取得
```
        # Determine if the identifier is an ID or a class
        element = None
        if identifier.startswith('#'):
            element = driver.find_element(By.ID, identifier[1:])
            # Click the refresh button
            refresh = driver.find_element(By.NAME, 'refresh')
            refresh.click()
            time.sleep(120)
        elif identifier.startswith('.'):
            element = driver.find_element(By.CLASS_NAME, identifier[1:])
        else:
            raise ValueError("Identifier must start with '#' for ID or '.' for class")
```
2\. 要素の位置、サイズを取得
```
        # Get the location and size of the element
        location = element.location 
        size = element.size 
```
3\. フルサイズのスクリーンショットをとったあとに上下左右の座標を元にトリミング
```
        # Take a screenshot of the webpage
        driver.save_screenshot('full_page_screenshot.png') 

        # Crop the screenshot to the specified element
        left = location['x'] 
        top = location['y'] 
        right = location['x'] + size['width'] 
        bottom = location['y'] + size['height'] 

        from PIL import Image 
        # Open the full page screenshot
        image = Image.open('full_page_screenshot.png') 
        # Crop the screenshot to the specified element
        element_screenshot = image.crop((left, top, right, bottom))
```
という流れで指定した要素のスクリーンショットを取得しています。

これで毎回安定してスクリーンショットを取得できるようになりました。

要素のidやnameを指定すれば好きな要素のスクリーンショットを取得できるのでとても便利です。

この取得したスクリーンショットをメール本文に埋め込んで送信するというのもPythonで実装したので別の記事でまとめたいと思います。

---------------------------------------
ソースコードはGitHubに上げています↓
[GitHub : sf-screenshot-tool](https://github.com/HitoTsuka/sf-screenshot-tool)