IT技術で仕事を減らしたい!

ITエンジニアのメモ+α

Python GoogleSheetsAPIでスプレッドシートへ書き込み

どうも、nippa です。

前回に続き、Google スプレッドシートの操作についてまとめておきます。

今回は GoogleSheetAPI を利用して、スプレッドシートのセルに書き込みをしていきたいと思います。

GoogleSheetsAPI の詳細については、こちらを参考にしてください。

Google Sheets API v4(英語)

また、スプレッドシートの情報取得に関しては以前の記事を参考にしてください。

GoogleSheetsAPI の有効化については、以前の記事同様の内容です。

環境

Google Sheets API を有効化

すでに有効化している場合は読み飛ばしてください。

新しくプロジェクトを作成

既存のプロジェクトを利用する場合は、作成不要です。

複数 Google アカウントログインしている場合は、ユーザを選んでから行なってください。

Cloud Console のダッシュボードにアクセスします。

Google Cloud Console

プロジェクトを選択 -> 「新しいプロジェクトの作成」 -> プロジェクトを作成

Google Sheet API を有効化

利用するプロジェクトを選択後に、

「ライブラリ」-> 「Google Sheets API」 -> 「有効可する」を選択

Google Cloud Console ライブラリ

Google Sheets API を無効化する場合が、

「ライブラリ」-> 「Google Sheets API」 -> 「概要」-> 「API を無効にする」

で無効化することもできます。

認証情報の作成と保存

有効可したあとに、認証情報を作成します。

認証情報には 2 種類あります。

  • OAuth クライアント ID: ユーザが Google スプレッドシートにアクセスする認証情報
  • サービスアカウント: サービス、アプリ用の認証情報

必要に応じて、使い分けてください。

「認証情報」 -> 「認証情報を作成」 -> 認証情報を選択して作成

作成した認証情報を保存します。

この認証情報を使って pythongoogle スプレッドシートにアクセスします。

認証情報は、重要な情報なので取り扱いに注意してください。

Git でサーバ上にアップロードなどしないように。

必要なライブラリのインストール

pip でインストールする場合は、以下です。

pip install google-api-python-client google-auth-httplib2 google-auth-oauthlib

conda でインストールする場合は、以下です。

conda install google-api-python-client google-auth-httplib2 google-auth-oauthlib

PythonGoogle スプレッドシートのセルに値を書き込む

スプレッドシートの ID と シート名

ブラウザからスプレッドシートを開いていただき、URL から確認することができます。

https://docs.google.com/spreadsheets/d/[スプレッドシートのID]/edit#gid=0

ブラウザ下部に表示されるシート名をメモしておいてください。

スプレッドシートの ID がわかっている場合は、API からシートの情報を取得できます。

下記は、スプレッドシートの ID の引数に与えるとすべてのシート名を順に表示する python のコードになっています。

import sys
import pickle
import os.path
from google.auth.transport.requests import Request
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError as googleHttpError

scopes = ['https://www.googleapis.com/auth/spreadsheets.readonly']

if len(sys.argv) == 2:
    spreadsheet_id = sys.argv[1]
else:
    sys.exit(f'invalid arguments. \n Usage: {sys.argv[0]} [Spreadsheet ID]')

creds = None

if os.path.exists('token.pickle'):
    with open('token.pickle', 'rb') as token:
        creds = pickle.load(token)
if not creds or not creds.valid:
    if creds and creds.expired and creds.refresh_token:
        creds.refresh(Request())
    else:
        flow = InstalledAppFlow.from_client_secrets_file(
            'credentials.json', scopes)
        creds = flow.run_local_server(port=0)
    with open('token.pickle', 'wb') as token:
        pickle.dump(creds, token)

service = build('sheets', 'v4', credentials=creds)
sheet = service.spreadsheets()

try:
    result = sheet.get(spreadsheetId=spreadsheet_id).execute()
except googleHttpError as e:
    print(e)

for sheet in result['sheets']:
    print('Index %s: Sheet name = %s' % (
        sheet['properties']['index'],
        sheet['properties']['title'])
    )

コードを sample1.py とした場合、実行結果の出力結果は以下のようになります。

python sample1.py [スプレッドシートのID]

# 出力結果
Title [シートのタイトル]: Sheet ID = [シートのID]

