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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Tkinter

Tkinterは、GUIツールキットである“Tk”をPythonから利用できるようにした標準ライブラリである。

Q&A

解決済

1回答

336閲覧

Pythonスクレイピング

T_www

総合スコア13

Tkinter

Tkinterは、GUIツールキットである“Tk”をPythonから利用できるようにした標準ライブラリである。

0グッド

1クリップ

投稿2018/04/21 12:59

前提・実現したいこと

Yahoo画像検索を使用して画像を集めまくるプログラムを作成したいのです。※超初心者です。

発生している問題

bs4で画像のURLを取得する方法が解らないです。

該当のソースコード

Python

1# -*- coding: utf-8 -*- 2#おまじない 3import urllib #URLエンコード用 4import bs4 #HTMl解析 5import requests #URlアクセス? 6import re #正規表現(URL抽出) 7import tkinter as tk #GUI 8#import ui #GUI作成 9 10#GUIコールバック関数 11def owari(): 12 quit() 13 14#関数コーナー 15def worde(): #検索ワード要求からURL作成まで(仮) 使用ライブラリ:urllib 16 #検索したいワード 17 ken = "草" 18 #URLエンコード 19 enk = urllib.parse.quote(ken) 20 #URL作成 21 global url 22 url = 'https://search.yahoo.co.jp/image/search?n=60&p=' + enk 23 url = url + '&search.x=1' 24#ダウンロード用(HTML)関数 25def hack(): #wordeで取得したURLから画像のURLを抜き出す(解析) 使用ライブラリ:bs4 26 res = requests.get(url) #URLアクセス? 27 res.raise_for_status() #わかんねえ 28 soup = bs4.BeautifulSoup(res.text, "html.parser") #わかんね 29 elems = soup.select('a') #aタグを選択 30 url_list = [] #URLを格納するリストやで 31 for img in elems: #URL取得やで 32 url_list.append(img.get('href')) 33 print (url_list) 34 35 kazu = (len(url_list)) #判定 36 37 print (kazu) 38 39 if kazu == 0: #URL数が0だった時、エラーを出す。 40 error = "urlzeroerror" 41 else: 42 tdo = url_list 43worde() 44hack() 45 46#GUIやで 47#トップウィンドウ作成 48root = tk.Tk() 49#ウィンドウのタイトルを設定 50root.title("フリー画像ダウンローダ -ver1.0_beta") 51#ウィンドウの大きさを指定 52root.geometry("800x500") 53 54#UI部分(本体) 55frame1 = tk.Frame(root) 56frame1.pack() 57#ロゴ?を表示 58image1 = tk.PhotoImage(file = 'LOGO.gif') 59tk.Label(frame1, image = image1).pack()#.grid(row=0, column=0) 60#探すボタンを作成 61serch = tk.Button(frame1, text='探す', padx=45, pady=7)#, command=b1) 62serch.pack() 63#空白 64tk.Label(frame1, text="").pack() 65#オプションボタンを作成 66option = tk.Button(frame1, text='設定', padx=44, pady=7) #微調整しているため、padxの値がちょっとおかしい 67option.pack() 68#空白 69tk.Label(frame1, text="").pack() 70#バグ連絡 71bug = tk.Button(frame1, text="バグ・要望等連絡", padx=15, pady=7) 72bug.pack() 73#空白 74tk.Label(frame1, text="").pack() 75#終了ボタンを作成 76owa = tk.Button(frame1, text="終了", padx=46, pady=7, command=owari) 77owa.pack() 78 79root.mainloop() 80

試したこと

いろいろなサイトを見て回ったこと

補足情報

Pyhon3.6.5

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

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

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

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

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

guest

回答1

0

ベストアンサー

bs4で画像のURLを取得する方法が解らないです。

これに関しては質問文のソースコードでurl_listでURLを取得できているので、ダウンロードの仕方と保存の仕方が分からないと判断しました。

極論を言えば以下のコードでも可能かと。

Python

1import os 2 3for s in url_list: 4 res = requests.get(s) 5 file_name = os.path.basename(s) 6 with open(file_name, 'wb') as f: 7 f.write(res.content)

※超初心者です。

うーん、少し悩みましたが、ソースコードを頑張って読み取ってくれることを期待して。

クラス役割
MyFrame画面
DownLoaderダウンロード処理

Python

