UWSC を Python で置換しよう（4） チートシート[2]

# はじめに

「UWSC を Python で置換しよう」第四回です。今回は前回の続きです、各モジュールのよく使う機能のチートシートを用意しました。
<font color=red>前回同様なにぶん、調べながら書いているため、間違っている点もあるかと思います。
その場合は、ビシバシ編集リクエストをください(汗</font>

前回は
[UWSC を Python で置換しよう（4） チートシート[1]](https://qiita.com/hirohiro77/items/b62e2e00405bbe2e8ee5)
次回は
[UWSC を Python で置換しよう（5） Robotを作ってみよう](https://qiita.com/hirohiro77/items/a385f9ab583acbb0b9db)

# 解説するモジュールと用途一覧
<font color=pink>
--チートシート[1]で解説したもの
-  PyAutoGUI (画像判定 / マウス・キーボード操作)
-  OpenCV (画像処理)※PyAutoGUI内部から使われる機能のみ解説
-  PyWin32 (Win32Api/Win32COM OLE/COMオブジェクト操作)
-  BeautifulSoup (html/xmlパーサー)
-  PyAudio (オーディオ操作)
-  SpeechRecognition (音声認識)
-  eSpeak (音声合成)</font>

--チートシート[2]で解説するもの
-  Selenium (ブラウザ操作)
-  xlrd , xlwt (Excel 読み書き)
-  OpenPyXL (Excel 読み書き)
-  ReportLab (PDF 読み書き)
-  PyInstaller (EXE 形式単一実行ファイル生成)
-  ConfigParser (cfg/ini 形式の読み込み)

# Selenium [[HP]](https://docs.seleniumhq.org/)

Seleniumはブラウザの自動テストツールです。単体では動作せず、ブラウザを操作する、WebDriverとセットで動作します。おおよその環境では、Chrome(&派生)かFirefox(&派生)が主だったブラウザかと思います。IEはSeleniumよりOLE/COMで制御した方がいいです。

- Chrome Driver

Chromeのバージョンに合わせたものを、ダウンロードして、python.exeと同じPATHに置いておくと良いです

https://chromedriver.chromium.org/downloads


- Gekko Driver

使用中のFireFoxのバージョンがサポートされているバージョンを、ダウンロードして、python.exeと同じPATHに置いておくと良いです。派生ブラウザ(Ice/CyberFox/WaterFoxなど)の場合は、使っているGekkoエンジンのバージョンで判断してください。大抵は最新版で大丈夫です

https://github.com/mozilla/geckodriver/releases

```cheat06.py
# モジュールのロード
from selenium import webdriver
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.alert import Alert
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.select import Select

##Chromeを操作
options = Options()
##Chromeのパス（通常は指定不要、ポータブル版などを使う場合やstable/beta切り替え時）
options.binary_location = 'PATH/To/Chrome.exe'
##起動オプション指定[Google Chrome まとめWiki](http://chrome.half-moon.org/43.html)
options.add_argument('--kiosk')
options.add_argument('--disable-gpu')
##ブラウザのオプション指定
options.add_experimental_option("prefs", {
    "download.default_directory": "%DriveRoot%¥temp¥",
    "plugins.always_open_pdf_externally": True
})
## ChromeのWebDriverオブジェクトを作成する。
driver = webdriver.Chrome(options=options,executable_path="./chromedriver.exe")

##Firefoxを操作
#options = Options()
##Firefoxのパス(通常は指定不要、ポータブル版などを使う場合や派生ブラウザ時)
#options.binary_location = 'Path/To/Firefox.exe'
##Firefox起動オプション(https://developer.mozilla.org/ja/docs/Mozilla/Command_Line_Options)
#options.add_argument('-browser')
#driver = webdriver.Firefox(options=options,executable_path="geckodriver")

#要素が見つかるまでの待ち時間、ドライバ生成直後にのみ指定可能
driver.implicitly_wait(10) 

#ページが完全にロードされるまで最大で5秒間待つよう指定、ドライバオブジェクト生成直後にのみ指定可能
driver.set_page_load_timeout(5)

#Javascript実行が終了するまで最大5秒間待つように指定
driver.set_script_timeout(5)

#URL移動
driver.get('https://www.google.com/')

#要素がクリックできるようになるまで待つ
WebDriverWait(driver, 30).until(EC.element_to_be_clickable((By.NAME, "q")))

## EC.xx の待機条件については、以下のようなものがある、ほぼ単語のままの意味
# title_is # 完全一致
# title_contains # 〜を含む
# presence_of_element_located
# visibility_of_element_located
# visibility_of
# presence_of_all_elements_located
# text_to_be_present_in_element
# text_to_be_present_in_element_value
# frame_to_be_available_and_switch_to_it
# invisibility_of_element_located
# element_to_be_clickable
# staleness_of
# element_to_be_selected
# element_located_to_be_selected
# element_selection_state_to_be # 要素がチェックONまたはチェックOFFになるまで待機
# element_located_selection_state_to_be
# alert_is_present　# Alertが表示されるまで待機する

## By.xx については以下のようなものが指定できる
# ID
# XPATH
# LINK_TEXT
# PARTIAL_LINK_TEXT
# NAME
# TAG_NAME
# CLASS_NAME
# CSS_SELECTOR

#ページが完全にロードされるまで最大で30秒間待機
driver.set_page_load_timeout(30)

#カレントウインドウのポジション(左上隅の座標)をX座標:100,Y座標:200に設定
driver.set_window_position(100,200)

#カレントウインドウを最大化する
driver.maximize_window()

#カレントウインドウのサイズを幅:100,高さ:200に設定する
driver.set_window_size(100,200)

#カレントウィンドウの座標(左上隅の座標)を取得(Dict型で返る)
coordinate = driver.get_window_position()

#カレントウィンドウのサイズを取得(Dict型で返る)
culSize = driver.get_window_size()

#カレントページのURLを取得
print(driver.current_url)

#カレントページのウィンドウハンドルを取得
print(driver.current_window_handle)

#カレントページのタイトルの取得
print(driver.title)

＃ブラウザを履歴中で一段階戻す
driver.back()

#ブラウザを履歴中で一段階進める
driver.forward()

#ページを更新(ブラウザのリフレッシュ)
driver.refresh()

#カレントページのソースを取得、保存したり、BeautifulSoupに渡して解析したりする
pages = driver.page_source.encode('utf-8')

#全てのウィンドウハンドルを取得(複数のウインドウを開いているとき)
allHandles = driver.window_handles
#ウィンドウハンドルはリスト型
print(allHandles[0])
#switch_to_windowを使って、切り替えできる
driver.switch_to_window(allHandles[0])

#カレントドメインの全てのクッキーを取得する(List型で返る)
allCookies = driver.get_cookies()

#クッキー名からクッキーを検索
cookie = driver.get_cookie("ABC")

#クッキー名を指定して削除
driver.delete_cookie("ABC")

#全てのクッキーを削除
driver.delete_all_cookies()

#表示されたダイアログの文字列を取得する
alertText = Alert(driver).text

#"OK or Cancel"の確認でOKを選択
Alert(driver).accept()

#カレントページのスクリーンショットを取得し保存(取得できた場合はTRUE)
if driver.get_screenshot_as_file("screenshot.png"):
    print("ScreenShot Sucsess")
else:
    print("ScreenShot Failed")

#エレメント取得
search_box = driver.find_element_by_name("q")
search_box.send_keys('ChromeDriver')
search_box.submit()

## 要素に関しては以下の設定ができる(パブリックメソッド)
## 単一要素
# find_element_by_id
# find_element_by_name
# find_element_by_xpath
# find_element_by_link_text
# find_element_by_partial_link_text
# find_element_by_tag_name
# find_element_by_class_name
# find_element_by_css_selector
## 複数要素
# find_elements_by_name
# find_elements_by_xpath
# find_elements_by_link_text
# find_elements_by_partial_link_text
# find_elements_by_tag_name
# find_elements_by_class_name
# find_elements_by_css_selector
# 複数取得時はforで回す

## 要素から属性操作
TargetElement = driver.find_element_by_name("q")

# クリア
TargetElement.clear()

# 文字列入力
TargetElement.send_keys("STR")

# 仮想キー
TargetElement.send_keys(Keys.ENTER)

# クリック
TargetElement.click()

# 送信
TargetElement.submit()

# 属性値取得
TargetElement.get_attribute("value")

# 要素のタグ名を取得する
TargetElement.tag_name

# 要素のinnerTextを出力
TargetElement.text

# CSSプロパティ名(text-align)からプロパティ値を取得
TargetElement.value_of_css_property("text-align")

# 要素の左上隅の座標を取得(dict)
TargetElement.location

# セレクトタグ内のオプションに含まれるインナーテキストを出力
for i in range(len(TargetElement.options)):
    print(TargetElement.options[i].text)

# 選択状態にあるオプションのインナーテキストを出力
for i in range(len(TargetElement.all_selected_options)):
    print(TargetElement.all_selected_options[i].text)

# 要素の表示状態を判定
if TargetElement.is_displayed():
    print("True:Displaed")
else:
    print("False:IsDisplayed")

# 要素がEnableかどうか判定
if TargetElement.is_enabled():
    print("True:Enable")
else:
    print("False:Disable")

#要素が選択されているかどうか判定
if TargetElement.is_selected():
    print("True:Selected")
else:
    print("False:IsSelected")

#セレクトタグの要素を指定してSelectクラスのインスタンスを作成
select = Select(TargetElement)
    #セレクトタグのオプションをインデックス番号から選択する
    select.select_by_index(indexNum)
    #指定したインデックス番号のオプションを未選択にする
    select.deselect_by_index(indexNum)
    #セレクトタグのオプションをテキストを指定して選択する
    select.select_by_visible_text(text)
    #全て未選択にする
    select.deselect_all()
    #指定したValue属性のオプションを未選択にする
    select.deselect_by_value(value)
    #テキストで指定したオプションを未選択にする
    select.deselect_by_visible_text(text)


##ActionChainsは直前に検索(find_*)した要素に対して操作する
#Controlキーを押下しながらエレメントをクリック(PyAutoGUIと組み合わせる場合、バッティング注意、どちらかのモジュールでpid/handleで操作しているとエラーになる、座標指定なら問題なし)
ViewButton = driver.find_element_by_id("button")
actions = ActionChains(driver)
actions.key_down(Keys.CONTROL)
actions.click(ViewButton)
actions.key_up(Keys.CONTROL)
actions.perform()

#Controlキーを押下しながら指定の座標へマウスカーソル移動してクリックする
actions = ActionChains(driver)
actions.key_down(Keys.CONTROL)
actions.move_by_offset(400,320)
actions.click()
actions.perform()

#Shiftキーを押下しながら"abc"を入力し、Shiftキーを押下しないで"de"を入力
actions = ActionChains(driver)
actions.key_down(Keys.SHIFT)
actions.send_keys("abc")
actions.key_up(Keys.SHIFT)
actions.send_keys("de")
actions.perform()

#要素をドラッグした状態でX/Y方向に100ポイントカーソル移動させる
select_element = driver.find_element_by_id("target")
actions = ActionChains(driver)
actions.click_and_hold(select_element)
actions.move_by_offset(100,100)
actions.perform()

#移動元(src)の要素と移動先(dst)の要素を取得
src_element  = driver.find_element_by_id("draggable")
dst_element  = driver.find_element_by_id("droppable")
#3秒間待機してドラッグ前の状態を確認
time.sleep(3)
#移動元の要素をドラッグし移動先の要素へカーソル移動、重ねるだけdropしない
actions = ActionChains(driver)
actions.click_and_hold(src_element)
actions.move_to_element(dst_element)
actions.perform()

#要素をX方向に250ポイント,y方向に200ポイント移動する、ドラッグアンドドロップを実行
actions = ActionChains(driver)
actions.drag_and_drop_by_offset(element,250,200)
actions.perform()

#移動元(src)の要素と移動先(dst)の要素を取得
src_element = driver.find_element_by_id("draggable")
dst_element = driver.find_element_by_id("droppable")
#3秒間待機して移動前の位置を確認
time.sleep(3)
#移動元の要素をドラッグし移動先の要素へドロップ
actions = ActionChains(driver)
actions.drag_and_drop(src_element,dst_element)
actions.perform()

# driverを終了
driver.close()

# 全て終了
driver.quit()
```

# xlrd [[github]](https://github.com/python-excel/xlrd) , xlwt [[github]](https://github.com/python-excel/xlwt)

単純な、読み書きであれば、こちらでいいが、図表を含むような場合はOpenPyXLを使った方が良い。
ただし、動作はこちらの方が軽いので、リソース消費を抑えたい場合は、こちらがいいかもしれない

```cheat07.py
import xlrd
import xlwt
from xlutils.copy import copy

#xlsxを開く
rb = xlrd.open_workbook('sample.xlsx',formatting_info=True)

#シート名表示
print(rb.sheet_names())

#シート番号か、シート名で指定
sheet = sheet_by_index(0)
sheet = rb.sheet_by_name('sheet1')

#セルの値を取得、Cellの属性、もしくは、オブジェクトのメソッドCell_Valueで取得できる
cell = sheet.cell(1,2).value
cell = sheet.cell_value(1, 2)

#列指定で取得(xlrd.sheet.Cellで取れる)
col = sheet.col(1)

#列指定の値取得(Listで取れる)
col_values = sheet.col_values(1)

#行指定で取得
row = sheet.row(1)

#行指定の値取得(Listで取れる)
row_values = sheet.row_values(1)

#二次元配列で取り出し
def get_list_2d_all(sheet):
    return [sheet.row_values(row) for row in range(sheet.nrows)]

l_2d_all = get_list_2d_all(sheet)
print(l_2d_all[1][0])

#テンプレートがある場合はxlutilsで書式を複製する
wb = copy(rb)

#新しいシート追加
sheet = wb.add_sheet('sheet3')

#sheet.write(行, 列, '値')で書き込む
sheet.write(0, 0, 'A')
sheet.write(0, 1, 'B')
sheet.write(1, 0, 10)
sheet.write(1, 1, 20)

#書き込み
wb.save('xlwt_sample.xlsx')
```

- OpenPyXL [[BitBucket]](https://bitbucket.org/openpyxl/openpyxl/src/default/)
[Manual](https://openpyxl.readthedocs.io/en/stable/index.html)

xlrd,xlwtではオートシェイプなどの設定が難しいので、複雑なテンプレートを使う場合はopenpyxlを使う
ただし、前述通り少々重いのが難点です。よく使うものだけ抽出していますので、グラフについてはマニュアルにもっと種類が載っています。
オートシェイプについては、Drawingモジュールで一部サポートしていますが、まだ完全には使えないようです

```cheat08.py
import openpyxl
from openpyxl.drawing.image import Image
from openpyxl.styles import colors ,Border, Side, PatternFill, Font, Color ,GradientFill, Alignment, numbers
from openpyxl.chart import (
    LineChart,
    Reference,
)

#既存ファイルを開く
WorkBook = openpyxl.load_workbook('sample2.xlsx')

#新規作成
#WorkBook = openpyxl.Workbook()

#シート名を取得(List型)
print(WorkBook.sheetnames)
CheckName = WorkBook.sheetnames[0]

#アクティブなbookから、アクティブなシートを指定
sheet = WorkBook.active

# 名前を指定
sheet = WorkBook.worksheets['Sheet_New']

# 新規作成(0番目に配置)      
sheet = WorkBook.create_sheet('Sheet_New', 0)

# 既存からコピー 
sheet = WorkBook.copy_worksheet('Sheet_1')

#シート名で指定
if CheckName == 'Sheet_1':
    sheet = WorkBook['Sheet_1']
if CheckName == 'Sheet_XX':
    sheet = WorkBook['Sheet_XX']

#シート名を書き換え
sheet.title = "Sheet_XX"

#セルを指定して読み出し
print(sheet["B4"].value)
print(sheet.cell(column=10, row=10).value)

#セルに値を入れる
sheet["B4"] = "ABCDE"

#行と列を指定しても書き込める
sheet.cell(row = 1, column = 1, value = 5)
sheet.cell(row = 2, column = 1, value = 10)
sheet.cell(row = 3, column = 1, value = 15)
sheet.cell(row = 2, column = 3, value = 23)
sheet.cell(row = 4, column = 6, value = "This is F4")

#書式設定
sheet["C3"].value = 1000.99
sheet["C3"].number_format = '#,##0'
sheet["C4"].value = 100
sheet["C4"].number_format = '0.000'

# 行の高さを変更
sheet.row_dimensions[1].height = 30
# 列の幅を変更
sheet.column_dimensions['B'].width = 50

#関数を入力
sheet['B1'].value = '=SUM(A1:A3)'
sheet['B2'].value = '=AVERAGE(A:A)'

#画像貼り付け
img = Image('figure.png')
sheet.add_image(img,'D1')

#グラフ挿入
#データ範囲(対象シート,最小値列,最小値行,最大値列,最大値行)
data = Reference(sheet, min_col=2, min_row=1, max_col=4, max_row=7)
LineFig1 = LineChart()
LineFig1.title = "折れ線グラフ"
LineFig1.style = 13 # グラフ種別
LineFig1.y_axis.title = '縦タイトル'
LineFig1.x_axis.title = '横タイトル'
LineFig1Style1 = LineFig1.series[0] # 折れ線1の色
LineFig1Style1.marker.symbol = "triangle" # マーカーの形
LineFig1Style1.marker.graphicalProperties.solidFill = "FF0000" # 影色 
LineFig1Style1.marker.graphicalProperties.line.solidFill = "FF0000" # 線色
LineFig1Style1.graphicalProperties.line.noFill = True
LineFig1Style2 = LineFig1.series[1] # 折れ線2の色
LineFig1Style2.graphicalProperties.line.solidFill = "00AAAA"
LineFig1Style2.graphicalProperties.line.dashStyle = "sysDot"
LineFig1Style2.graphicalProperties.line.width = 100050
#描画
LineFig1.add_data(data, titles_from_data=True)
sheet.add_chart(LineFig1, "F1")

#指定列前に空列挿入(開始列,挿入列数)
sheet.insert_cols(7,2)

#指定行前に空行挿入(開始列,挿入行数)
sheet.insert_rows(7,2)

#指定列を削除(開始列,削除列数)
sheet.delete_cols(6,3)

#指定行を削除(開始行,削除行数)
sheet.delete_rows(6,3)

#フォント設定(フォント/書体/色/下線/塗りつぶし)
sheet['A1'].font = Font(color=colors.RED, bold=True)
sheet['A2'].font = Font(color=colors.BLUE, italic=True)
sheet['A3'].font = Font(color=colors.GREEN, name='Arial', size=14, underline="single")

#セルの水平中寄せ、垂直中央寄せ
sheet['C2'].value = 'TEXT'
sheet['C2'].alignment = Alignment(horizontal="center", vertical="center")

#セル結合
sheet.merge_cells('A2:D2')
#セル結合解除
sheet.unmerge_cells('A2:D2')

#背景色指定
sheet['A3'].fill = PatternFill(patternType='solid', fgColor='FDE9D9')

#罫線(Cellに対して上下左右)
#線種指定(‘dashDot’, ‘dashDotDot’, ‘double’, ‘hair’, ‘dotted’, ‘mediumDashDotDot’, ‘dashed’, ‘mediumDashed’, ‘slantDashDot’, ‘thick’, ‘thin’, ‘medium’, ‘mediumDashDot’)
BlackLine = Side(style='thin', color='000000')
BlueLineThick = Side(style='thick', color='0000FF')

#セルに対して指定
sheet['B1'].border = Border(top= BlackLine, bottom= BlueLineThick, left= BlackLine, right= BlackLine)

#印刷用紙設定
sheet.page_setup.orientation = sheet.ORIENTATION_LANDSCAPE
sheet.page_setup.paperSize = sheet.PAPERSIZE_TABLOID

#余白設定(inch)
sheet.page_setup.fitToHeight = 0
sheet.page_setup.fitToWidth = 1

#印刷位置 : 中寄せ
sheet.print_options.horizontalCentered = True
sheet.print_options.verticalCentered = True

#印刷ヘッダー/フッター[全ページ共通] (左寄せ:left,右寄せ:right,中寄せ:center)
sheet.oddHeader.left.text = "Page &[Page] of &N"
sheet.oddHeader.left.size = 14
sheet.oddHeader.left.font = "MS Gothic,Bold"
sheet.oddHeader.left.color = "CC3366"
sheet.oddFooter.center.text = "Page &[Page] of &N"

#印刷ヘッダー/フッダー[1ページ目のみ]
sheet.firstHeader.center.text = "Title"
sheet.firstFooter.center.text = "Page &[Page] of &N"

#印刷ヘッダー/フッダー[1ページ目以外]
sheet.evenHeader.center.text = "Title"
sheet.evenFooter.center.text = "Page &[Page] of &N"

#印刷タイトル行、列指定
sheet.print_title_cols = 'A:B' 
sheet.print_title_rows = '1:1' 

#印刷範囲
sheet.print_area = 'A1:F10'

# 保存
WorkBook.save('sample2.xlsx')
```

# ReportLab [[BitBucket]](https://bitbucket.org/rptlab/reportlab/src/default/) [Manual](https://www.reportlab.com/dev/docs/)

ReportLabはPDFを生成・編集することができる、いろいろあるPDFのライブラリの中でかなり有用なライブラリであることはまちがいない。OSS版と商用版がある。使用方法についてもマニュアルが充実しているので、すぐ利用できる点もとてもいい。暗号化やパスワードがかかっていないPDFについては、追記も可能

```cheat09.py
from reportlab.pdfgen import canvas
from reportlab.lib import colors
from reportlab.lib.pagesizes import A4, portrait , landscape
from reportlab.platypus import SimpleDocTemplate, Table, TableStyle
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.lib.utils import ImageReader


class PdfConfig:
    title = "No title" # タイトル
    author = "" # オーナー
    subject = "" # サブタイトル

    default_fontname = "MS Gothic"
    image_resolution = 300 # DPI
    jpeg_quality = 95 # Jpeg 圧縮率
    font_adjustment = 0.85 # フォント間隔
    image_embeded = True # 画像同梱

    def __init__(self):
        pass

config = PdfConfig()
output_filename = 'output_new.pdf' #出力ファイル名固定

#キャンバス作成
newPdfPage = canvas.Canvas(output_filename)

# 用紙 / 向き
# A0,A1,A2,A3,A4,A5,A6
# B0,B1,B2,B3,B4,B5,B6
# LETTER, LEGAL, ELEVENSEVENTEEN
page_size['width'], page_size['height'] = A4
#縦
newPdfPage.setPageSize(portrait(A4))
#横
#newPdfPage.setPageSize(landscape(A4))
#カスタムサイズ(cm指定)
#newPdfPage.setPageSize(page_size['width'], page_size['height'])

newPdfPage.setAuthor(config.author) # オーナー設定
newPdfPage.setTitle(config.title) # タイトル設定
newPdfPage.setSubject(config.subject) #サブタイトル設定

#画像貼り付け(ファイル名,Xoffset,Yoffset,画像幅,画像高さ,アスペクト比維持,アンカー)
newPdfPage.drawImage(imagefilename, 0+image_offset_x, 0+image_offset_y,width=page_size['width'],
height=page_size['height'], preserveAspectRatio=True, anchor='c')

#文字書き込み(座標X,座標Y,文字列)
str_out = "Hello World"
newPdfPage.drawString(100, 730, str_out)

# Canvasに書き込みと改ページ
newPdfPage.showPage()

#そのまま書いていけばOK
pdf_canvas.drawString(100, 700, "２ページ目です。")
pdf_canvas.showPage()

# ファイル保存
newPdfPage.save()
```

# PyInstaller [[HP]](https://www.pyinstaller.org/)

こちらは過去に記事を書いているので、そちらを参考にしてください(手抜き

参照先 : [Pythonスクリプトを単一実行ファイルにする方法](https://qiita.com/hirohiro77/items/466e411fa41f144c8b2a)

使い方だけ、転記

```
pyinstaller pythonファイル名 [--onefile] [--noconsole] [--windowed]
```

|挙動|オプション|概要|
|---|---|---|
|コンパイルする | --onefile | 関連するファイルを1つにまとめてバイナリ化します|
|非コンソール表示 | --noconsole | コンソールアプリでもコンソール表示をしないようにします|
|Windowsバイナリ生成 | --windowed | 異なるプラットフォームでもWindowsのバイナリを作ります|
|データバインド | --add-data | バイナリ内部にファイルを取り込みます|
|管理者モード実行 | --uac-admin --uac-uiaccess |管理者モードで実行するバイナリを作ります|

画像マッチングなどで、画像を含む場合は、画像の入ったフォルダを取り込むか、相対パスで指定しておくと幸せになれるかも。

```shell

pyinstaller pythonファイル名 --onefile --add-data "./data/logo.png;./sample01.png;sample02.png"
```

あとは、レシピを書いたSPECファイルを作って指定する方法でもいいと思う

```compile.spec.py
# -*- mode: python -*-
# filename = Compile.spec

a = Analysis(['pythonファイル名'],
             pathex=['スクリプトがあるPATH'],
             datas=[('./data/logo.png','DATA'),('./data/sample01.png','DATA'),('./data/sample02.png','DATA')],
             hiddenimports=[],
             hookspath=None,
             runtime_hooks=None)
pyz = PYZ(a.pure)
exe = EXE(pyz,
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,
          name='Main',
          debug=False,
          strip=None,
          upx=True,
          console=False , icon='アイコンファイル')
app = BUNDLE(exe,
             name='実行ファイル名',
             icon='アイコンファイル')
```

みたいに書いて

```shell

pyinstaller Compile.spec 
```

と実行すれば、実行形式のファイルが生成される。
この実行ファイルはPythonの環境がインストールされていなくても実行できるので、ロボットの配布にはもってこいだと思います。

# ConfigParser [[Manual]](https://docs.python.org/ja/3/library/configparser.html)

これは、cfg/conf/iniと行ったセッションディレクティブ形式のテキストを読み込むモジュール
キーバリュー型の設定テキストを簡単に読み出すことができるので、ロボットの設定を簡単に読み書きするのがとても捗ります。

例えば、以下のような設定がある場合

```sample.conf
[webserver]
ipaddress = 192.168.0.1
port = 80
useSSL = false

[proxy]
ipaddress = 127.0.0.1
port = 1080
proto = socks
```

```cheat10.py
import configparser

# 設定ファイルのパス
CONF_FILEPATH = 'sample.conf'

config = configparser.ConfigParser()

config.read( CONF_FILEPATH, 'UTF-8')

# confファイルで[]で囲った場所を指定
config_webserver = config['webserver']
config_proxy     = config['proxy']

# confで[]の下に変数とデータを入れてる内容を取得
HOST      = config_webserver['ipaddress']
PORT      = config_webserver['port']
SSL       = config_webserver['useSSL']

PROXY     = config_proxy['ipaddress']
PROXYPORT = config_proxy['port']
PROTOCOL  = config_proxy['proto']

#新しいセッションディレクティブを作る
section = 'AppServer'
config.add_section(section)
config.set(section, 'host', HOST)
config.set(section, 'port', PORT)
config.set(section, 'proxy_proto', PROTOCOL)
config.set(section, 'proxy', PROXY)
config.set(section, 'proxy_port', PROXYPORT)

#書き込む
with open('server.conf', 'w') as file:
    config.write(file)
```

こんな感じに書くと、簡単に読み書きができて、以下のような、server.confが作れる。

```server.conf
[webserver]
ipaddress = 192.168.0.1
port = 80
usessl = false

[proxy]
ipaddress = 127.0.0.1
port = 1080
proto = socks

[AppServer]
host = 192.168.0.1
port = 80
proxy_proto = socks
proxy = 127.0.0.1
proxy_port = 1080
```

# さいごに

自分用の意味合いで書いているもののため、微妙な書き方になっているところがあります。ご容赦ください・・・

次回は `UWSC を Python で置換しよう（5） Robotを作ってみよう` の予定