このとき、認証情報としてcredentials.jsonまたは Token (token.pickle)を読み込んでいますので、同じディレクトリの中に保存しておいてください。

特定のシートのセルに値を書き入れる

セルへの書き込みにはspreadsheets().values().updateを利用します。

いくつかオプションがありますが、基本的には body で以下を指定すれば、書き込み可能です。

body = {
    'range': '[シート名]![セルの範囲],
    'majorDimension': 'ROWS',
    'values': [値のリスト]
}

service = build('sheets', 'v4', credentials=creds)
sheet = service.spreadsheets()
result = sheet.values().update(spreadsheetId=[スプレッドシートのID],
                               range='[シート名]![セルの範囲]',
                               body=body).execute()

配列の並びとスプレッドシートの関係はmajorDimensionで指定します。

'majorDimension': 'ROWS'のときは、行方向に値を書き入れていきます。

RANGE = '[シート名]!A1:B5'
valuse = [['test0', '0'], ['test1', '1'], ['test2', '2'], ['test3', '3'], ['test4', '4']]

python の配列がスプレッドシートに以下の表の用に書き込まれます。

A B
1 test0 0
2 test1 1
3 test2 2
4 test3 3
5 test4 4

'majorDimension': 'COLUMNS'のときは、列方向に値を書き入れていきます。

RANGE = '[シート名]!A1:E2'
valuse = [['test0', '0'], ['test1', '1'], ['test2', '2'], ['test3', '3'], ['test4', '4']]

python の配列がスプレッドシートに以下の表の用に書き込まれます。

A B C D E
test0 test1 test2 test3 test4
2 0 1 2 3 4

書き込み用のサンプルプログラム

引数にスプレッドシートの ID とシート名を与えます。

指定したスプレッドシートのシートの A1:B5 までに以下のような書き込みを行い、値を取得します。

A B
1 test0 0
2 test1 1
3 test2 2
4 test3 3
5 test4 4
import init
import sys
import pickle
import os.path
from google.auth.transport.requests import Request
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError as googleHttpError

scopes = ['https://www.googleapis.com/auth/spreadsheets.readonly']

if len(sys.argv) == 3:
    spreadsheet_id = sys.argv[1]
    sheet_name = sys.argv[2]
else:
    sys.exit(f'invalid arguments. \n Usage: {sys.argv[0]} [Spreadsheet ID]')

creds = None

if os.path.exists('token.pickle'):
    with open('token.pickle', 'rb') as token:
        creds = pickle.load(token)
if not creds or not creds.valid:
    if creds and creds.expired and creds.refresh_token:
        creds.refresh(Request())
    else:
        flow = InstalledAppFlow.from_client_secrets_file(
            'credentials.json', scopes)
        creds = flow.run_local_server(port=0)
    with open('token.pickle', 'wb') as token:
        pickle.dump(creds, token)

service = build('sheets', 'v4', credentials=creds)
sheet = service.spreadsheets()

# Config
range_ = sheet_name + '!A1:B5'

# Check values on sheet
try:
    result = sheet.values().get(spreadsheetId=spreadsheet_id,
                                range=range_).execute()
    print(result.get('values', []))
except googleHttpError as e:
    print(e)

# Preprocess
values = []
for i in range(10):
    values += [[f'test{i}', i]]

value_input_option = 'RAW'

body = {
    'range': range_,
    'majorDimension': 'ROWS',
    'values': values
}

# Write values to sheet
try:
    result = sheet.values().update(spreadsheetId=spreadsheet_id,
                                   range=range_,
                                   valueInputOption=value_input_option,
                                   body=body).execute()
except googleHttpError as e:
    print(e)

# Check values on sheet
try:
    result = sheet.values().get(spreadsheetId=spreadsheet_id,
                                range=range_).execute()
    print(result.get('values', []))
except googleHttpError as e:
    print(e)

感想

python から GoogleSheetsAPI を使ってスプレッドシートの特定のシートに値を書き入れることができました。

セルの読み書きがこれでできるようになったので、スプレッドシートの簡単な操作が python からできるようになりました。

他にもグリッドの操作、色の操作などを GoogleSheetsAPI を使って行うことができます。

これらの操作については、今後必要に合わせてまとめていきたいと思っています。

