退屈なことをPythonにやってもらうための演習の回答[11.10.2]
こんばんは白地です。
毎度、『退屈なことはPythonにやらせよう』についている演習プロジェクトの自分なりの回答を投げていきます。
11-10-1より先に11-10-2を先にやったのは、ちょっとWebメールをどうしようか悩んだからです。いちおう本文でも触れられていますが、セキュリティ的に褒められたものではなさそうです。それに、下手にGmailとか使ってロックされたら面倒ですしね。
お題について
FlickrやImgurなどの写真共有サイトから、写真のカテゴリーを検索し、検索結果の画像をすべてダウンロードするプログラムを書きなさい
何にしようかと考えたのですが、もう流行ではなくプラットフォームと化しているInstagramにしました。
まずここで面倒になったのが、ログイン系です。Instagramはログインしないと検索フォームに入力できないようのですが、そこまでやることなのかなと…
そこで検索してみたところ、検索結果のURLがhttps://www.instagram.com/explore/tags/(検索した単語)/ になっていたので、このURLを生成してアクセスすることにします。
URLへのrequestsをそのままbs4に引き渡すやり方が分からなかったので、 https://python.civic-apps.com/beautifulsoup4-selector/ を参考にしました。
そしてその次に面倒になったのが、画像取得です。盛大に詰まりました。
まず、色々な対策やら実装の都合だとは思うんですが、Instagramの画像はimgタグで表示されているわけではなく、JavaScriptで実装されてるんですよね。なので、BeautifulSoupの解析が使えません。涙目。
なので、bodyタグ直下のscriptタグの中身をひっぺがして、画像のURLを抜き取ります。
ここで更に詰まったのが「URLの正規表現がわからん」ということでした。仕方ないので決め打ちで仕込んだのですが、本当はもうちょっと汎用性がある方が良いように思いました。
あとは、抜き取ったURLのなかから縮小表示用の画像と、DLしたファイルと同一のものを弾いてファイルに保存します。
ソースコード
#! python3
# 11.10.2 画像サイトのダウンローダー
# FlickrやImgurなどの写真共有サイトから、写真のカテゴリーを検索し、検索結果の画像をすべてダウンロードするプログラムを書きなさい
# instagramに決定
import requests,bs4,logging,re,os
#DEBUG
logging.basicConfig(level=logging.CRITICAL,
format=' %(asctime)s - %(levelname)s - %(message)s')
logging.debug('start')
# 検索ワードの設定
search_word = '柊宇咲'
access_url = 'https://www.instagram.com/explore/tags/' + search_word + '/'
res = requests.get( access_url )
res.raise_for_status()
# jpgを抜き出す
soup = bs4.BeautifulSoup(res.content, 'html.parser')
content = soup.select('body > script')
img_regex = re.compile(r'https://scontent-nrt1-1.cdninstagram.com/.+?\.jpg')
img_list = img_regex.findall(str(content))
# logger.debug(img_list)
# ファイルのダウンロード
# URLに「s150x150」「s240x240」「s320x320」「s480x480」が含まれていたらDLしない
# ファイル名が重複してもDLしない
no_dl_regex = re.compile(r's[0-9]+?x[0-9]+?')
file_list = []
os.makedirs( search_word, exist_ok=True)
for img in img_list:
if ( no_dl_regex.search(img) is None ) and ( os.path.basename(img) not in file_list ):
img_file = open(os.path.join( search_word ,os.path.basename(img)),'wb')
logging.debug('start download %s', format(img))
img_url = requests.get(img)
img_url.raise_for_status()
for chunk in img_url.iter_content(100000):
img_file.write(chunk)
img_file.close()
logging.debug('download complete')
file_list.append(os.path.basename(img))
logging.debug('end')
# 一応クローズしておく
res.close()
余談
検索ワードの方は、お顔がよろしいなぁと思ったアイドルの方です。
この記事が気に入ったらサポートをしてみませんか?