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

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

新規登録して質問してみよう
ただいま回答率
85.51%
スクレイピング

スクレイピングとは、公開されているWebサイトからページ内の情報を抽出する技術です。

Python 3.x

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

Q&A

解決済

3回答

7641閲覧

Python スクレイピング for文の高速化したい

RWW

総合スコア13

スクレイピング

スクレイピングとは、公開されているWebサイトからページ内の情報を抽出する技術です。

Python 3.x

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

0グッド

0クリップ

投稿2018/04/19 04:59

Pythonにてブランドサイトから、商品情報を抽出し保存するコードを書きました。
プログラミング初心者ながら、やっと完成したのですが
最後のエクセルへの書き込みと画像の保存の処理を行う度にループする速度が遅くなってしまいます。
原因と解決方法がありましたら、教えていただきたいです。

Python

1import requests 2from bs4 import BeautifulSoup 3import pprint 4import os 5from urllib.parse import urljoin 6import itertools 7import re 8import time 9import xlsxwriter 10 11from selenium import webdriver 12driver= webdriver.Chrome("/Users/AA/Downloads/chromedriver") 13 14sex_URL = "https://www.gucci.com/jp/ja/ca/men-c-men" 15soup = BeautifulSoup(requests.get(sex_URL).content,'lxml') 16 17#カテゴリ毎のURLを取得し、相対パスを絶対パスに変換 18#category_listにURLを格納 19base = "https://www.gucci.com/jp/ja/" 20category_link = soup.find_all("a",class_="category-product") 21category_list = [] 22for category_link in category_link: 23 category_list.append(urljoin(base,category_link.get("href"))) 24print(category_list) 25 26#商品カテゴリ名を取得し、category_name_listに格納 27category_name = soup.select("header > h2") 28category_name_list = [] 29for category_name in category_name: 30 category_name_list.append((category_name).getText()) 31print(category_name_list) 32 33#category_listとcategory_name_listの2つのリストを1つのディクショナリに変換 34keys = category_name_list 35values = category_list 36dic = dict(zip(keys,values)) 37print(dic) 38 39for category in dic: 40 #カテゴリURL毎に分割されている全てのURLを取得する 41 url = dic[category] 42 url_list = [url] 43 driver.implicitly_wait(10) 44 driver.get(url) 45 cur_url= driver.current_url 46 n = 1 47 while url == cur_url: 48 url = dic[category] 49 url = url + "/" + str(n) 50 driver.get(url) 51 cur_url= driver.current_url 52 url_list.append(url) 53 n += 1 54 url_list.pop() 55 #ここまで 56 for p in url_list: 57 soup_1 = BeautifulSoup(requests.get(p).content,'lxml') 58 item_list=[] 59 item_link = soup_1.find_all("a",class_="product-tiles-grid-item-link") 60 for item_link in item_link: 61 #商品URLの相対パスを絶対パスに変換し、item_listに格納 62 item_list.append(urljoin(base,item_link.get("href"))) 63 #商品毎の名前、金額、商品説明を取得 64 for i in item_list: 65 soup_2 = BeautifulSoup(requests.get(i).content,'lxml') 66 #商品名 67 item_title = soup_2.select_one("section > h1").text 68 #商品金額(日本円) 69 item_price = soup_2.select_one("#markedDown_full_Price").text 70 #商品金額(フランス) 71 fr_url = i.replace("jp/ja", 'fr/fr') 72 soup_3 = BeautifulSoup(requests.get(fr_url).content,'lxml') 73 try: 74 item_price_fr= soup_3.select_one("#markedDown_full_Price").text 75 except AttributeError: 76 item_price_fr = "フランスのサイトが存在しませんでした" 77 #商品詳細 78 item_detail = soup_2.find(class_="product-detail").text 79 #フォルダを作成 80 os.makedirs("/Users/RP/Desktop/GUCCI/メンズ/" + category +"/"+ item_title ,exist_ok=True) 81 82 #エクセルファイルを作成 83 workbook = xlsxwriter.Workbook("/Users/RP/Desktop/GUCCI/メンズ/" + category +"/"+ item_title + "/" + "detail.xlsx") 84 worksheet = workbook.add_worksheet("Sheet1") 85 worksheet.set_column('B:B', 90) 86 worksheet.write('A1', '商品URL') 87 worksheet.write('A2', 'カテゴリー名') 88 worksheet.write('A3', '商品名') 89 worksheet.write('A4', '商品金額(円)') 90 worksheet.write('A5', '商品金額(€)') 91 worksheet.write('A6', '商品詳細') 92 93 worksheet.write('B1', i) 94 worksheet.write('B2', category) 95 worksheet.write('B3', item_title) 96 worksheet.write('B4', item_price) 97 worksheet.write('B5', item_price_fr) 98 worksheet.write('B6', item_detail) 99 workbook.close() 100 101 #画像取得 102 img = [] 103 img_url = soup_2.select("#carousel-vertical > div.product-detail-carouse-vertical-inner.carousel-vertical-inner.carousel-inner picture > source") 104 for url in img_url: 105 img_url = urljoin(base,url.get("srcset")) 106 img.append(img_url) 107 for target in img: # imgからtargetに入れる 108 re = requests.get(target) 109 with open("/Users/RP/Desktop/GUCCI/メンズ/" + category +"/"+ item_title + "/" +target.split('/')[-1], 'wb') as f: # imgフォルダに格納 110 f.write(re.content) # .contentにて画像データとして書き込む 111 time.sleep(1)

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

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

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

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

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

