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

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

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

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

Q&A

解決済

1回答

3710閲覧

Python3で発生したエラー:AttributeError: 'str' object has no attribute 'text'について

shohei_mlb

総合スコア9

Python

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

0グッド

0クリップ

投稿2019/12/13 06:03

編集2019/12/13 06:05

#前提・実現したいこと
食べログから福岡市の全ラーメン店の店舗名・食べログ点数・口コミ件数・口コミを取得したい。

#発生している問題・エラーメッセージ
ページ指定を1ページの場合、全データ取得できます。しかし、for page in range(1,10)のように2ページ以上にすると、下記のようなエラーが発生します。

python

1Traceback (most recent call last): 2 File "scraping_ramen.py", line 51, in <module> 3 review_cnt = review_count.text 4AttributeError: 'str' object has no attribute 'text'

#該当のソースコード

python

1import requests 2from bs4 import BeautifulSoup 3import pandas as pd 4import time 5 6list_df = pd.DataFrame(columns=['店舗名', '食べログ点数', '口コミ件数','口コミ']) 7 8score_list = [] 9store_list = [] 10link_list = [] 11 12#店舗一覧ページ 13#for page in range(1): 14for page in range(1, 10): 15 url = 'https://tabelog.com/fukuoka/C40130/rstLst/ramen/' + str(page) + '/?sk=%E3%83%A9%E3%83%BC%E3%83%A1%E3%83%B3&svd=20191008&svt=1900&svps=2' 16 response = requests.get(url) 17 soup = BeautifulSoup(response.text, 'lxml') 18 #店舗一覧ページから食べログスコア一覧を取得 19 score_tags = soup.find_all('span', class_='list-rst__rating-val') 20 for score in score_tags: 21 #食べログスコア一覧が格納されたリスト作成 22 score_list.append(score.text) 23 24 #店舗一覧ページから店舗名一覧を取得 25 store_tags = soup.find_all('a', class_='list-rst__rst-name-target cpy-rst-name') 26 for store_tag in store_tags: 27 #店舗詳細ページのリンクが格納されたリスト作成 28 link_list.append(store_tag.get('href')) 29 #店舗名一覧が格納されたリスト作成 30 store_name = store_tag.text 31 store_name = store_name.replace(' ', '') 32 store_list.append(store_name) 33 34 for score, store_name, link in zip(score_list, store_list, link_list): 35 if not score == '-': 36 #食べログスコアが3.5以上の店舗のみ、店舗詳細ページにアクセス 37 if float(score) > 3.5: 38 response = requests.get(link) 39 soup = BeautifulSoup(response.text, 'lxml') 40 #口コミ一覧ページのリンクを取得 41 review_tag_id = soup.find('li', id='rdnavi-review') 42 review_tag_href = review_tag_id.a.get('href') 43 44 #口コミ一覧ページ 45 response = requests.get(review_tag_href) 46 soup = BeautifulSoup(response.text, 'lxml') 47 #口コミ件数取得 48 review_counts = soup.find('li', id='rdnavi-review') 49 review_count = review_counts.find('span', class_='rstdtl-navi__total-count') 50 review_cnt = review_count.text 51 52 #口コミ詳細ページのリンク取得 53 review_comments = soup.find_all('a', class_='rvw-item__title-target') 54 for review_comment in review_comments: 55 56 #口コミ詳細ページ 57 response = requests.get('https://tabelog.com' + review_comment.get('href')) 58 soup = BeautifulSoup(response.text, 'lxml') 59 #口コミ取得 60 review_tags = soup.find_all('div', class_='rvw-item__rvw-comment') 61 review = review_tags[0].p.text.encode('cp932', 'ignore') 62 review = review.decode('cp932') 63 review = review.replace('\n','') 64 review = review.replace(' ','') 65 review = review.replace(' ','') 66 67 #取得した項目 68 #store_name = 店舗名 69 #score = 食べログ点数 70 #review_cnt = 口コミ件数 71 #review = 口コミ 72 tmp_se = pd.DataFrame([store_name, score, review_cnt, review], index=list_df.columns).T 73 list_df = list_df.append(tmp_se) 74 75print(list_df) 76 77#csv保存 78list_df.to_csv('list_ramen.csv', mode = 'a', encoding='cp932')

#解析対象となるHTML

HTML

1<li id="rdnavi-review" class="rstdtl-navi__list-item js-rstdtl-navi-list-item"> 2 <div class="rstdtl-navi__list-item-inner"> 3 <a class="mainnavi" href="https://tabelog.com/fukuoka/A4001/A400102/40007006/dtlrvwlst/"><span>口コミ</span><span class="rstdtl-navi__total-count"><em>174</em></span></a> 4 <ol class="js-rstdtl-navi-sublist rstdtl-navi__sublist"> 5 <li class="rstdtl-navi__sublist-item"> 6 <a href="https://tabelog.com/fukuoka/A4001/A400102/40007006/dtlrvwlst/" id="review"> 7 <span class="rstdtl-navi__sublist-item-genre">口コミ<span class="rstdtl-navi__sublist-item-count">(<em>174</em>)</span></span> </a> 8 </li>

#試したこと
・review_count.textをreview_count.stringに変換。結果は変わりませんでした。
・review_count.textを避けるため、review_cnt = review_counts.find('span', class_='rstdtl-navi__total-count').textに変えましたが、結果は変わりませんでした。

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

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

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

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

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

shiracamus

2019/12/13 06:11

エラー行の直前に print(type(review_count), review_count) を入れて変数の内容を確認してみるとどうなりますか?
shohei_mlb

2019/12/13 06:20

<class 'bs4.element.Tag'> <span class="rstdtl-navi__total-count"><em>174</em></span>になりました。
shiracamus

2019/12/13 06:55

それが表示された直後にエラーで落ちるのですか?
shiracamus

2019/12/13 07:28

試してみたところ、 <span class="rstdtl-navi__total-count"> のない口コミがあって、count が None になる場合があるようですよ。 None ならスキップする処理が必要なのでは?
shohei_mlb

2019/12/14 02:23

ご教授していただきありがとうございます。取得できました。 review_cnt = review_count.text if review_cnt is not None: review_cnt = review_cnt
siruku6

2019/12/21 08:17

解決していれば解決済みにしていただけるとよいかと思いました。 他の質問が埋もれてしまうため。
guest

回答1

0

自己解決

review_cnt = review_count.text
if review_cnt is not None:
review_cnt = review_cnt

投稿2019/12/21 15:45

shohei_mlb

総合スコア9

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問