仕事の効率化に使ってみてはいかがでしょうか?

ではでは、また次回。

Python GoogleSheetsAPIでスプレッドシートの情報取得

どうも、nippa です。

python で便利な操作を勉強中です。

本日は、pythonGoogle スプレッドシート(SpeadSheets)から情報を取得してみたいと思います。

Google の公式のクイックスタートを参考にして、python で GoogleSheetAPI を利用してみたいと思います。

GoogleSheetsAPI は Google アカウントがあれば無料で使えます。

GoogleSheetsAPI の詳細については、こちらを参考にしてください。

Google Sheets API v4(英語)

環境

Google Sheets API を有効化

新しくプロジェクトを作成

既存のプロジェクトを利用する場合は、作成不要です。

複数 Google アカウントログインしている場合は、ユーザを選んでから行なってください。

Cloud Console のダッシュボードにアクセスします。

Google Cloud Console

プロジェクトを選択 -> 「新しいプロジェクトの作成」 -> プロジェクトを作成

Google Sheet API を有効化

利用するプロジェクトを選択後に、

「ライブラリ」-> 「Google Sheets API」 -> 「有効可する」を選択

Google Cloud Console ライブラリ

Google Sheets API を無効化する場合が、

「ライブラリ」-> 「Google Sheets API」 -> 「概要」-> 「API を無効にする」

で無効化することもできます。

認証情報の作成と保存

有効可したあとに、認証情報を作成します。

認証情報には 2 種類あります。

  • OAuth クライアント ID: ユーザが Google スプレッドシートにアクセスする認証情報
  • サービスアカウント: サービス、アプリ用の認証情報

必要に応じて、使い分けてください。

「認証情報」 -> 「認証情報を作成」 -> 認証情報を選択して作成

作成した認証情報を保存します。

この認証情報を使って pythongoogle スプレッドシートにアクセスします。

認証情報は、重要な情報なので取り扱いに注意してください。

Git でサーバ上にアップロードなどしないように。

必要なライブラリのインストール

pip でインストールする場合は、以下です。

pip install google-api-python-client google-auth-httplib2 google-auth-oauthlib

conda でインストールする場合は、以下です。

conda install google-api-python-client google-auth-httplib2 google-auth-oauthlib

PythonGoogle スプレッドシートのセルの情報を取得

Google のクイックスタートのサンプルコード(読み取りのみ)

PythonGoogle Sheets API のサンプルコードは以下から取得できます。

Github python-samples/sheets/quickstart/quickstart.py

内容は以下の通りです。

from __future__ import print_function
import pickle
import os.path
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request

# If modifying these scopes, delete the file token.pickle.
SCOPES = ['https://www.googleapis.com/auth/spreadsheets.readonly']

# The ID and range of a sample spreadsheet.
SAMPLE_SPREADSHEET_ID = '1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms'
SAMPLE_RANGE_NAME = 'Class Data!A2:E'

def main():
    """Shows basic usage of the Sheets API.
    Prints values from a sample spreadsheet.
    """
    creds = None
    # The file token.pickle stores the user's access and refresh tokens, and is
    # created automatically when the authorization flow completes for the first
    # time.
    if os.path.exists('token.pickle'):
        with open('token.pickle', 'rb') as token:
            creds = pickle.load(token)
    # If there are no (valid) credentials available, let the user log in.
    if not creds or not creds.valid:
        if creds and creds.expired and creds.refresh_token:
            creds.refresh(Request())
        else:
            flow = InstalledAppFlow.from_client_secrets_file(
                'credentials.json', SCOPES)
            creds = flow.run_local_server(port=0)
        # Save the credentials for the next run
        with open('token.pickle', 'wb') as token:
            pickle.dump(creds, token)

    service = build('sheets', 'v4', credentials=creds)

    # Call the Sheets API
    sheet = service.spreadsheets()
    result = sheet.values().get(spreadsheetId=SAMPLE_SPREADSHEET_ID,
                                range=SAMPLE_RANGE_NAME).execute()
    values = result.get('values', [])

    if not values:
        print('No data found.')
    else:
        print('Name, Major:')
        for row in values:
            # Print columns A and E, which correspond to indices 0 and 4.
            print('%s, %s' % (row[0], row[4]))

