Pyautoguiでyahooピンポイント天気のサイトを立ち上げ
情報をコピペして表に保存する方法です。
Pyautoguiを理解するためのもので実用的ではありません。
Windows、JupiterNotebookにて動作を想定しています。
この記事の続きです。
注意事項
コードを実行するときは自己責任でお願いします。
コードの内容を理解してから実行してください。
最前面のWindowが処理対象になるため処理中は他の操作はできません。
最前面にほかのWindowが出ていると、そのWindowに対して操作してしまいます。
マウスをコントロールするため予想外の動作をするかもしれません。
緊急時の停止方法
- 0,0の座標にマウスをもっていけばフェールセーフ機能で
プログラムを止めることができます。 - alert画面でマウスの位置を決めるように促されるので
その時JupiterNotebookの停止を押してプログラムを止めてください。 - 最悪CTRL+Alt+Delでとまるので、その間に0,0を何回も突っつく、またはJupiterNotebookの停止を押す。またはタスクマネージャーをクリックしてJupiterNotebook(プラウザ)のタスクを終了する(いろいろ不具合が起こるかもしれないので最終手段です。)
Yahooピンポイント天気新宿から天気の表を抽出する(CTRL+a、CTRL+c版) のみ
実行おすすめします。
動作画面
出力された表の見出し行が2行になってカッコ悪いと思った方は
こちらの記事を見てください。(原因が書いてあります)
Yahooピンポイント天気新宿から天気の表を抽出する(個別にコピペ版)
参考にしてもらうため意味のない動作、数パターンで文字を選択しています。
動作説明
Yahooのピンポイント天気の項目を、やり方を変えて読み込んでいます。
時刻→1個ずつ読み込む
天気→1行まとめて読み込む。
気温、湿度、降水量→3行まとめて読み込む。
画面位置が人それぞれ違うと思うので、
開始位置をalert画面で指定するようにしてます。
しかし「時刻」は1文字ずつ読み込んでいるので
文字間隔が違うとちゃんと読めないと思います。
- JupiterNotebookでプログラムを開始させる。
- Edgeが立ち上がりyahooピンポイント天気のアドレスをアドレスバーにコピペして移動。
- alert画面がでるので時刻の左側の位置にマウスを移動し、その状態でEnterキーを押す。
(クリックではないので注意でいてください。)
クリックしてしまうとターゲットがEdgeに移動してしまうので
もう一度alert画面のOK以外の部分をクリックしてalert画面がアクティブな状態にしてから
マウスを移動しキーボードでEnter。 - 天気の欄を1行分読み込む。
開始は天気の横、終了位置はマークではなく「晴れ」とかの文字の横にする。 - 気温、湿度、降水量はまとめて読み込むので開始位置は気温の横、
終了位置は降水量の最後にしてください。 - Yahooを閉じJupiterNotebookに読み込んだ表を表示。
コード
import文は、もう1個のプログラムも共通です。
import pyautogui as pag
import time
import pyperclip
import subprocess
import pandas as pd
import re
#Yahooピンポイント天気新宿から天気の表を抽出する(個別にコピペ版)
#Edgeの起動
subprocess.run(r'C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe')
time.sleep(1)
#window最大化
pag.hotkey('win', 'up')
#Yahooピンポイント天気新宿のアドレス
str1='https://weather.yahoo.co.jp/weather/jp/13/4410/13104.html'
#クリップボードにコピー
pyperclip.copy(str1)
#アドレスバーにカーソルがなく入力する状態になっていない場合座標確認して使ってください。
#マウスをアドレスバーへ移動
# pag.moveTo(220,51)
#クリック
# pag.click()
time.sleep(1)
#CTRL+Vで貼り付け
pag.hotkey("ctrl","v")
#Enter
pag.press('enter')
#***********時刻をコピペする処理************
time.sleep(5)
list1=[]
#alertとメッセ時表示
goal=pag.alert(text='時刻の開始点を指定してEnterしてください',title='確認',button='OK')
#時刻の開始点を代入
x,y=pag.position()
#時刻の開始点へ移動してクリック
pag.moveTo(x,y,1)
pag.click()
#ドラッグして選択状態
pag.dragTo(x+30,y,1)
#CTRL+Cでコピー
pag.hotkey("ctrl","c")
#str1へコピーした文字を入れる
str1=pyperclip.paste()
#リストに追加
list1.append(str1)
#以下8個分コピーしてリストへ
x1=x+90
pag.moveTo(x1,y,0.5)
time.sleep(0.5)
for i in range(8):
pag.click()
time.sleep(0.5)
pag.drag(35,0,1)
pag.hotkey("ctrl","c")
str1=pyperclip.paste()
#読み取った時間を1個ずつlist1に追加
list1.append(str1)
pag.move(30,0,0.5)
#************天気をコピペする処理************
list2=[]
goal=pag.alert(text='天気開始点を指定してEnterしてください',title='確認',button='OK')
x,y=pag.position()
goal=pag.alert(text='天気終点を指定してEnterしてください',title='確認',button='OK')
x1,y1=pag.position()
pag.moveTo(x,y,1)
pag.click()
pag.dragTo(x1,y1,1)
pag.hotkey("ctrl","c")
str1=pyperclip.paste()
#str1の中身
#'天気\t晴れ\r\n晴れ\t晴れ\r\n晴れ\t晴れ\r\n晴れ\t晴れ\r\n晴れ\t晴れ\r\n晴れ\t晴れ\r\n晴れ\t晴れ\r\n晴れ\t晴れ\r\n晴れ'
#str1に入ってる文字列の\tと\rnをカンマに置き換え
str2=str1.replace('\t',',').replace('\r\n',',')
#カンマでリストへ
list20=str2.split(',')
#偶数番目が必要な要素なのでリストへ
list2=list20[::2]
#************気温、温度、降水量をコピペする処理************
list0=[]
goal=pag.alert(text='気温開始点を指定してEnterしてください',title='確認',button='OK')
x,y=pag.position()
goal=pag.alert(text='降水量終点を指定してEnterしてください',title='確認',button='OK')
x1,y1=pag.position()
pag.moveTo(x,y,1)
pag.click()
pag.dragTo(x1,y1,1)
pag.hotkey("ctrl","c")
str1=pyperclip.paste()
#str1の中身
#'気温(℃)\t4\t4\t3\t5\t8\t7\t4\t3\r\n湿度(%)\t51\t37\t41\t35\t24\t20\t28\t29\r\n降水量(mm)\t0\t0\t0\t0\t0\t0\t0\t0'
#余計な記号をカンマに変換
str2=str1.replace('\t',',').replace('\r\n',',')
#カンマで分割してリストへ
list0=str2.split(',')
i=0
bunkatu=[]
#数字意外の文字を探索して場所を記録、そこで分割するため
for a in list0:
if not a.isdecimal():
bunkatu.append(i)
i+=1
#気温、温度、降水量のリストに分割
#漢字の位置はbunkatuに入っているので、それを使ってスライス(指定した位置をリストとして取り出し新たなリストが作れる。)
list3=list0[bunkatu[0]:bunkatu[1]]
list4=list0[bunkatu[1]:bunkatu[2]]
list5=list0[bunkatu[2]:]
list3,list4,list5
#************表にする処理************
list_all=[list2,list3,list4,list5]
#list1をカラム、list2から5をデータにして表作成
df1=pd.DataFrame(data=list_all, columns = list1)
#インデックスが0123と数字になってしまうのでインデックスを時刻列にする
df1.set_index('時刻', inplace=True)
time.sleep(0.5)
#Yahooを閉じる
pag.hotkey("Ctrl","w")
df1
Yahooピンポイント天気新宿から天気の表を抽出する(CTRL+a、CTRL+c版)
CTRL+aとCTRL+cですべて選択し文字列に代入して処理する。
この方がマウス操作を使わないため安定性は高い。
しかし最前面に出ている状態での操作には変わらない。
動作説明
- JupiterNotebookでプログラムを開始させる。
- Edgeが立ち上がりyahooピンポイント天気のアドレスをアドレスバーにコピペして移動。
- CTRL+a、CTRL+cによりすべてコピーして読み込みます。
- 時刻\t0時~\r\n風向までが必要なデータなので
replaceやsplit、正規表現を使ってデータを整え表にする。 - Yahooを閉じJupiterNotebookに読み込んだ表を表示。
コード
上のimport文を使ってください。
#Yahooピンポイント天気新宿から天気の表を抽出する(CTRL+a、CTRL+c版)
#Edgeの起動
subprocess.run(r'C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe')
time.sleep(1)
#window最大化
pag.hotkey('win', 'up')
#Yahooピンポイント天気新宿のアドレス
str1='https://weather.yahoo.co.jp/weather/jp/13/4410/13104.html'
#クリップボードにコピー
pyperclip.copy(str1)
#アドレスバーにカーソルがなく入力する状態になっていない場合座標確認して使ってください。
#マウスをアドレスバーへ移動
# pag.moveTo(220,51)
#クリック
# pag.click()
time.sleep(1)
#CTRL+Vで貼り付け
pag.hotkey("ctrl","v")
#Enter
pag.press('enter')
time.sleep(5)
#************ ctrl+aとCTRL+cで全部コピーしてstr2にペースト************
pag.hotkey("ctrl","a")
time.sleep(1)
pag.hotkey("ctrl","c")
time.sleep(1)
str2=pyperclip.paste()
#'時刻\t0時'~'\r\n風向'までが対象なので分割の目印としてbunkatuを加える
str3=str2.replace('時刻\t0時','bunkatu時刻\t0時').replace('\r\n風向','bunkatu\r\n風向')
#bunkatuで分割してリストへ、1番目の要素が対象部分なのでstr4[1]のみ使う
str4=str3.split('bunkatu')
#各行に分割するため目印としてbunkatuを追加
str5=str4[1].replace('\r\n天気','bunkatu天気').replace('\r\n気温','bunkatu気温').replace('\r\n湿度','bunkatu湿度').replace('\r\n降水量','bunkatu降水量').replace('\t',',').replace('\r\n','')
#bunkatuで分割しリスト化
str6=str5.split('bunkatu')
#各要素を,で分割しリスト化
list1=str6[0].split(',')
list2=str6[1].split(',')
list3=str6[2].split(',')
list4=str6[3].split(',')
list5=str6[4].split(',')
#天気の行は天気マークが文字に変換され同じ文字がダブっているので正規表現を使って同じ文字を1文字へ変換
list20=[]
#'天気'追加
list20.append(list2[0])
#各要素で同じ文字列が出現したら1つにする
for a in list2:
for m in re.finditer(r"(\S+?)\1+",a):
list20.append(f"{m[1]} ")
#************表にする処理************
list_all=[list20,list3,list4,list5]
#list1をカラム、list2から5をデータにして表作成
df1=pd.DataFrame(data=list_all, columns = list1)
#インデックスが0123と数字になってしまうのでインデックスを時刻列にする
df1.set_index('時刻', inplace=True)
time.sleep(0.5)
#Yahooを閉じる
pag.hotkey("Ctrl","w")
df1
CSVファイルに出力
Pyautoguiを使用して自動化するコツ
- 今回と別の方法として対象ツールの立ち上げはデスクトップにショートカットを作ったり
タイル(スタートをクリックしたら右に出るやつ)に置いたりする。
Webの場合はお気に入りバーを使う。 - マウス操作は対象の位置を気にしないとならないので、できるだけ使わない。
- キー操作を使う。
- CTRL+A→CTRL+Cですべてコピーして文字列変数に代入してから操作するほうがいい。
- 1個1個ドラッグする場合ドラッグ区間を長く移動区間を短く配分するとうまくいく。
- Excelの場合は名前ボックスや矢印キーを使って移動する。
同じような内容ですが、こちらはより実践的な記事です。こちらのほうがおすすめです!
pandasのread_htmlを使えば簡単だけど・・・
実は今回、紹介したものは以下で簡単に実施できます。必ず目でこのサイトを見てから実行してください。yahooピンポイント天気(目で見られること(広告がみられること)を前提に情報を出していると思うので見ないで情報を抽出するのは避けたほうがいいと思います。なぜネットの情報が無料なのかについて、こちらも見てください。↓↓)
注意点
- この処理はスクレーピングにあたるので実施については「スクレーピング 注意点」で、お調べください。
- 表があるサイトしか抽出できない。できない場合もある。
- ログインが必要なサイトの表は抽出できないと思います。
コード
import pandas as pd
url='https://weather.yahoo.co.jp/weather/jp/13/4410/13104.html'
dflist = pd.read_html(url,encoding='utf-8')
df = dflist[1]
df.head()
サイトによってはエラーになります。
例えば新型コロナウイルスに感染した患者の発生状況
pandas以外のライブラリ(BeautifulSoup4、html5lib、lxml)が必要なようです。私はあまりインストールしたくないので、よく使うBeautifulSoup4しかいれてません。なのでこれらをインストールした実行の確認はしていません。
File ~\anaconda3\lib\site-packages\pandas\io\html.py:931, in _parser_dispatch(flavor)
929 if flavor in ("bs4", "html5lib"):
930 if not _HAS_HTML5LIB:
--> 931 raise ImportError("html5lib not found, please install it")
932 if not _HAS_BS4:
933 raise ImportError("BeautifulSoup4 (bs4) not found, please install it")
ImportError: html5lib not found, please install it
PyAutoGuiやpyperclipを使った方法だと、汎用性は高いしわかりやすいです。
PyAutoGuiとpyperclipを使う方法
目次へ
この記事を書いたイチゲを応援する(質問でもOKです)
Vプリカでのお支払いがおすすめです。
MENTAやってます(ichige)
コメント