技術雑記帳兼日記帳

AWS、Python、Terraformの使い方をコッソリ

AWS 認定 クラウドプラクティショナー受験記録

はじめに

5月8日にAWS 認定 クラウドラクティショナーを受験してきました。  

試験までの流れ

1.試験前

きっかけは実務でAWSも触ってるし、説明するときの根拠付もあったほうがいいかなぁと思って以下の本を購入して勉強を開始しました。
勉強方法は「古典的なノートに書き写す」+「音読する」でやってました。

1冊目:

2冊目:

1冊目はAWSとは?クラウドとは?AWSのサービスや監視、課金方式や課金の確認方法などの幅広い範囲で図解付きで丁寧に説明してくれていたので良書でした。
最初は読むだけ読んで2冊目の問題集を説いていました。
問題集の正解と誤りの訂正箇所をセブンイレブンで売っているA5ノートにまとめていました。
それも飽きてきて、1冊目の本の内容をノートにまとめていました。
ちなみに2冊目はKndle Unlimitedに入っているおかげで読み放題。

期間的には平日は読むくらいに留めていましたが、GW中にガッツリ勉強してました。

2.試験当日

一夜漬け+当日もギリギリまで勉強していざ試験会場へ。
10年ぶりくらいに試験に行ったので謎に緊張しました。

試験会場では、ナイスミドルの案内で身分証明書(マイナンバーカード+クレジットカード)を提示して同意書に記入しました。
そのあと顔写真を撮って、身分証明書(マイナンバーカード)のみをポケットにいれて、スマホの電源を切って時計を外して、ロッカーに預けました。

ちなみに身分証明書は片方の名前がローマ字で書いてなくても大丈夫でした。

3.試験開始

試験会場に入る前にメモ用のボードとペンを借りました。
座席に案内されて身分証明書は机の上においておくよう指示され、備え付けのPCを設定してもらって試験を実施します。
そして、いざテスト開始ですが特に書くことはなく単純に問題を解くだけでした。
なお、騒音対策でイヤーマフが備え付けられていました。

4.試験終了

RTAしたわけではないですが、1時間以上の持ち時間を余らせて終わらせました。
本に書いていないサービスが頻繁に出てきたので、落ちたかなぁと思っていたらノーモーションで「合格」の文字が出てきて焦りつつ、席に備え付けらているボタンを押して退出。
AWSの試験はPCでは合格とでますが、結果レポートには審査は後日と記載されます。

後日とありましたが、実際は3時間位で結果レポートをもらえました。
また、特典などもすぐに利用できました。
PDF 証明書も貰えます。

5.振り返り

ギリギリまで勉強していましたが、本の内容をまとめるのは6割くらいしかできてませんでした。
次の上位を取るにあたっては、ページ数から時間を見積もってやるのがいいですね。(当たり前笑)

結果的に合格できたので良かったです。

次はデベロッパーかなぁ

python スクレイピング その3

はじめに

今回はYahoo画像検索で猫の画像をかき集めて保存するプログラムを書いてみた。

準備

  • imageDownload.py
import requests, os, json, traceback
from bs4 import BeautifulSoup

path =  './img-cat/'
maxPage = 2
searchText = '猫'

def imageDownload(searchWord, index):
    url = 'https://search.yahoo.co.jp/image/search?p={searchWord}&ei=UTF-8&b={index}'
    resp = requests.get(url.format(searchWord=searchWord, index=index))
    soup = BeautifulSoup(resp.content, 'html.parser')

    #分析
    script = soup.find("script", attrs={"id": "__NEXT_DATA__"})

     # タグの内容を取り出してJSON変換
     # <script>なので中身はstringで取るみたい。
    scriptJson = json.loads(script.string)
    imageUrlList = []
    for algos in scriptJson['props']['initialProps']['pageProps']['algos']:
        imageUrlList.append(algos['main']['url'])

    #画像取得
    imageObjectList = []
    for imageUrl in imageUrlList:
        resp = requests.get(imageUrl)
        imageObjectList.append(resp.content)
    
    #画像リスト返却
    return imageObjectList

def imageWrite(imageList):
    for i, image in enumerate(imageList):
        fileName = path + 'img' + '{:04}'.format(i+1) + '.jpg'
        with open(fileName, 'wb') as saveImage:
            saveImage.write(image)

    return