if __name__ == '__main__':
    main()

前項で作成した認証情報と quickstart.py を同じフォルダに保存し、実行します。

python quickstart.py

#実行結果
Name, Major:
Alexandra, English
Andrew, Math
Anna, English
Becky, Art
Benjamin, English
Carl, Art
Carrie, English
Dorothy, Math
Dylan, Math
Edward, English
Ellen, Physics
Fiona, Art
John, Physics
Jonathan, Math
Joseph, English
Josephine, Math
Karen, English
Kevin, Physics
Lisa, Art
Mary, Physics
Maureen, Physics
Nick, Art
Olivia, Physics
Pamela, Math
Patrick, Art
Robert, English
Sean, Physics
Stacy, Math
Thomas, Art
Will, Math

初回の場合、認証を要求される場合があります。

python コードの中では、認証情報を使って、Token を作成してます。

2 回目からは認証情報ではなく、Token を利用してアクセスしています。

Google のサンプルのスプレッドシートにアクセスして情報を取得して、その情報が表示されます。

スプレッドシート全体の情報の取得

python からスプレッドシート全体の情報の取得する場合、以下のスクリプトになります(スプレッドシート、シート情報)。

こちらには、セルの情報は含まれません。

spreadsheet_idスプレッドシートの ID を指定して下さい。

import json
import pickle
import os.path
from google.auth.transport.requests import Request
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError as googleHttpError

scopes = ['https://www.googleapis.com/auth/spreadsheets.readonly']
spreadsheet_id = 'XXXXXXXXXXXXXXXX'

creds = None

if os.path.exists('token.pickle'):
    with open('token.pickle', 'rb') as token:
        creds = pickle.load(token)
if not creds or not creds.valid:
    if creds and creds.expired and creds.refresh_token:
        creds.refresh(Request())
    else:
        flow = InstalledAppFlow.from_client_secrets_file(
            'credentials.json', scopes)
        creds = flow.run_local_server(port=0)
    with open('token.pickle', 'wb') as token:
        pickle.dump(creds, token)

service = build('sheets', 'v4', credentials=creds)
sheet = service.spreadsheets()

try:
    result = sheet.get(spreadsheetId=spreadsheet_id).execute()
except googleHttpError as e:
    print(e)

print(json.dumps(result, indent=2))

スプレッドシートの情報が表示されます。

スプレッドシートの ID とアクセス権限について

サンプルコード quickstart.py では

SAMPLE_SPREADSHEET_ID = '1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms'

スプレッドシートの ID を指定しています。

ID は スプレッドシートの URL を見ていただて、確認することもできます。

https://docs.google.com/spreadsheets/d/[スプレッドシートのID]/edit#gid=0

また、スプレッドシートの全情報を取得すれば、確認することが可能です。

quickstart.py では読み込み専用になっていますので、

# 変更前
SCOPES = ['https://www.googleapis.com/auth/spreadsheets.readonly']

# 変更後
SCOPES = ['https://www.googleapis.com/auth/spreadsheets']

のように変更が必要になります。

感想

今回、pythonGoogle スプレッドシート の情報を取得についてまとめてみました。

GoogleSheetAPI を利用すれば、スプレッドシートへの書き込みやシートの削除や編集、グラフの作成なども行うことができます。

pythonスプレッドシートにレポートを自動生成することもできます。

少しずつ慣れて、ルーティン的な作業は自動化していきたいですね。

スプレッドシートの操作や書き込みについてもまとめていきます。

ではでは、また次回。

本紹介「論理的思考と交渉のスキル」

どうも、nippa です。

エンジニアをやっているとどうしてもクライアントとの仕様や工数で、主張のすり合わせが発生します。

双方にとって良い交渉にするために、交渉をどのように行えばよいのか、考慮するべき点はどこなのかを全般的に学ぼうと思い、

論理的思考と交渉のスキル 著者:高杉 尚孝Amazon リンク)」を読んでみました。

2003 年に出版されており、毎年増刷されていた本です。

著者について

この本の読み方

冒頭の方で述べられていますが、この本は交渉の指南書という立て付けになります。

そのため最初から最後まで通読するというよりも、「交渉」というものに対して、自分が足りない部分、現在問題になっている箇所を把握して、そのトピックに関する部分を読むような形をおすすめします。

