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 特別:新しいページ タチジャコウソウ シソ科 イブキジャコウソウ属 多年生植物 ハーブ 香辛料 和名 麝香 衝動買い ブランド ヨーゼフ・メルク 1795年 1月18日 1852年 6月16日 ウィーン チェリスト ウィーン国立歌劇場 チェロ ウィーン国立音楽大学 ギター ヴァイオリン フランシス・グレスナー・リー 1878年 3月25日 1962年 1月27日 アメリカ合衆国 法科学 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のアルバムジャケット
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のアルバムジャケット
1 is Type:LINE [NIRVANA] 2 is Type:LINE ["BLEACH''] 3 is Type:WORD [NIRVANA] 4 is Type:WORD ["BLEACH'']
3個めはネコは見ている系の寄せ集め
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
実行結果
グレイ変換
ネガポジ変換
ネガポジ変換戻し
モノクロ変換
まとめ
使いでが難しそうだけど、使いこなせれば画像解析とかに役立てるのかな?
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
- 実行結果
ごちゃごちゃしているがちゃんと表示された
pointは点なので分かりづらいがちゃんと表示されている
まとめ
Pillowのほうが直感的に使いやす印象がある。
グレー変換とかも挑戦してみようと思う。
python pillow Image
はじめに
今回はdetect_facesのBounding Boxとテキストをpillowに置き換えてみる。
※写真はAIで生成したものらしいです。
準備
先にpillowをインストールする。
pip install pillow
下記のプログラムを用意する。
- detect_faces_pillow.py
from PIL import Image, ImageDraw, ImageFont import boto3, sys, json, os, traceback #detect_facesで顔の分析結果を返す def detect_faces(image): client=boto3.client('rekognition') #写真を読み出して、Byte変換してdetect_faces送信 file = open(image,'rb') response = client.detect_faces(Image={'Bytes':file.read()},Attributes=['ALL']) 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 #指定箇所にtextを設定する def set_text_image(image, text, pos): 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) #文字の吐き出し 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_faces(in_file_name) file = open(json_file_name, 'w') file.write(json.dumps(response)) #分析元の画像を読み込み image = Image.open(in_file_name) #画像に分析結果の設定(複数人できるが今回は一人だけ) for faceDetail in response['FaceDetails']: #boundingboxを設定 text = '対象の年齢は'+ str(faceDetail['AgeRange']['Low']) + 'から' + str(faceDetail['AgeRange']['High']) + '歳です。' set_bounding_box(image, faceDetail['BoundingBox']) set_text_image(image, text, (0,0)) break #結果の出力 image.save(out_file_name) except Exception as e: print(e) print(traceback.format_exc())
実行方法
python detect_faces_pillow.py 分析したいファイル.jpg 出力したいファイル名.jpg
- 実行結果
BoundingBoxもちゃんと表示され、テキストも日本語で表示されている。
まとめ
Pillowのほうがフォントがボヤボヤしている気がするけど、線はきれい感じがする。
使いでとしては、簡易なCV2と行った感じなのかな?
python Amazon Rekognition Recognize Celebrities
はじめに
今回は有名人の顔を分析するRecognize Celebritiesを使ってみる。
準備
下記のプログラムを用意する。
- recognize_celebrities.py
import boto3, sys, json, cv2, math, os, traceback #recognize_celebritiesで顔の分析結果を返す def recognize_celebrities(in_image_file): client=boto3.client('rekognition') #写真を読み出して、Byte変換してdetect_faces送信 file = open(in_image_file,'rb') response = client.recognize_celebrities(Image={'Bytes':file.read()}) return response #Bounding Boxを設定して返す def set_bounding_box(image_file, bounding_box_data): #画像の高さと幅を取得 imgHeight, imgWidth = image_file.shape[:2] #位置を算出 left = math.ceil(bounding_box_data['Left'] * imgWidth) top = math.ceil(bounding_box_data['Top'] * imgHeight) width = math.ceil(bounding_box_data['Width'] * imgWidth) height = math.ceil(bounding_box_data['Height'] * imgHeight) image_file = cv2.rectangle(image_file , (left, top) , (width+left, height+top) , (0,255,0) , 2) return image_file #Bounding Boxの左下に名前を設定して返す def set_celebrity_name(image_file, celebrity_name, boundingBox): #画像の高さと幅を取得 imgHeight, imgWidth = image_file.shape[:2] left = math.ceil(boundingBox['Left'] * imgWidth) top = math.ceil(boundingBox['Top'] * imgHeight) height = math.ceil(boundingBox['Height'] * imgHeight) image_file = cv2.putText(image_file , celebrity_name , (left, height+top) , cv2.FONT_HERSHEY_PLAIN , 2 , (255, 255, 255) , 2 , cv2.LINE_AA) return image_file 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 = recognize_celebrities(in_file_name) file = open(json_file_name, 'w') file.write(json.dumps(response)) #分析元の画像を読み込み origin_image = cv2.imread(in_file_name) after_image = origin_image.copy() #画像に分析結果の設定 for celebrity in response['CelebrityFaces']: after_image = set_bounding_box(after_image, celebrity['Face']['BoundingBox']) after_image = set_celebrity_name(after_image, celebrity['Name'], celebrity['Face']['BoundingBox']) #結果の出力 if after_image is not None: cv2.imwrite(out_file_name, after_image) except Exception as e: print(e) print(traceback.format_exc())
実行方法
python recognize_celebrities.py 分析したいファイル.jpg 出力したいファイル名.jpg
- 実行結果
BoundingBoxを設定して、名前を設定してみた。
動作はほぼ共通化していて、流用が簡単にできるのでAmazonのAPIが共通的に作られているかがわかった。
やっぱ、似たようなAPIは似たような構造になるんだよな、普通。
まとめ
今までの集大成で一気に書き上げることができた。
text設定とかはもうちょっとうまくメソッド化できそうだなぁ。
python cv2
cv2のputTextは残念ながら日本語が使えないようだ。 PILのImageDraw.textは使えるみたい。
PILの使い方も覚えて置き換えるのも良さそうだな