if __name__ == '__main__':

    try:
        if os.path.exists(path) != True:
            os.mkdir(path)

        imageList = []
        # Page * 20ループで画像取得
        for i in range(int(maxPage)):
            #画像収集
            index = (i * 20) + 1
            imageList.extend(imageDownload(searchText, index))

        #画像書き込み
        imageWrite(imageList)

    except Exception as e:
        print(e)
        print(traceback.format_exc())
  • 実行方法と結果
$ python imageDownload.py 
$ ls img-cat/
img0001.jpg  img0003.jpg  img0005.jpg  img0007.jpg  img0009.jpg  img0011.jpg  img0013.jpg
:
  • 簡単な解説

Yahoo画像検索が1ページに付き20枚画像が取れる。
それを前提に以下で20ずつindexを勧めて画像を取得してリストに追加している。
リストにリストを追加する処理はextend(appendでやって1敗)

        # Page * 20ループで画像取得
        for i in range(int(maxPage)):
            #画像収集
            index = (i * 20) + 1
            imageList.extend(imageDownload(searchText, index))

ここでリストを全部渡して、カレントの下のディレクトリにファイルに出力している。

        #画像書き込み
        imageWrite(imageList)
  • 関数の解説

以下の処理でリクエストを投げて、結果を受け取っている。
特筆すべきはscriptにJSONでURLなどを保持しているところ。

def imageDownload(searchWord, index):
    url = 'https://search.yahoo.co.jp/image/search?p={searchWord}&ei=UTF-8&b={index}'
    resp = requests.get(url.format(searchWord=searchWord, index=index))
    soup = BeautifulSoup(resp.content, 'html.parser')

    #分析
    script = soup.find("script", attrs={"id": "__NEXT_DATA__"})

あとは、JSONを分析+URLのリストを作って画像をダウンロードしてimageObjectListに保存している。

    scriptJson = json.loads(script.string)
    imageUrlList = []
    for algos in scriptJson['props']['initialProps']['pageProps']['algos']:
        imageUrlList.append(algos['main']['url'])

    #画像取得
    imageObjectList = []
    for imageUrl in imageUrlList:
        resp = requests.get(imageUrl)
        imageObjectList.append(resp.content)
    
    #画像リスト返却
    return imageObjectList

imageWriteはリストを吐き出しているだけなので省略


まとめ

スクレイピングをやっていると、どんどんこれやっていいのかってなってくるので方向性がぶれてくる。
だけど、やりたいことはできたので良しとする。



python スクレイピング その2

はじめに

前回の続きでスクレイピングについて書いていく。

準備

これまた本通りだと芸がないので、はてなブログの「注目」のタイトルとURLを抽出してCSVに出力する処理を作成した。

  • entryTitle.py
import requests
from bs4 import BeautifulSoup
import csv

url = 'https://hatenablog.com/'

resp = requests.get(url)
soup = BeautifulSoup(resp.content, 'html.parser')
# <class 'bs4.element.Tag'>
serviceTopRecommendList = soup.find("div", attrs={"class": "serviceTop-recommend-list"})

# <class 'bs4.element.ResultSet'>
entryTitleList = serviceTopRecommendList.find_all("h3", attrs={"class": "entry-title"})

entryTitleCsvList = []

for i, entryTitle in enumerate(entryTitleList):
    # <class 'bs4.element.Tag'>
    entryTitleCsvList.append([i + 1, entryTitle.find("a").get_text(), entryTitle.find("a").get("href")])

with open("entryTitleCsvList.csv", "w") as file:
    writer = csv.writer(file, lineterminator='\n')
    writer.writerows(entryTitleCsvList)
  • 実行方法と結果