指南書のため通読すると

あれもこれも・・・となり、読み終えた頃にはほとんど身につかなかった。

というこになりかねません。

また、各章末に章のまとめがありますので、そちらに目を通してから章を読むと理解しやすいと思います。

学べる内容

簡単にまとめると以下のような内容を学ぶことができます。

  • 良い交渉の定義
  • 交渉に必要な論理的な考え方
  • 交渉用の文章の書き方
  • 交渉の準備をするにあたり必要なもの
  • 悪徳交渉に出くわしたときの対処
  • 交渉をうまく行うための振るい舞・心構え
  • 交渉での相手の心理

交渉での心理(8章)はとても興味深い内容でした。

感想

エンジニアといえど、日頃から仕様や要件の交渉、トラブル発生時の今後の対応など、意外とクライアントと交渉するタイミングが多いです。

特にプロジェクトマネージャーやチームリーダーの立場を任されるようなときは必須のスキルになると思います。

そういったときに、交渉がどうあるか知っているだけでも対応が全くかわってくると思います。

フリーランスであれば、契約交渉の機会もありますので、そういった場面でも使えるスキルになります。

日本人は交渉が下手と言われがちですが、訓練すればどうとでもなるものだと思います。

ぜひ読んでみてはいかがでしょうか。

ではでは、また次回。

商品ページはこちら:

論理的思考と交渉のスキル 著者:高杉 尚孝Amazon リンク)

python PyArmorでコードの難読化

どうも、nippa です。

python cryptography で暗号化についてまとめましたが、key をどのように保存するかについて考えていました。

セキュリティ的に可能な方法としては、

  1. 実行サーバとは別のサーバに保存
  2. API
  3. key 自体を難読化

1.と 2. は key を物理的に別で保存する方法になります。

物理的に別で保存できない場合は、key を難読化するしかないのかもしれません。

他に方法があれば、教えてもらいところですね。

今回は 3.について python のコード自体を難読化して key を保存を考えてみます。

python のコードの難読化には pyarmor ライブラリを使ってみます。

環境

PyArmor のインストール

PyArmor は pip インストール

$pip install pyarmor

pyarmor でコードの難読化

サンプルとして、以下のソースコードを難読化させてみたいと思います。

hello.py

def hello():
     print('Hello world!')


def sum(a, b):
     return a+b

pyarmor で pythonソースコードを難読なライブラリ化します。

$pyarmor obfuscate hello.py

$ls
# 出力結果
dist/     hello.py

distディレクトリが生成され、難読化されたコードが dist 配下に生成されます。