1# -*- coding: utf-8 -*- 2from concurrent.futures import ThreadPoolExecutor, as_completed 3from io import BytesIO 4import os 5from pathlib import Path 6from threading import Thread 7from time import sleep 8#おまじない 9import urllib #URLエンコード用 10import bs4 #HTMl解析 11import requests #URlアクセス? 12import re #正規表現(URL抽出) 13import tkinter as tk #GUI 14#import ui #GUI作成 15 16 17class MyFrame(tk.Frame): 18 def __init__(self, root): 19 super().__init__(root) 20 self.pack() 21 22 # ロゴ?を表示 23 # image1 = tk.PhotoImage(file = 'LOGO.gif') 24 # tk.Label(frame1, image = image1).pack()#.grid(row=0, column=0) 25 # ※検索キーワードのテキストボックスを作成 26 self.key_word = tk.StringVar(value='草') 27 self.txt_key_word = tk.Entry(self, textvariable=self.key_word) 28 self.txt_key_word.pack() 29 # 探すボタンを作成 30 serch = tk.Button(self, text='探す', padx=45, pady=7, command=self.search) 31 serch.pack() 32 # 空白 33 tk.Label(self, text="").pack() 34 # オプションボタンを作成 35 option = tk.Button(self, text='設定', padx=44, pady=7) # 微調整しているため、padxの値がちょっとおかしい 36 option.pack() 37 # 空白 38 tk.Label(self, text="").pack() 39 # バグ連絡 40 bug = tk.Button(self, text="バグ・要望等連絡", padx=15, pady=7) 41 bug.pack() 42 # 空白 43 tk.Label(self, text="").pack() 44 # 終了ボタンを作成 45 owa = tk.Button(self, text="終了", padx=46, pady=7, command=self.owari) 46 owa.pack() 47 48 def search(self): 49 search_word = self.key_word.get() 50 # ※画面をブロックさせないためにスレッドを生成して、startを呼び出す。 51 t = Thread(target=hack, args=(search_word,)) 52 t.start() 53 54 def owari(self): 55 quit() 56 57 58class DownLoader(object): 59 def __init__(self): 60 # ミリ秒に変換 61 self.interval = 500 / 1000 62 # sec 63 self.timeout = 10 64 self.download_dir = Path('download') 65 self.download_dir.mkdir(exist_ok=True) 66 67 def get(self, url: str, params: dict=None): 68 # 実際のリクエスト処理はここ 69 res = requests.get(url, params=params, timeout=self.timeout) 70 print(res.url) 71 # http ステータスコードが200番台以外なら例外を発生させる。 72 # 存在しないwebページをurlに指定すると例外が発生するので分かりやすいかと。 73 res.raise_for_status() 74 return res 75 76 def get_content(self, url: str, params: dict=None): 77 sleep(self.interval) 78 res = self.get(url, params) 79 return BytesIO(res.content), res.headers['content-type'] 80 81 def request(self, url_list: list) ->None: 82 """ 83 internet -- (Get) --> local 84 use ThreadPoolExecutor 85 """ 86 count = 0 87 with ThreadPoolExecutor() as executor: 88 future_to_url = {executor.submit(self.get_content, url): url for url in url_list} 89 for future in as_completed(future_to_url): 90 url = future_to_url[future] 91 try: 92 93 # get_contentの戻り値はここで取得 94 buffer, content_type = future.result() 95 # 保存対象のファイルかどうか。 96 if not self.save_content_type(content_type): 97 continue 98 # 保存ファイル名はURLのパス部分をそのまま取得 99 # 重複が発生するので連番を付けたりして対応してくださいな。 100 file_name = self.download_dir / os.path.basename(url) 101 102 print(content_type, file_name) 103 # 保存 104 self.save_file(buffer, file_name) 105 count += 1 106 except Exception as ex: 107 print(f"url:{url}, {ex}") 108 109 if count == 0: 110 print(f'save file Empty') 111 112 def save_content_type(self, content_type: str) ->bool: 113 is_saved = ["image/jpeg", "image/png", "image/gif"] 114 return content_type.lower() in is_saved 115 116 def save_file(self, buffer: BytesIO, file_name: Path) ->None: 117 with file_name.open('wb') as f: 118 f.write(buffer.getvalue()) 119 120 121# ※Downloaderクラスのインスタンスを生成 122dl = DownLoader() 123 124 125#ダウンロード用(HTML)関数 126def hack(search_word: str): #wordeで取得したURLから画像のURLを抜き出す(解析) 使用ライブラリ:bs4 127 url = 'https://search.yahoo.co.jp/image/search' 128 params = {'n': '60', 'p': search_word, 'search.x': '1'} 129 res = dl.get(url, params) 130 print(res.text) 131 soup = bs4.BeautifulSoup(res.text, "html.parser") #わかんね 132 elems = soup.select('a') #aタグを選択 133 url_list = [] #URLを格納するリストやで 134 for img in elems: #URL取得やで 135 url_list.append(img.get('href')) 136 #print (url_list) 137 print(url_list) 138 kazu = (len(url_list)) #判定 139 140 #print (kazu) 141 142 if kazu == 0: #URL数が0だった時、エラーを出す。 143 error = "urlzeroerror" 144 # ※即座に抜けて、if文のネストを減らす 145 return 146 tdo = url_list 147 # ※リスト内の重複を削除 148 url_list = list(set(url_list)) 149 # ※url_listの内容に対してリクエスト! 150 dl.request(url_list) 151 152 153def main() ->None: 154 root = tk.Tk() 155 # ウィンドウのタイトルを設定 156 root.title("フリー画像ダウンローダ -ver1.0_beta") 157 # ウィンドウの大きさを指定 158 root.geometry("800x500") 159 f = MyFrame(root) 160 root.mainloop() 161 162 163if __name__ == '__main__': 164 main() 165