$ python entryTitle.py 
$ cat entryTitleCsvList.csv
1,ぼのこと女社会2【第92-1】,https://www.bonogura.com/entry/bonoko-onnasyakai2-92-1
2,「はてなブックマーク」からいくらなんでも人が減りすぎではないかという話,https://www.tyoshiki.com/entry/2021/05/05/224428
3,FLoCとはなにか,https://jovi0608.hatenablog.com/entry/2021/05/06/160046
4,子の泣いてる時間を観察したくてM5StickCで泣き声モニタを作った,https://blog.sushi.money/entry/2021/05/06/100840
5,制作開放席システムは人生を狂わせる。,http://161cm910kg.hatenablog.com/entry/2021/05/05/205408
6,その粉、まさにメイクアップフォーエバー。【ウルトラHDセッティングパウダー】,https://www.konataro.blog/entry/2021/05/06/190000
7,JAPAN JAM終了後にテレビ局のインタビューに答えたけど、印象操作する偏った報道をされた件について,https://www.ongakunojouhou.com/entry/2021/05/06/125604
8,弱者男性論者を見ていると、「社会適応という名の悪」に対してあまりにも潔癖すぎると強く感じてしまう,https://ta-nishi.hatenablog.com/entry/2021/05/05/155031
9,フロントエンドのパフォーマンスチューニングを俯瞰する,https://numb86-tech.hatenablog.com/entry/2021/05/05/224611

  • 簡単な解説

divタグでclassがserviceTop-recommend-listの要素を取り出す。
これが、注目のClassのよう。

serviceTopRecommendList = soup.find("div", attrs={"class": "serviceTop-recommend-list"})

取得したserviceTopRecommendListの中データから、h3タグで、classがentry-titleの要素を取得する。

entryTitleList = serviceTopRecommendList.find_all("h3", attrs={"class": "entry-title"})

最後にentryTitleListのenumerateで回して、indexと要素を設定する。
そのあと、リストにインデックス値とaタグの内容、aタグのhrefを取り出して設定する。
あとはそのままCSVに吐き出す。

for i, entryTitle in enumerate(entryTitleList):
    # <class 'bs4.element.ResultSet'>
    entryTitleCsvList.append([i + 1, entryTitle.find("a").get_text(), entryTitle.find("a").get("href")])

with open("entryTitleCsvList.csv", "w") as file:
    writer = csv.writer(file, lineterminator='\n')
    writer.writerows(entryTitleCsvList)

enumerate便利


まとめ

言葉遣いが難しい。要素なのか?データなのか?このあたりはもう少し勉強が必要かな。
あとは、<class 'bs4.element.ResultSet'><class 'bs4.element.Tag'>の関係がイマイチ読み解けなかったな。
メソッドに応じてどちらが取れるかを把握しとけば役に立ちそうだ。

それにしても、プロのHTMLだからすごくキレイに作られているな。ちょっと感動。



python スクレイピング その1

はじめに

この本を買ったので、学習成果をまとめていく。

準備

スクレイピングWikipediaの「今日は何の日」を取得するんだけど芸がないので、「新しい記事」のリンクのタイトルをすべて取得してみる。

  • newArticles.py
import requests
from bs4 import BeautifulSoup

url = 'https://ja.wikipedia.org/'

resp = requests.get(url)
soup = BeautifulSoup(resp.content, 'html.parser')
new_articles = soup.find("div", attrs={"id": "new_articles"})
links = new_articles.find_all('a')

for link in links:
    print(link.get('title'))
  • 実行方法と結果
$ python newArticles.py 
特別:新しいページ
タチジャコウソウ
シソ科
イブキジャコウソウ属
多年生植物
ハーブ
香辛料
和名
麝香
衝動買い
ブランド
ヨーゼフ・メルク
17951181852616日
ウィーン
チェリスト
ウィーン国立歌劇場
チェロ
ウィーン国立音楽大学
ギター
ヴァイオリン
フランシス・グレスナー・リー
18783251962127日
アメリカ合衆国
法科学
1/12スケール (存在しないページ)
ドールハウス
ジオラマ
Wikipedia:メインページ新着投票所
Wikipedia:月間新記事賞
  • 簡単な解説
resp = requests.get(url)
soup = BeautifulSoup(resp.content, 'html.parser')

ここでリクエストを投げて、取得したレスポンスをBeautifulSoupでhtml.parserする。

new_articles = soup.find("div", attrs={"id": "new_articles"})
links = new_articles.find_all('a')

div要素でIDがnew_articlesの要素を取り出して、a Tagの要素(hrefやtitle)を取り出す。

for link in links:
    print(link.get('title'))

