Webスクレイピングというものでカニの写真を集めてみた話[Python]
wauです。Webスクレイピングというものに挑戦したので、メモを残しておきます。
準備
Visual Studio 2019でコードを書いていきます。
そのために、インストーラーでPython開発環境をインストールしておきます。
Pythonでは「ライブラリ」というものを適宜インストールしていくことで環境を拡張することができます。
今回使った外部ライブラリはこちら。
・requests … Webサイトの情報を取得
・BeautifulSoup4 … Htmlからデータを取り出す
・Selenium … ブラウザを自動操作する
その他にも、Seleniumを動作させるために必要なWebDriverをダウンロードする必要などがありました。
Python全くわからなかったのでインストールも大変でした。
実際のコード
色んなサイトや動画を見てつなぎ合わせたコードがこちら。
import requests from bs4 import BeautifulSoup from selenium import webdriver import chromedriver_binary import subprocess import time import re # スクレイピングするURLを記述。 pageUrl = "https://search.yahoo.co.jp/image/search?p=%E3%82%AB%E3%83%A9%E3%83%83%E3%83%91&fr=top_ga1_sa&ei=UTF-8" # WebDriverのオプションを設定。 options = webdriver.ChromeOptions() # options.add_argument('--headless') # コメントアウトすることでブラウザを実際に立ち上げる。 print('connectiong to remote browser...') driver = webdriver.Chrome(options=options) # WebDriverにURLを渡す。 driver.get(pageUrl) # 最下段まで進んで1秒待つ、を繰り返す(ページの自動リロード)。 driver.execute_script("window.scrollTo(0, document.body.scrollHeight);") time.sleep(1) driver.execute_script("window.scrollTo(0, document.body.scrollHeight);") time.sleep(1) driver.execute_script("window.scrollTo(0, document.body.scrollHeight);") time.sleep(1) driver.execute_script("window.scrollTo(0, document.body.scrollHeight);") time.sleep(1) driver.execute_script("window.scrollTo(0, document.body.scrollHeight);") # ページのソースをエンコードしてHtmlとし、BeautifulSoupで読み込む。 html = driver.page_source.encode('utf-8') soup = BeautifulSoup(html, 'html.parser') # imgタグのうち、alt属性に"カラッパ"を含むものを全て集めてリストにする。 img_tags = soup.find_all("img", alt=re.compile("カラッパ")) img_urls = [] # リストのimgタグそれぞれから画像URLを取得し、img_urlsに追加。 for img_tag in img_tags: url=img_tag.get("src") img_urls.append(url) print(url) # ダウンロード関数の定義。 def download_image(url, file_path): # requwstsでURLからページを取得 r = requests.get(url, stream=True) # status_code == 200 というのは、ページ取得成功のこと。 if r.status_code == 200: # f = open(~)と同じ。with-asで使うことでcloseの必要がなくなる。 # "wb"はw:書き込み用で、b:バイナリモードで開く。 with open(file_path, "wb") as f: # URLのバイナリデータをfに書き込む。つまり画像などのデータ保存となる。 f.write(r.content) # subprocessモジュールでコマンドプロンプトを起動。画像を保存するディレクトリを作成。 subprocess.Popen("dir",shell=True) subprocess.Popen("mkdir images",shell = True) # img_urlsをforループで回して、ダウンロード関数を動かす。 for index, url in enumerate(img_urls): file_name = f"{index:03}.jpg" print(file_name) img_path = "images/{}".format(file_name) print(img_path) download_image(url = url, file_path = img_path)
正直よくわかってない箇所があまりに多いのでアレなんですが、ひとまずこれで画像を沢山保存することはできました。
ここにつまづいた
Pythonのライブラリインストール
上にも書きましたが、最初はここからわかりませんでした。importってコードに書けば使えるものだと思ってました。C#でいうとこのusingですね。
fromってのをつけることで、モジュール名を省略して使えるようになるそうで。この辺もC#で似たようなのをやった気がします。
画面に表示されてる分しか画像が保存できない
Yahooの画像検索の仕様で、下にスクロールすることである程度画像を追加読み込みしてくれます。これを疑似的に動かすために、webdriverのメソッドで一番下までスクロールさせて、timeのメソッドで1秒待つ。を何度か行いました。もう少しスマートにいくと思うんだけどな。
HTMLタグと属性
imgタグが付いてるものは画像!というのは感覚でわかりました。
alt属性には画像の情報をテキストで書くものというのも聞いたことがあったので、そこに対象となる文字列(ここでは"カラッパ")を含むものをピックアップする…という書き方をするのにすこしつまづきました。
re.compileというメソッドを使うのですが、このreもimportしなきゃいけないんですね…わかりにくい……
forループの書き方
C#でいうとこのforeachに近いんだなという印象でした。また、indexを追記することでインデックスを同時に参照することもできるみたいです。これは便利。
コマンドの使い方
windowsではLinux,Unixのシェルコマンド?を使うことはできないので、Windowsで使われているコマンドを使う必要があります。それは当然なんだけど、これをどう使うか?最初はよくわかりませんでした。
結果、
subprocess.Popen("コマンド", shell=True)
と書く必要がありました。subprocessはimportしたうえで使います。
ちなみにPopen()のかわりにrun()でもよさそうです。違いは非同期処理か同期処理かだそうですが、なんのことやら…この用法だったらrun()の方でも良さそうな気もしますね。
ダウンロード関数の定義
コピペして動かしてから、なんで動いてんのかわからないな…?となったので調べました。
requests.status_codeってのはいわゆる404とか503とかのやつですね。200は成功を意味するそうです。
Pythonにおけるwithってのが最初はよくわからなかったですね。openで開いたファイルはcloseで閉じる必要があるらしく、withをつけてあげることでそのcloseを省略できるとのことでした。
そして画像保存の仕組みはバイナリデータの書き込みだそうです。なるほど…?
5/16追記 chromedriverのパス
chromedriverを実行する際にパスを指定する必要があります。
driver = webdriver.Chrome(~ここにパスを指定~)
ですが今回は記述してません。それなのに動いた理由は、
import chromedriver_binary
のおかげだそうです。理由は今一つわからないけど、ここを省略できるのは今後大きいなと思いました。
おわりに
Pythonわからん、Htmlもよくわからん。
でもググりにググって情報をかき集めることで、なんとかものになったので満足です。
今後はこれを応用できればなおよしですね。何ができるかを調べるのもよさそう。では。