質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.38%
Beautiful Soup

Beautiful Soupは、Pythonのライブラリの一つ。スクレイピングに特化しています。HTMLデータの構文の解析を行うために、HTMLタグ/CSSのセレクタで抽出する部分を指定することが可能です。

HttpWebRequest

HttpWebRequestとは.NETにおけるクラスであり、WebRequestクラスをHTTPに導入するものです。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

1回答

636閲覧

BeautifulSoupを用いたスクレイピングの画像収集条件の設定が上手くできない

lilliveon

総合スコア9

Beautiful Soup

Beautiful Soupは、Pythonのライブラリの一つ。スクレイピングに特化しています。HTMLデータの構文の解析を行うために、HTMLタグ/CSSのセレクタで抽出する部分を指定することが可能です。

HttpWebRequest

HttpWebRequestとは.NETにおけるクラスであり、WebRequestクラスをHTTPに導入するものです。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

0クリップ

投稿2023/09/24 16:08

編集2023/09/24 16:30

実現したいこと

スクレイピングで画像/動画作品を収集する際、各Webページにアクセスした時に、作品が表示される場合は取得し、表示されない場合は取得しないようにしたい(私の1つ前の質問とは内容が異なります)。

前提

閲覧頂きありがとうございます。
現在、danbooruというイラスト投稿サイトにおいて、特定のタグが付与されている作品を収集するソースコードを作っています。

下部に掲示しているソースコードの仕組みについて説明します。
まず以下のページのhtmlをrequestしたあとに作品を収集します。
https://danbooru.donmai.us/posts/6632499?q=jolteon
その後、nextクラスにある次のページのhtmlをrequestして作品を収集します。
https://danbooru.donmai.us/posts/6619855?q=jolteon
そしてまたnextクラスにある次のページのURLをrequestして作品を収集するというのを繰り返してスクレイピングを行います。

そして、danbooruの特徴として、擬人化(?)である一部の作品は、左上にある「Disable all」を押さないと表示されないようになっています。2つ目のURLの次のページは下記のURLであり、表示されない作品ページに該当いたします。
https://danbooru.donmai.us/posts/6619346?q=jolteon

その上で私のやりたいことは、3つ目のURLにあるような、擬人化されているため表示を制限されており「Disable all」を押さないといけない作品は収集しないように設定することです。現状のソースコードでは、表示を制限されている作品であろうとなかろうと収集してしまいます。

上記のことを実現するためのお力添えをいただきたいです。よろしくお願い致します。

### 該当のソースコード import requests from bs4 import BeautifulSoup import os import time output_dir = "danbooru_img/jolteon" end_times = 10000 url = "https://danbooru.donmai.us/posts/6632499?q=jolteon" for page in range(end_times): response = requests.get(url) if not os.path.exists(output_dir): os.makedirs(output_dir) soup = BeautifulSoup(response.text, "html.parser") try: source = soup.find("img", id="image").get("src") except AttributeError: # 作品が画像ではなく動画である場合はエラーが発生するのでこちらを実行 source = soup.find("video").get("src") img = requests.get(source) with open(f"{output_dir}/{source.split('/')[-1]}", 'wb') as f: f.write(img.content) time.sleep(1) next = soup.find("a", class_="next").get("href") url = f"https://danbooru.donmai.us/{next}" #次のページのURLを作成

試したこと

調べてみた結果、Seleniumを使うと実現できるのではないかと思いました。ですが、その場合は動作が遅くなるデメリットがあるためできるだけ使用したくありません。

加えて、開発者ツールを除いてみると、擬人化の作品ページには下の写真のような黄色で示してある部分がありました。ですがその部分はrenposeで解析したhtmlにはなかったため、find等で認識ができないという状態です。

イメージ説明

補足情報(FW/ツールのバージョンなど)

Python==3.11.5
requests==2.31.0
beautifulsoup4==4.12.2

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

lilliveon

2023/09/25 11:35 編集

コメントありがとうございます。 理由としましては正直にいいますと、当方APIを利用した経験がないのに対し、スクレイピングの方は簡単なものではありますが何度か実装したことがあるため、こちらの方が時間をかけずに作れると思ったからです。 (本ソースコードにおけるスクレイピングは規約違反ではないことは確認済みです) ですが、実際は本質問の部分で思わぬ苦戦してしまったため、APIを使った方が良かったかもです。
PondVillege

2023/09/25 12:59

そうですね,APIを使えば https://chat.openai.com/share/61fd18c8-7e49-442d-8b11-955937b0e309 かなり簡単に100件取得できましたし,APIレスポンスに`rating`の項目があったので,これが`g`か否かで判断するのがシンプルかと思われます あまりにも苦戦するようでしたら乗り換えるのも一手です
lilliveon

2023/09/25 13:35

確かに今回と同じかそれよりも更に応用的な実装を行う際にはAPIの方が速い気がしますし、プログラマーとしてAPiに触れることは確実にプラスになると思いますので、次に実装する時はAPIを使うことにします。 アドバイスに加え参考資料まで提示していただき誠にありがとうございます🙇‍♂
guest

回答1

0

ベストアンサー

当該のウェブページには blacklisted-tags というメタデータ要素が含まれています。

html

1<meta name="blacklisted-tags" content="guro,scat,furry -rating:g">

また、class 属性 image-container を含む section 要素には data-tags 属性と data-rating 属性があって、これらと blacklisted-tags を照合して表示・非表示を決定している様です。

html

1<section class="image-container note-container" data-id="6632499" 2 data-tags="absurdres animal_focus aqua_eyes blue_border border ..." 3 data-rating="g" ...

以上から、下記の様になります。

python

1import requests 2from bs4 import BeautifulSoup 3import os 4import time 5 6output_dir = "danbooru_img/jolteon" 7end_times = 10000 8url = "https://danbooru.donmai.us/posts/6632499?q=jolteon" 9 10os.makedirs(output_dir, exist_ok=True) 11 12for page in range(end_times): 13 response = requests.get(url) 14 soup = BeautifulSoup(response.text, "html.parser") 15 16 btags = soup.select_one('meta[name=blacklisted-tags]').get('content') 17 blacklisted_tags = btags.split(' ')[0].split(',') 18 blacklisted_rating = btags.split(' ')[-1].split(':')[-1] 19 img_container = soup.select_one('section.image-container') 20 data_tags = img_container.get('data-tags').split(' ') 21 data_rating = img_container.get('data-rating') 22 23 # data-tags に blacklisted-tags が含まれていない、もしくは data-rating が blacklisted rating に 24 # 等しい("-rating:g" となっているので)場合にコンテンツを保存する 25 if not ({*data_tags} & {*blacklisted_tags}) or data_rating == blacklisted_rating: 26 try: 27 source = soup.find("img", id="image").get("src") 28 except AttributeError: # 作品が画像ではなく動画である場合はエラーが発生するのでこちらを実行 29 source = soup.find("video").get("src") 30 31 img = requests.get(source) 32 33 with open(f"{output_dir}/{source.split('/')[-1]}", 'wb') as f: 34 f.write(img.content) 35 36 time.sleep(1) 37 next_url = soup.find("a", class_="next").get("href") 38 url = f"https://danbooru.donmai.us/{next_url}" #次のページのURLを作成

投稿2023/09/24 19:46

編集2023/09/24 21:51
melian

総合スコア20552

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

lilliveon

2023/09/25 11:28

分かりやすく丁寧な解説をしてくださり大変参考になりました。 おかげさまで原理も含めてちゃんと理解することができました。 本当にありがとうございました🙇‍♂
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.38%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問