取得したlinkの要素titleをgetメソッドで取得する。


まとめ

find_allタグ全体とって、要素をgetメソッドで取るのかなぁ?
何にしてもスクレイピングは以外と面白いな。



python Amazon Rekognition Detect Text

はじめに

今回は画像からテキストを分析するDetect Textを使ってみる。

準備

下記のプログラムを用意する。

  • detect_text.py.py
from PIL import Image, ImageDraw, ImageFont
import boto3, sys, json, os, traceback

#画像の分析結果を返す
def detect_text(image):
    client=boto3.client('rekognition')
    #写真を読み出して、Byte変換してdetect_faces送信
    file = open(image,'rb')
    response = client.detect_text(Image={'Bytes':file.read()})

    return response

#BoundingBoxを設定する
def set_bounding_box(image, bounding_box_data):
    #画像の高さと幅を取得
    imgWidth, imgHeight = image.size
    draw = ImageDraw.Draw(image)

    #位置を算出
    left = bounding_box_data['Left'] * imgWidth
    top = bounding_box_data['Top'] * imgHeight
    width = bounding_box_data['Width'] * imgWidth
    height = bounding_box_data['Height'] * imgHeight

    points = (
            (left,top),
            (left + width, top),
            (left + width, top + height),
            (left , top + height),
            (left, top)

        )

    draw.line(points, fill='#00d400', width=2)
    
    return

#指定箇所に文字列を設定して返す
def set_bounding_box_text(image, text, bounding_box_data):

    #画像の高さと幅を取得
    imgWidth, imgHeight = image.size
    draw = ImageDraw.Draw(image)

    #位置を算出
    left = bounding_box_data['Left'] * imgWidth
    top = bounding_box_data['Top'] * imgHeight
    width = bounding_box_data['Width'] * imgWidth
    height = bounding_box_data['Height'] * imgHeight

    draw = ImageDraw.Draw(image)
    #フォントの設定
    font_ttf = "/usr/share/fonts/truetype/fonts-japanese-gothic.ttf"
    draw.font = ImageFont.truetype(font_ttf, 25)

    color = (0,255,0)
    pos = (left, top)
    #文字の設定
    draw.text(pos, text, color)
    return

if __name__ == '__main__':
    if len(sys.argv) != 3:
        exit()
    
    in_file_name = sys.argv[1]
    out_file_name = sys.argv[2]

    try:
        #画像分析
        #jsonが無ければ分析あれば使う
        json_file_name = in_file_name + '.json'
        if (os.path.exists(json_file_name) == True):
            file = open(json_file_name, 'r')
            response = file.read()
            response = json.loads(response)
        else:
            response = detect_text(in_file_name)
            file = open(json_file_name, 'w')
            file.write(json.dumps(response))

        #分析元の画像を読み込み
        image = Image.open(in_file_name)
        
        #画像に分析結果の設定
        cnt = 1
        for text in response['TextDetections']:
            #boundingboxを設定
            set_bounding_box(image, text['Geometry']['BoundingBox'])
            set_bounding_box_text(image, str(cnt), text['Geometry']['BoundingBox'])
            print(str(cnt) + ' is ' + 'Type:' + text['Type'] + ' [' + text['DetectedText'] + ']')
            cnt = cnt + 1

        #結果の出力
        image.save(out_file_name)


    except Exception as e:
        print(e)
        print(traceback.format_exc())

実行方法

python detect_text.py 分析したいファイル.jpg 出力したいファイル名.jpg
  • 実行結果
    今回は何枚か画像を貼り付けてみる
    数字がかぶって見づらいけど画像に数字を埋め込んで、ターミナルに数字と文字タイプ、文字列を表示するようにした。


1個めはIRON MAIDENのアルバムジャケット

f:id:halhalhal1:20210503101313j:plain

1 is Type:LINE [IRAN MAAIDEN]
2 is Type:LINE [Kllers]
3 is Type:WORD [IRAN]
4 is Type:WORD [MAAIDEN]
5 is Type:WORD [Kllers]

2個めはNIRVANAのアルバムジャケット
f:id:halhalhal1:20210503101603j:plain

