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

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

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

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

Beautiful Soup

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

スクロール

スクロールとは、ディスプレイスクリーン上において連続的にコンテンツが滑っていくことを指します。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

1144閲覧

Python スクレイピング件数が複数にまたがるときの条件分岐

yoshicue

総合スコア8

スクレイピング

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

Beautiful Soup

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

スクロール

スクロールとは、ディスプレイスクリーン上において連続的にコンテンツが滑っていくことを指します。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2021/10/27 07:00

pipでインストールする部分は省きますが、
下記が初心者なりになんとか実行できたコードになります。

コード

import requests from bs4 import BeautifulSoup url = 'https://el.e-shops.jp/local/jb/6008/jn/6000523/cn/23109/' res = requests.get(url) soup = BeautifulSoup(res.text,'html.parser') import re companies = [element.text for element in soup.find_all('a',href=re.compile("^/local/nsh/"))] list_address = soup.find_all('p', attrs = {'class':'shop_address'}) shop_address = [e.text for e in soup.find_all('p',attrs = {'class':'shop_address'})] list_tel = soup.find_all('p', attrs = {'class':'shop_tel'}) shop_tel = [e.text for e in soup.find_all('p', attrs = {'class':'shop_tel'})] import pandas as pd Coulumn1 = ['社名'] df1 = pd.DataFrame(companies,columns=Coulumn1) Coulumn2 = ['住所'] df2 = pd.DataFrame(shop_address,columns=Coulumn2) Coulumn3 = ['TEL'] df3 = pd.DataFrame(shop_tel,columns=Coulumn3) df4 = df1.join(df2) df5 = df4.join(df3) df5

目的は会社名と住所とTELをもれなくExcelに落とし込むことですが、
対処のURLで熱田区の切削加工だと39件ヒットするので、
ページが2つ以上にまたがります。

個人的な考えでは、
pguiを利用した座標の取得で「加工方法(件数)」のところの件数の数字部分のテキストを読み取って、
例えば、20以上ならスクロールして、次のページボタンをクリックするところを座標で取得する。
20以下なら次の加工方法のボタンの座標を取得してクリックする。
というものです。
スクレイピング自体がサーバーに負荷をかける行為だとは理解しているので
区単位で、特に欲しい加工技術を持った会社一覧(切削加工や金属加工、鉄鋼工業など)を全てまとめて読み取って、
次の区にページを切り替えて
の繰り返しでやるという想定でいます。

もっと別の方法をご存じでしたらご教授お願い致します。

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

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

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

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

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

guest

回答1

0

ベストアンサー

2ページ目のURLを見てみるとhttps://el.e-shops.jp/local/jb/6008/jn/6000523/cn/23109/2.htmlのように末尾に2.htmlが付いています。別の区の3ページ目も確認すると末尾が3.htmlでした。

ということはbase_urlhttps://el.e-shops.jp/local/jb/6008/jn/6000523/cn/23109/とすると、2ページ目はbase_url + '2.html'、3ページ目はbase_url + '3.html'……となっているわけです。

そして、最後のページの次のページ(例えばhttps://el.e-shops.jp/local/jb/6008/jn/6000523/cn/23109/3.html)を見てみると、.list-tel-shopという要素がないページが表示されます。

ここまでのことから、順番にURLを変えてアクセスしていって.list_tel_shopが取得できなくなったらその区はおわり、という判断の仕方ができます。

コードに落とし込むと、こんな感じでしょうか。

python

1import requests 2import re 3from bs4 import BeautifulSoup 4 5def get_shops_at_page(base_url, n): 6 """ある区のn番目のページにあるすべてのlist_tel_shopを返す""" 7 url = f"{base_url}{str(n)}.html" if n > 1 else base_url 8 res = requests.get(url) 9 soup = BeautifulSoup(res.text, 'html.parser') 10 return soup.find_all('div', attrs={'class': 'list_tel_shop'}) 11 12def get_shops(base_url): 13 """ある区のすべてのlist_tel_shopを返す 14 返値は [{'name': '...', 'address': '...', 'tel': '...'}, {...}, ...] 15 """ 16 shops = [] 17 n = 1 18 # get_shops_at()が[]を返すまでどんどん次のページの情報を取得する 19 while True: 20 shop_els = get_shops_at_page(base_url, n) 21 if not shop_els: 22 break 23 for shop_el in shop_els: 24 # 以下、shop_el.find_all()でないのは「shop_el」つまり「.list_tel_shop」に 25 # 「.shop_address」や「.shop_tel」といった要素が1つづつしか存在しないため 26 shop = {} 27 name = shop_el.find('a', href=re.compile("^/local/nsh/")) 28 if name: 29 shop['name'] = name.text 30 address = shop_el.find('p', attrs={'class': 'shop_address'}) 31 if address: 32 shop['address'] = address.text 33 tel = shop_el.find('p', attrs={'class':'shop_tel'}) 34 if tel: 35 shop['tel'] = tel.text 36 shops.append(shop) 37 n += 1 38 return shops 39 40# 複数の区の情報を得るなら以下のように使う 41 42def flatten(xs): 43 return list(itertools.chain.from_iterable(xs)) 44 45urls = [ 46 'https://el.e-shops.jp/local/jb/6008/jn/6000523/cn/23109/', 47] 48 49# [ [{...}, ...], [{...}, ...], ... ]になるのでflattenして[{...}, {...}, ...]に 50shops = flatten([get_shops(url) for url in urls])

get_shops()ではshopごとに{'name': '...', 'address': '...', 'tel': '...'}という辞書を作ってそのリストを返すようにしています。

name/address/telそれぞれのリストがほしければ以下のようにしましょう。

python

1names = [shop['name'] for shop in shops] 2address = [shop['address'] for shop in shops] 3tels = [shop['tel'] for shop in shops]

これらを一列づつ追加してもいいですが、一気にpd.Dataframeにした方がいい気がします。

python

1import pandas as pd 2 3# [[shopの社名, shopの住所, shopのTEL], [...], ...]に変換 4data = [[shop['name'], shop['address'], shop['tel']] for shop in shops] 5df = pd.DataFrame(data, columns=['社名', '住所', 'TEL'])

投稿2021/10/27 07:58

編集2021/10/31 03:26
fj68

総合スコア752

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

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

yoshicue

2021/10/31 02:32

ご回答ありがとうございます。問題なく、複数ページにまたがる分も取得することができました。 最後のコードですが、文法エラーが返ってきてしまいます。 import pandas as pd # [[shopの社名, shopの住所, shopのTEL], [...], ...]に変換 data = [[shop['name'], shop['address'], shop['tel'] for shop in shops] df = pd.DataFrame(data, columns=['社名', '住所', 'TEL']) で、data = の一文が引っ掛かります。 [が一つ余分なのかなと思いましたが、うまくいきません。 ご確認お願い致します。
fj68

2021/10/31 03:26 編集

あ、そうですね、すみません。 逆に、「]」が一つ足りないようです。 直しておきますね。 ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問