guest

回答3

0

ベストアンサー

力作ですねー。。

1,変数:item_listは不要ではないでしょうか?
以下の処理だとitem_linkのループ分 item_listに要素を追加してしまいます。

Python

1 item_list = [] 2 item_link = soup_1.find_all("a", class_="product-tiles-grid-item-link") 3 for item_link in item_link: 4 # 商品URLの相対パスを絶対パスに変換し、item_listに格納 5 item_list.append(urljoin(base, item_link.get("href"))) 6 # 商品毎の名前、金額、商品説明を取得 7 for i in item_list: 8

2,urlを取り扱う時は重複値を扱える Listではなく重複なしの setで扱ってくださいな。
listsetの違いは検索サイトで検索するとHITするかと。

Python

1item_list = [] 2item_link = soup_1.find_all("a", class_="product-tiles-grid-item-link") 3for item_link in item_link: 4 # 商品URLの相対パスを絶対パスに変換し、item_listに格納 5 item_list.append(urljoin(base, item_link.get("href")))

Python

1item_list = set() 2item_link = soup_1.find_all("a", class_="product-tiles-grid-item-link") 3for item_link in item_link: 4 # 商品URLの相対パスを絶対パスに変換し、item_listに格納 5 item_list.add(urljoin(base, item_link.get("href")))

3,全般的に個々の処理を関数化することをオススメします。これはデバックとテストをしやすさの向上のためです。

例えば、エクセルファイル書き込み処理なら

Python

1def create_excel(i, category, item_title, item_price, item_price_fr, item_detail): 2 workbook = xlsxwriter.Workbook( 3 "/Users/RP/Desktop/GUCCI/メンズ/" + category + "/" + item_title + "/" + "detail.xlsx") 4 worksheet = workbook.add_worksheet("Sheet1") 5 worksheet.set_column('B:B', 90) 6 worksheet.write('A1', '商品URL') 7 worksheet.write('A2', 'カテゴリー名') 8 worksheet.write('A3', '商品名') 9 worksheet.write('A4', '商品金額(円)') 10 worksheet.write('A5', '商品金額(€)') 11 worksheet.write('A6', '商品詳細') 12 13 worksheet.write('B1', i) 14 worksheet.write('B2', category) 15 worksheet.write('B3', item_title) 16 worksheet.write('B4', item_price) 17 worksheet.write('B5', item_price_fr) 18 worksheet.write('B6', item_detail) 19 workbook.close()