◇参考情報
0. 17.4. concurrent.futures – 並列タスク実行
0. MIME タイプ

投稿2018/04/21 20:21

編集2018/04/22 19:10
umyu

総合スコア5846

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

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

T_www

2018/04/22 07:19

柔軟性を向上すべく params = {'n': '60', 'p': "草", 'search.x': '1'} の部分の"草"を変数にしてみましたが、うまく動きません。 エラーは出ないのですが、どうすれば動くのでしょう...(泣
umyu

2018/04/22 07:39

>T_wwwさんへ どういう処で詰まってるのか、分かりませんでしたが、tk.StringVarとtk.Entryを使った画面から検索キーワードを渡すサンプルコードです。変更差分ですが、私が書いたコードをPyCharmのLocal History機能で差分が分かるかと。PyCharmのCommunity Editionは無料なので、導入することをお勧め致します。
T_www

2018/04/22 08:34 編集

Entryのワードを変えて見たところ Exception in thread Thread-1: Traceback (most recent call last): File "C:\Users\xxxx\AppData\Local\Programs\Python\Python36-32\lib\threading.py", line 916, in _bootstrap_inner self.run() File "C:\Users\xxxx\AppData\Local\Programs\Python\Python36-32\lib\threading.py", line 864, in run self._target(*self._args, **self._kwargs) TypeError: hack() takes 1 positional argument but 4 were given のようになりました。どのようなことなのでしょう google先生に翻訳してもらったんです。↓ 402/5000 スレッドの例外Thread-1: トレースバック(直近の最後のコール): ファイル "C:¥Users¥xxxx¥AppData¥Local¥Programs¥Python¥Python36-32¥lib¥threading.py"、行916、_bootstrap_inner self.run() ファイル "C:\ Users \ xxxx \ AppData \ Local \ Programs \ Python \ Python36-32 \ lib \ threading.py"、行864、実行中 self._target(* self._args、** self._kwargs) TypeError:hack()は1つの位置引数を取るが、4つは与えられた
umyu

2018/04/22 13:18

>T_wwwさんへ 質問文を編集して現状のソースコードを貼ってくださいな。
T_www

2018/04/22 13:20

あ、あの、このページのソースコードです(教えてくれたやつです)。
umyu

2018/04/22 13:22

うーんと、手順としては画面のテキストボックスを変更して探すボタンをクリックですよね?
T_www

2018/04/22 13:23

そうです。
umyu

2018/04/22 13:26

回答文のコードのdef hack(search_word: str):こうなってるのでー MyFrameのdef search(self):が search_word = self.key_word.get() t = Thread(target=hack,args=search_word) こうなのですがー
umyu

2018/04/22 13:26

あ、変数 tのしたに t.start()がありますが
umyu

2018/04/22 13:31

と、話がそれてしまいました、質問のエラーメッセージとしてはt = Thread(target=hack,args=search_word) の部分でargsオプションに引数を渡してますが、関数:hackの定義が引数1個しかないというメッセージです。
umyu

2018/04/22 13:33

def search(self): search_word = self.key_word.get() print(len(search_word)) このprintが1になると思いますが。
umyu

2018/04/22 13:35

あああ、入力キーワードに, (カンマ)が入ってませんか?
umyu

2018/04/22 13:36

いや、違いますね、なんとなく再現したので、直してみます。失礼しました。
T_www

2018/04/22 13:36

入れておりません(´・ω・`)
umyu

2018/04/22 13:38

def search(self): search_word = self.txt_key_word.get() # ※画面をブロックさせないためにスレッドを生成して、startを呼び出す。 t = Thread(target=hack, args=(search_word,)) t.start()
umyu

2018/04/22 13:40

>< 修正してみましたが、どーでしょうか?お手数をかけてすみませぬ。
T_www

2018/04/22 13:44

す、すごい!こんな初心者を手伝ってくれてありがとうございました。
umyu

2018/04/22 13:48

で、バグ(不具合)を入れちゃったのですが、原因は引数argsの渡しかたでした。 tupleをargsに渡す必要があったのが、文字列を渡して、文字列の長さになっていたと思います。 args=(search_word,) args=search_word
T_www

2018/04/22 13:54

なるほど(凄い
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問