$ls dist/*

# 出力結果
dist/hello.py

dist/pytransform:
__init__.py         _pytransform.dylib*

これらのファイルはランタイムファイルと呼ばれます。

  • dist/hello.py:難読化された python コード
  • dist/pytransform/pytransform.py:実行時に使用されるダイナミックライブラリ

になります。dist/hello.pyを難読化する前を同様に読み込むことで実行できます。

dist/hello.pyの中身は、以下のようになっており、難読化されていることがわかります。

from pytransform import pyarmor_runtime
pyarmor_runtime()
__pyarmor__(__name__, __file__, b'\x50...\x4f/', 2)

難読化コードの実行

難読化されたコードの実行は、難読化前のコード同じように読み込み実行可能です。

難読化前のhello.py を実行するためのコードとして、以下を利用します。

run.py

import hello

hello.hello()
print(hello.sum(1, 1))

実行して、結果を確認してみます。

$python run.py

# 出力
Hello world!
2

難読化後のコードを読み込んで実行してみます。

run.pyを以下のように変更します。

from .dist import hello

hello.hello()
print(hello.sum(1, 1))

難読化されたコードdist/hello.pyの import のパスの修正をします。

- from pytransform import pyarmor_runtime
+ from .pytransform import pyarmor_runtime

これでrun.pyを実行して結果を確認します。

$python run.py

# 出力
Hello world!
2

難読化されたライブラリを読み込むことができます。

ライセンス期限の設定

pyarmor で licence を作成して、それを使って難読化することで、ソースコードに使用期限を設定することが可能です。

$pyarmor licenses --expired 2021-01-31 r001

コマンドを実行するとlicensesディレクトリが作成されます。

$ls -R licenses

#出力
r001/

licenses/r001:
license.lic      license.lic.txt

生成されるファイルの詳細は以下の通りです。

  • licence.lic: ライセンスファイル
  • license.lic.txt: ファイルの詳細

このlicence.licを pyarmor 実行時にオプションで読むことで、ライセンスの有効期限を設定することが可能なります。

ちなみに、指定しない場合(デフォルト)ではライセンスの期限が無期限になります。

ライセンスの指定オプションは以下の通りです。

$pyarmor obfuscate --with-license licenses/r001/license.lic hello.py

これで難読化のコードにライセンスの有効期限を設定することが可能です。

感想

key を難読化させることで多少なり key のセキュリティを上げるために、pyaromr ライブラリを使ってコードの難読化をしてみました。

意外と簡単に難読化でき、さらにはライセンスの有効期限も設定できました。

key 自体は別サーバにおいて都度、取得する方法のが良いのですがどうしてもという場合に使えるかと思います。

単に、ソースコードを難読化するためでも良いのかと思いました。

pyaromr を使えば、簡単なライセンス管理が可能になりますね。

ではでは、また次回。

本紹介「コンサルタントの読書術 確実に成果につながる戦略的読書のススメ」

どうも、nippa です。

今回は本の読み方を学ぼうと思い手にとった一冊です。

一般的に仕事量が3倍と言われるコンサルタントの方がどのように本を読むのかを知りたいと思い、「コンサルタントの読書術 確実に成果につながる戦略的読書のススメ 著者:大石哲之Amazon リンク)」を読んでみました。

速読するわけでも、熟読でもない本の読み方に関してです。

この本の読み方

この本の著者の別の本を読んだことがあります。

物理的な読み方的は、同じです。

この本を読むと以下のように重要度を文字、行間で以下のような表現をしています。

  • 文字サイズ大(要点)
  • 太文字・行間を広くとる(結論・筆者の言いたいことなど)
  • 普通文字(補足・例など)

なので、以下のような読み方をしました。

  1. 文字サイズが大きい文章を読む
  2. その周辺の太文字や行間が広い部分を読む
  3. 2 で理解できなければ、普通の文字部分を読む
  4. 次の節に進み、1-3 を繰り返す

Web 検索をイメージした読み方で、必要な部分だけを読み取る読み方です。

ビジネス本は自分が持っていない情報を得る本であり、イチからすべてを読む必要はないと考えて、必要な部分を選別して、情報収集しました。

学べる・書かれている内容

コンサルタントの仕事視点から著者の本の選び方のコツ・選んだ本の読み方を知ることができます。

この2つの点について書かれているのですが、その前提にあるのが、

「どうしてこの本を読むのか」を考えることです。

仕事のためなので時間が限られていることがほとんどです。

そのため、「何を目的」として本を読むかを考えることが重要であり、目的の設定の仕方をコンサルタント視点で教えてくれます。

仕事のための本の選びのポイントとして、以下のようなことを取り上げてあります。

  • 奥付
  • 著者のプロフィール
  • 翻訳本かどうか

また、本を以下の 4 種類に分類し、どの分類をどの目的で読むかが著者視点で書かれてています。

本を読む行動をコンサルタントの業界では基本のロジカルシンキングで読むことを薦めています。

コンサルタントの仕事の仕方のように本を読むことで、本からより効率よく情報を収集する方法が書かれています。

感想

人の心理とは不思議なもので、2000 円の本を買ったときに、2000 円分の価値がある情報がそこには書かれていると思いがちです。

そのため、2000 円分の価値を見つけ出そうとしてしまいます。

私自身もそうですが、その心理が本を読むこと自体を億劫にしたり、時間をかけさせることに気づきました。

また、「本を読む」行為自体を効率よくするためには、「目的に合わせて、戦略的に本を選び・読む」ことを意識して今後、ビジネス本は読んでいきたと思います。

大事なことは、「なんのために本を読むか」です!

本を読んでも、内容が身につかないと悩んでいる方は、ぜひ読んでみてはいかかがでしょうか。

ではでは、また次回。

商品ページはこちら: コンサル一年目が学ぶこと 著者:大石哲之