Python

1#呼び出しかた 2create_excel(i, category, item_title, item_price, item_price_fr, item_detail)

関数化するとスクレイピングを行わなくても、create_excelを呼び出せば、テストできます。
こうすることで、スクレイピングの問題なのか、エクセルファイル書き込みの問題なのかの問題切り分けが可能になります。

高速化の基本は処理に時間が掛かっているところ(ボトルネック)を特定するところからかと
cProfileSnakevizを使って時間が掛かっている所を可視化する事をお勧めします。

投稿2018/04/19 06:05

編集2018/04/19 06:16
umyu

総合スコア5846

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

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

RWW

2018/04/19 09:47

ご丁寧にありがとうございます!自分なりに、修正してみます!
guest

0

おそらくなのですが、

python

1#エクセルファイルを作成 2 workbook = xlsxwriter.Workbook("/Users/RP/Desktop/GUCCI/メンズ/" + category +"/"+ item_title + "/" + "detail.xlsx")

の行を

python

1 for item_link in item_link:

の上に移動しまして、

python

1 #画像取得 2 img = [] 3 img_url = soup_2.select("#carousel-vertical > div.product-detail-carouse-vertical-inner.carousel-vertical-inner.carousel-inner picture > source") 4 for url in img_url: 5 img_url = urljoin(base,url.get("srcset")) 6 img.append(img_url) 7 for target in img: # imgからtargetに入れる 8 re = requests.get(target) 9 with open("/Users/RP/Desktop/GUCCI/メンズ/" + category +"/"+ item_title + "/" +target.split('/')[-1], 'wb') as f: # imgフォルダに格納 10 f.write(re.content) # .contentにて画像データとして書き込む 11 time.sleep(1)

この部分を、

python

1 #画像取得 2 img = [] 3 img_url = soup_2.select("#carousel-vertical > div.product-detail-carouse-vertical-inner.carousel-vertical-inner.carousel-inner picture > source") 4 for url in img_url: 5 img_url = urljoin(base,url.get("srcset")) 6 img.append(img_url) 7 with open("/Users/RP/Desktop/GUCCI/メンズ/" + category +"/"+ item_title + "/" +target.split('/')[-1], 'wb') as f: # imgフォルダを開く 8 for target in img: # imgからtargetに入れる 9 re = requests.get(target) 10 f.write(re.content) # .contentにて画像データとして書き込む 11 time.sleep(1)

こう書き直すと、必要以上にファイルを開く処理や、Excelファイルを展開する処理が減ると思います。

P.S.

ファイルを開いたりする処理は極力1回だけ実行するように心がけ、for文やwhile文の中では実行しないようにするのがいいと思います。

投稿2018/04/19 05:18

manzyun

総合スコア2244

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

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

RWW

2018/04/19 05:40

ありがとうございます。必要以上にファイルを展開する処理が多くなると遅くなるのですね。勉強になりました。参考にさせていただきます。
guest

0

time.sleep(1)を入れる場所がおかしくないですか。webへの連続アクセスを回避したいのだと思いますが、この位置だと、ループの奥にありすぎるので無駄に足踏みを続けそうな気がします。

投稿2018/04/19 05:20

KojiDoi

総合スコア13669

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

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

RWW

2018/04/19 05:41

ご回答ありがとうございます。もしよろしければ、どの位置に入れればいいか教えていただけると幸いです。
KojiDoi

2018/04/19 05:47

webにアクセスした直後。
KojiDoi

2018/04/19 05:54

これに限らず、ループの外で一回実行しておけばいい事をループのなかで繰返していないか再検討して、 外に出せる物は外に出す。 この原則に従って数行修正するだけで、全体の所要時間が数十分の一に減ることもあります。
RWW

2018/04/19 09:46

ありがとうございます!修正してみます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.51%

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

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

質問する

関連した質問