1 is Type:LINE [NIRVANA]
2 is Type:LINE ["BLEACH'']
3 is Type:WORD [NIRVANA]
4 is Type:WORD ["BLEACH'']

3個めはネコは見ている系の寄せ集め
f:id:halhalhal1:20210503101825j:plain

1 is Type:LINE [7IL71]
2 is Type:LINE [HOMLSI]
:
48 is Type:WORD [LT ]
49 is Type:WORD [t]
50 is Type:WORD [OHOEN'OCFLS]
51 is Type:WORD [K]

まとめ

ラストが若干狂気じみているが、これはdetect textが日本語に対応していないからっぽい。
崩し文字は、そのままそれっぽく見えるアルファベットに変換してくれる。
NIRVANA」や「BLEACH」はさすがの検出力。



python pillow 色々な画像変換

はじめに

今回はpillowを使って色々な画像変換を試してみる。

準備

下記のプログラムを用意する。

  • convert.py
from PIL import Image, ImageOps
import sys

if len(sys.argv) != 2:
    exit()

#画像をsampleを開く
inFileName = sys.argv[1]
outFileName = 'out' + sys.argv[1] 
im = Image.open(inFileName)

# グレースケール
gray = im.convert('L')
gray.save('00'+'_gray_'+outFileName)

# ネガポジ
inve = im.convert('RGB')
inve = ImageOps.invert(inve)
inve.save('01'+'_invert1st_'+outFileName)

# ネガポジ戻し
inve = ImageOps.invert(inve)
inve.save('01'+'_invert2nd_'+outFileName)


# モノクロ
mono = im.convert(mode="1") 
mono.save('02'+'_mono_'+outFileName)

実行方法

python convert.py 画像.jpg

実行結果
グレイ変換
f:id:halhalhal1:20210501095611j:plain

ネガポジ変換
f:id:halhalhal1:20210501095731j:plain

ネガポジ変換戻し
f:id:halhalhal1:20210501095748j:plain

モノクロ変換
f:id:halhalhal1:20210501095804j:plain


まとめ

使いでが難しそうだけど、使いこなせれば画像解析とかに役立てるのかな?



python pillow 色々なメソッド

はじめに

今回はpillowを使って線や四角形などを描画してみる。

準備

下記のプログラムを用意する。

  • pil.py
from PIL import Image, ImageDraw

#640x480の黒い画像を準備 
im = Image.new('RGB', (640, 480), (0, 0, 0))
draw = ImageDraw.Draw(im)

#丸四角の線の色
outLineColor = (255, 255, 255)

#丸四角の座標値設定
#((左上のx座標, 左上のy座標), (右下のx座標, 右下のy座標))
#(左上のx座標, 左上のy座標, 右下のx座標, 右下のy座標)
#丸の描画
draw.ellipse((50, 50, 150, 150), fill=(255, 0, 0), outline=outLineColor)
#四角の描画
draw.rectangle((200, 100, 300, 200), fill=(0, 255, 0), outline=outLineColor)

#線の座標値設定
#(x1, y1, x2, y2, x3, y3...)
#((x1, y1), (x2, y2), (x3, y3)...)
#線の描画
#draw.line(((350, 100), (450, 250), (500, 100), (350, 200), (350, 100)), fill=(255, 255, 0), width=3)
linePoints = (
    (350, 100), (450, 250), (500, 100), 
    (350, 200), (350, 100)    
)
draw.line(linePoints, fill=(255, 255, 0), width=3)

#多角形の描画
polygonPoints = (
    (550, 200), (450, 350), (500, 200),
    (550, 300), (250, 200)    
)
draw.polygon(polygonPoints, fill=(0, 0, 255),outline=outLineColor)

#点の描画
points = (
    (250, 400), (250, 450), (300, 450),
    (350, 400), (400, 400)    
)
draw.point(points, fill=(0, 255, 255))

#保存しておく
im.save('image.png')

#めんどくさいから表示させる
im.show()

実行方法

python pil.py
  • 実行結果

f:id:halhalhal1:20210430115206p:plain

ごちゃごちゃしているがちゃんと表示された
pointは点なので分かりづらいがちゃんと表示されている


まとめ

Pillowのほうが直感的に使いやす印象がある。
グレー変換とかも挑戦してみようと思う。