Webサイトからのデータ取得 ①Google系Webサービスのデータ取得(サイト検索・画像検索・Youtube検索)
やりたいこと
pythonで下記のGoogle系Webサービスの結果を自動取得する
Gooogle検索 (キーワードにヒットした検索結果のタイトル、リンク一覧)
Google画像検索 (キーワードにヒットした検索結果の画像ファイル)
Youtube動画検索 (キーワードにヒットした検索結果の動画ファイル)
Google検索(キーワードにヒットした検索結果のタイトル、リンク一覧)
実装手順
①requestsライブラリでgoogleに検索を要求し、結果を取得
②Beautifulsoupライブラリでタイトル・リンクを抽出
③日本語エンコード変換に注意しつつ結果をpandas dataframeに保存
※検索結果の説明文も取得することは可能だが、タイトルと紐づけて取得するのが難しかった (リンクだけ表示されるものがある)ので省略
def Get_GoogleWebSearch_Result(self,keyword,num=100): ''' GoogleWeb検索結果と説明文の取得 ''' result_df = pd.DataFrame(columns=['Title','Link'] ) title_list = [] link_list = [] print("Loading...") res = requests.get("https://google.com/search?num="+str(num)+"&q=" + " ".join(keyword)) res.encoding = res.apparent_encoding res.raise_for_status() # 上位の検索結果のリンクを取得する soup = BeautifulSoup(res.content, "lxml") link_elems = soup.select('.r > a') #タイトル・リンク link_elems2 = soup.select('.s > .st') #説明文 (タイトル・リンクと一緒に表示させたかったがずれるので取得のみ) # 各結果をブラウザのタブで開く num_open = min(100, len(link_elems2)) for i in range(num_open): tex_temp = link_elems[i].get_text() #タイトル文字列の処理 try: print(tex_temp) except: #機種依存文字を含む場合はエンコード可能な文字だけを出力 tex_temp = tex_temp.encode('cp932',"ignore") tex_temp = tex_temp.decode('cp932') print(tex_temp) link_temp = "https://google.com" + link_elems[i].get("href") #結果への追加 title_list.append(tex_temp) link_list.append(link_temp) #tex_temp2 = link_elems2[i].get_text() #説明文の保存 (タイトル・リンクと一緒に表示させたかったがずれるので取得のみ) #try: # print(tex_temp2) #except: #機種依存文字を含む場合はエンコード可能な文字だけを出力 # tex_temp2 = tex_temp2.encode('cp932',"ignore") # tex_temp2 = tex_temp2.decode('cp932') # print(tex_temp2) #webbrowser.open("https://google.com" + link_elems[i].get("href")) result_df['Title'] = pd.Series(title_list) result_df['Link'] = pd.Series(link_list) return result_df
Google画像検索 (キーワードにヒットした検索結果の画像ファイル)
実装手順
①画像保存先ディレクトリの存在を確認し、すでにある場合はツリーごと削除(自動でリネーム保存されるため)
②google_images_downloadライブラリで画像検索結果をフォルダに保存
def Get_GoogleImageSearch_Result(self,keyword,imnum=100): ''' Google画像検索結果の取得 (取得した画像は実行ファイルと同じ階層のdownloadフォルダに検索ワードのフォルダを作って保存) ''' imnum = int(min(99,imnum)) #100以上の場合はchrome driverの設定が必要 target_dir =os.path.dirname(os.path.abspath(__file__))+"/downloads/"+keyword if os.path.exists(target_dir): shutil.rmtree(target_dir) response = google_images_download.googleimagesdownload() arguments = {"keywords":keyword,"limit":imnum,"la":"Japanese","pr":"test"} #creating list of arguments response.download(arguments) return
Youtube動画検索 (キーワードにヒットした検索結果の動画ファイル)
実装手順
①requestsライブラリでYoutubeに検索を要求し、結果を取得
②Beautifulsoupライブラリでタイトル・リンクを抽出
※①②については下記記載の参考リンクにある処理を転用させていただきました
③pytubeライブラリで取得したリンクから動画をmp4形式でダウンロード
※動画形式によっては失敗する場合がある。成功したものだけを取得する。
def Get_YoutubeSearch_Result(self,keyword,imnum=20): ''' Youtube検索結果の取得 (取得した画像は実行ファイルと同じ階層のmovieフォルダに検索ワードのフォルダを作って保存) ''' imnum = int(min(20,imnum)) contents = list(Youtube.search(keyword, num=imnum)) target_dir =os.path.dirname(os.path.abspath(__file__))+'/movie/'+keyword+"/" if os.path.exists(target_dir): shutil.rmtree(target_dir) os.makedirs(target_dir) for indx in range(len(contents)): tex_title = contents[indx].title.encode('cp932',"ignore") tex_title = tex_title.decode('cp932') print(tex_title) try: yt = YouTube(contents[indx].url) stream = yt.streams.get_by_itag(22) #MP4動画(720p)は22/ MP4音楽:140 失敗する動画はyt.streams.all()で表示後個別調整すれば取得可能 stream.download(target_dir) except: print("error") return
実装済みソースコード
参考サイト
Google画像検索の取得ライブラリ Google-images-download
Youtube動画ダウンロードライブラリ Pytube
データマージ方法① 複数ファイルに記載された集計データに対するマージ
やりたいこと
複数ファイルに記載された集計データのマージ * 各種の集計結果 (アンケート、帳票など)
* 時系列データ (タイムスタンプの処理)については別記事で記載予定
複数ファイルに記載された集計データのマージ
一般的によく使われそうなケースを想定して場合分けして考える
①複数グループのデータのマージ
- 重複する対象がない複数グループに対して同じ項目の計測をしたデータ
(下記では複数のチームに対する身体測定結果の例でイメージを記載)
[f:id:sd08419ttic:20190224192344p:plain]
実装
pandasのconcat関数を適用する
pandasのデータフレームリスト(以前記載した方法で取得)を引数とすると下記の処理でマージできる。
def merge_data_simlpe(self,input_pd_list): ''' 最もシンプルなデータのマージ (pandas concatを使った縦方向の結合) ''' result = input_pd_list[0] for dnameindx in range(len(input_pd_list)-1) : result = pd.concat([result,input_pd_list[dnameindx+1]]) result = result.reset_index(drop=True) #インデックスを振りなおす return result
②同一対象を含むデータのマージ
- 重複する対象を含む複数ファイルのデータ (同じ対象を別の時間で計測した結果など)
(下記では同じ組織に対する年度毎の身体測定結果の例でイメージを記載)
実装①
各dataframeに新しい列を追加し、ファイル名の情報を追加する
追加したdfをpandasのconcat関数を適用して結合する
def merge_data_with_filenamecol(self,input_pd_list,fname_list): ''' ファイル名を新しい列として追加するマージ ''' result = input_pd_list[0] fname, ext = os.path.splitext( os.path.basename(fname_list[0]) ) #ファイル名/拡張子の取得 result["file_name"] = fname for dnameindx in range(len(input_pd_list)-1) : fname, ext = os.path.splitext( os.path.basename(fname_list[dnameindx+1]) ) #ファイル名/拡張子の取得 temp_df = input_pd_list[dnameindx+1] temp_df["file_name"] = fname result = pd.concat([result,temp_df]) result = result.reset_index(drop=True) #インデックスを振りなおす return result
実装②
各dataframeの列にファイル名を添え字として保存する (下記の例)
上図において全て存在しているものを残す場合と、存在しない場合はでNanとする場合の2つの実装を考慮する。
(この2つはデータの種類によってどちらの形式を選択するか考慮したほうが良いと考えたため)
def merge_data_with_merge_only_common(self,input_pd_list,fname_list): ''' 一番左の列の要素をキーとして各ファイルのデータを添え字付きでマージする処理 (全てのファイルにキーが存在する行のみ表示) ''' result = input_pd_list[0] fname, ext = os.path.splitext( os.path.basename(fname_list[0]) ) #ファイル名/拡張子の取得 ori_columns = result.columns.tolist() for colindx in range(len(ori_columns)-1): ori_columns[colindx+1] = ori_columns[colindx+1]+"_"+fname #列名に添え字を追加 result.columns = ori_columns key_name = result.columns[0] #一番左の列をキーとする for dnameindx in range(len(input_pd_list)-1) : fname, ext = os.path.splitext( os.path.basename(fname_list[dnameindx+1]) ) #ファイル名/拡張子の取得 temp_df = input_pd_list[dnameindx+1] ori_columns = temp_df.columns.tolist() for colindx in range(len(ori_columns)-1): ori_columns[colindx+1] = ori_columns[colindx+1]+"_"+fname #列名に添え字を追加 temp_df.columns = ori_columns result = pd.merge(result,temp_df,on=key_name) result = result.reset_index(drop=True) #インデックスを振りなおす return result def merge_data_with_merge_all_data(self,input_pd_list,fname_list): ''' 一番左の列の要素をキーとして各ファイルのデータを添え字付きでマージする処理 (キーが不在の場合はNanで表示) ''' result = input_pd_list[0] fname, ext = os.path.splitext( os.path.basename(fname_list[0]) ) #ファイル名/拡張子の取得 ori_columns = result.columns.tolist() for colindx in range(len(ori_columns)-1): ori_columns[colindx+1] = ori_columns[colindx+1]+"_"+fname #列名に添え字を追加 result.columns = ori_columns key_name = result.columns[0] #一番左の列をキーとする for dnameindx in range(len(input_pd_list)-1) : fname, ext = os.path.splitext( os.path.basename(fname_list[dnameindx+1]) ) #ファイル名/拡張子の取得 temp_df = input_pd_list[dnameindx+1] ori_columns = temp_df.columns.tolist() for colindx in range(len(ori_columns)-1): ori_columns[colindx+1] = ori_columns[colindx+1]+"_"+fname #列名に添え字を追加 temp_df.columns = ori_columns result = pd.merge(result,temp_df,on=key_name, how='outer') print(result) result = result.reset_index(drop=True) #インデックスを振りなおす return result
実装結果は下記に記載
その他集約するファイル名の命名ルールで判定する、データ種別で結合可能か判定するなどのアプローチがあるが長くなりそうなので別記事で記載する。
画像・動画ファイル読み込み方法 (フォルダ配下の画像/動画/ドキュメントを一括読み込み)
やりたいこと
ユーザーが指定したローカルフォルダにある下記ファイルを画像形式で読み込む
jpgファイル
pngファイル
aviファイル
mp4ファイル
pdf ファイル (各ページを画像として取得)
フォルダ・ファイルパスを指定すると拡張子からフォーマットを識別して取得
動画は全フレーム/PDFは全ページを読み込む
読み込み結果はpandas dataframeのリスト(ファイル数分)、ファイル名のリストとして出力する
事前準備
pdfファイルの読み込みにpdf2imageというライブラリを利用する
上記ライブラリはpopperというアプリを動かす必要があるため、下記サイトからダウンロードして保存する
解凍後にbinファイルのパスを環境変数に指定する必要がある。 下記githubのスクリプトではpythonファイル内でパスを指定する処理を入れているのでフォルダ名を変更すれば利用できる。
実装
実装結果
https://github.com/sd08419ttic/python_tech_memo
各フォーマットファイルをnumpy ndarray として読み込む
画像・動画はopencvの関数を利用する (動画はフレームを1フレームづつ読み込み、成功した場合は保持する)
pdfはPILファイルをndarrayに変換した後で、色の順序をBGRにして保存する
def read_image_data(self,filename): ''' 画像データを読みとる (jpg/png/bmp) ''' result = cv2.imread(filename) return result def read_movie_data(self,filename): ''' 動画ファイルを読み込む(avi,mp4,wmv) ''' result_list = [] try: cap = cv2.VideoCapture(filename) ret, frame = cap.read() #最初のフレームを取得 except: print(filename ,"could not loaded!") traceback.print_exc() return result_list indx = 0 while (cap.isOpened()): ret, frame = cap.read() #最初のフレームを取得 if ret == True: #読み込み成功判定 #img = cv2.cvtColor(frame, cv2.COLOR_BGR) result_list.append(frame) print("deb_movie",indx) indx = indx +1 else: break cap.release() return result_list def read_pdf_page(self,filename): ''' PDFファイルを画像として読み込む (ページを一括変換) ''' result_list = [] try: images = convert_from_path(filename) for indx in range(len(images)): img_temp = np.asarray(images[indx]) img_temp = img_temp[:, :, ::-1].copy() #RGB->BGR result_list.append(img_temp) except: print(filename, "could not loaded!") traceback.print_exc() result_list = null return result_list
参考サイト・書籍
参考書 Pythonではじめるデータラングリング ―データの入手、準備、分析、プレゼンテーション
トップページ
このブログのコンセプト
業務等で活用しやすい『機能単位』でノウハウをまとめる
イラスト1つでやりたいことがわかる構成とする
詳細な機能の記事(各種ライブラリに関する使い方説明など) は他サイトのリンクにとどめる
カテゴリ
pythonによるデータ分析
データ読み込み
題目 | 説明 | リンク |
---|---|---|
数値データの読み込み | 指定したフォルダの各種ファイル(csv/xlsx/json等)から数値データを読み込む | リンク |
画像・動画データの 読み込み |
指定したフォルダの画像・動画ファイル(jpg/png/avi等)から数値データを読み込む | リンク |
Webサイトからの データ取得 |
WEBサイトから情報を取得する | リンク |
命名規則・作成日などの 条件付きファイル探索 |
条件にマッチしたファイルだけを探索して取得する | リンク |
前処理
題目 | 説明 | リンク |
---|---|---|
画像データの前処理 | 画像データを処理しやすいように整える(サイズ・ノイズ除去など) | リンク |
数値データの前処理 | 数値データのノイズ・欠損値を処理する | リンク |
数値データマージ・削減 | データの内容に応じてマージ・削減する処理 | リンク |
特徴抽出/パターン認識
題目 | 説明 | リンク |
---|---|---|
物体検出① | 簡易的な物体検出を行う(テンプレートマッチング/色検出/エッジ検出) | リンク |
物体検出② | YoloV3を用いたWebカメラ画像の物体検出 | リンク |
統計処理 | 入力データの特性を算出して可視化する | TBD |
機械学習 | データの特性を学習し、適切に分類する | TBD |
GUI出力/ユーザー要求処理
題目 | 説明 | リンク |
---|---|---|
GUI | tkinterを用いたGUI実装 | リンク |
グラフ表示 | matplotlibを用いたデータの可視化 | リンク |
グラフ表示(アニメーション) | matplotlibのアニメーション描画 | リンク |
exe化 | pyinstllerを用いたpythonスクリプトの実行ファイル化 | リンク |
ユーザー入力の受理 | pygameを用いたキーボード/ゲームパッド操作取得 | リンク |
電子工作プロトタイピング
前提知識
題目 | 説明 | リンク |
---|---|---|
開発環境 | プロトタイプ用ハード・開発環境に関する考え方 | リンク |
Raspberry Pi開発環境(ハード) | 必要なハードウェアについて | リンク |
Raspberry Pi開発環境(ソフト) | Ubuntu mate/ROSの導入方法について | リンク |
ソフトウェアアーキテクチャ | プロトタイピング時のソフトウェアアーキテクチャについて | リンク |
環境構築
題目 | 説明 | リンク |
---|---|---|
Pythonソフト構造 | 複数機能・ファイルから成り立つプロジェクトの構築 | リンク |
Python処理タイミング | 各機能の動作タイミングの設計方法 | TBD |
Arduinoソフト構造 | 複数機能・ファイルから成り立つプロジェクトの構築 | リンク |
Arduino処理タイミング | 各機能の動作タイミングの設計方法 | リンク |
通信機能
題目 | 説明 | リンク |
---|---|---|
ArduinoとPCの通信 | シリアル通信(USBケーブル) | リンク |
PCとの接続 | リモートデスクトップ/カメラ画像の送信/信号の送信 | TBD |
クラウドサービスとの接続 | IFTTT連携 (Google Home/スマートフォン) | TBD |
ROS開発
題目 | 説明 | リンク |
---|---|---|
ROS基礎 | 概念/用語/コマンドの使い方 | リンク |
ROS基礎2 | プロジェクト構築 | リンク |
PCとの通信 | Ubuntu PCとRaspberry piとの接続/制御信号の通信 | リンク |
ロボットモデルの記述 | URDFファイルにロボットのモデルを記述する | リンク |
移動ロボット基礎 | シミュレーション上でロボットを移動させる | リンク |
移動ロボットの走行経路 | ロボットの走行経路を設定する | リンク |
移動ロボットの経路追従 | 走行経路を追従する車速・角速度の制御 | リンク |
センシング
題目 | 説明 | リンク |
---|---|---|
カメラセンシング | Raspberry pi カメラを使った画像処理 | リンク |
各種センサ実装 | 各種センサの実装 | TBD |
pandasのデータファイル読み込み方法 (フォルダ配下のファイルを一括読み込み)
やりたいこと
Pandasでユーザーが指定したローカルフォルダにある下記データファイルを読み込む
フォルダ・ファイルパスを指定すると拡張子からフォーマットを識別して取得
各データファイルは1行目に項目ラベル、2行目以降にデータが記述されていることが前提
読み込み結果はpandas dataframeのリスト(ファイル数分)、ファイル名のリストとして出力する
実装
実装結果
各フォーマットファイルをpandas data frame として読み込む
pandasの各種フォーマットの読み込み関数を利用する 入力パスの拡張子からそれぞれの関数を呼び分ける
#csvデータの読み込み def read_file_autohandle(self,input_path): ''' 入力ファイルから拡張子を自動判定してpandasに読み込む ''' root, ext = os.path.splitext(input_path) #拡張子の取得 #拡張子毎に読み込みを実施 if ext == ".csv": result = self.read_csv_data(input_path) elif ext == ".tsv": result = self.read_tsv_data(input_path) elif (ext == ".xls") or (ext == ".xlsx"): result = self.read_xls_data_firstseat(input_path) elif ext == ".json": result = self.read_json_data(input_path) return result def read_csv_data(self,filename): ''' csvデータを読みとる ''' result = pd.read_csv(filename, encoding="shift-jis") #日本語データ(Shift-Jis)を含む場合を想定 return result def read_tsv_data(self,filename): ''' tsvデータを読みとる ''' result = pd.read_table(filename, encoding="shift-jis") #日本語データ(Shift-Jis)を含む場合を想定 return result def read_xls_data_firstseat(self,filename): ''' xlsx or xlsファイルの1枚目のシートを読みとる ''' result = pd.read_excel(filename, encoding="shift-jis") #日本語データ(Shift-Jis)を含む場合を想定 return result def read_xls_data_allsheat(self,filename): ''' xlsx or xlsファイルの全てのシートを読み込む ''' result = pd.read_excel(filename, encoding="shift-jis", sheetname =None) #日本語データ(Shift-Jis)を含む場合を想定 return result def read_json_data(self,filename): ''' jsonファイルを読み込む ''' result = pd.read_json(filename, encoding="shift-jis") #日本語データ(Shift-Jis)を含む場合を想定 return result
フォルダ内のファイルリストを探索する
フォルダ内のファイルリストを作成し、指定した拡張子に該当するものだけを抽出する サブフォルダ含めたファイルリストの作成はos.walkを用いる
def __init__(self, ext="ALL"): ''' コンストラクタ (読み込み対象とする拡張子を引数extで指定可能) ''' if ext !="ALL": self.target_ext = [ ext ] else: self.target_ext = [".csv",".tsv",".xls",".xlsx",".json"] return def get_file_path_list_in_folder(self,folder_path): ''' 入力フォルダパス直下にあるファイルのリストを作成する ''' if folder_path[-1] != "\\": folder_path = folder_path + "\\" file_full_path_list = [] # Search_Current_Directry for file in os.listdir(folder_path): root, ext = os.path.splitext(file) for indx2 in range(len(self.target_ext)): if ext == self.target_ext[indx2]: file_fullpath = folder_path + file file_full_path_list.append(file_fullpath) return file_full_path_list def get_file_path_list_in_folder_recrussive(self,folder_path): ''' 入力フォルダパスの配下(サブフォルダ含む)にあるファイルのリストを作成する ''' if folder_path[-1] != "\\": folder_path = folder_path + "\\" file_full_path_list = [] for folder, subfolders, files in os.walk(folder_path): for indx in range(len(files)): root, ext = os.path.splitext(files[indx]) for indx2 in range (len(self.target_ext)): if ext == self.target_ext[indx2]: file_fullpath = folder+'/'+ files[indx] file_full_path_list.append(file_fullpath) return file_full_path_list
参考サイト・書籍
pandasへのデータ読み込み yolo.love
参考書 Pythonではじめるデータラングリング ―データの入手、準備、分析、プレゼンテーション