sakihokusho
@sakihokusho

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

Pythonのスクレイピング(SUUMOから物件情報を取り出す)はうまくいかない

解決したいこと

SUUMOから物件情報をスクレイピングしたいのですが、どうしても途中で”ページを表示できません”となってしまいます。
最初の数ページ分の情報を取り出せているので、コード自体に間違いはないと思うのですが…
超初心者が見様見真似で始めたものなので、原因が思い当たらず困っております。

発生している問題・エラー

AttributeError                            Traceback (most recent call last)
<ipython-input-49-ccef615dab50> in <module>
     32     soup = BeautifulSoup(c, "html.parser")
     33     summary = soup.find("div",id ='js-bukkenList')
---> 34     houses = summary.find_all('li', class_='cassette js-bukkenCassette')
     35 
     36     for house in houses:

AttributeError: 'NoneType' object has no attribute 'find_all'

または、問題・エラーが起きている画像をここにドラッグアンドドロップ。

該当するソースコード

!pip install beautifulsoup4
from bs4 import BeautifulSoup
import re
import requests
import time
import pandas as pd
!pip install lxml
print('done')

url = 'https://suumo.jp/jj/common/ichiran/JJ901FC004/?initFlg=1&seniFlg=1&ar=030&ta=13&scTmp=13103&scTmp=13109&scTmp=13110&scTmp=13111&scTmp=13112&scTmp=13113&ct=9999999&cb=0.0&kt=8000&kb=0&xt=9999999&xb=60&md=7%2C8%2C9&md=10%2C11%2C12&md=13&et=7&cn=25&newflg=0&km=1&sc=13103&sc=13109&sc=13110&sc=13111&sc=13112&sc=13113&bs=010&bs=011&bs=020&bs=021&pc=100'
result = requests.get(url)
c = result.content
soup = BeautifulSoup(c,"html.parser")

summary = soup.find("div",{'id':'js-bukkenList'})
body = soup.find("body")
pages = body.find_all("div", {'class':'pagination pagination_set-nav'})
pages_text = str(pages)
pages_split = pages_text.split('</a></li></ol>')
num_pages = int(pages_split[0].split('>')[-1])
print("ページ数=",num_pages)
urls = []
urls.append(url)

for i in range(num_pages - 1):
    page_num = str(i + 2)
    url_page = url + '&pn=' + page_num
    urls.append(url_page)

data = []

jenre = '' #物件タイプ
name = '' #物件名
price = '' #購入価格
address = '' #住所
station = '' #最寄駅
walk = '' #バス徒歩
area = '' #土地面積
building = '' #建物面積
floor_plan = '' #間取り
monthly = '' #月々の支払い
age = '' #築年数
link = '' #リンク
kanrihi = '' #管理費
shuzenhi = '' #修繕積立費
reform = '' #リフォーム
total_units = '' #総戸数
right_form = '' #権利形態
right_district = '' #用途地域
parking = '' #駐車場

for url in urls:

    result = requests.get(url)
    c = result.content
    soup = BeautifulSoup(c, "html.parser")
    summary = soup.find("div",id ='js-bukkenList')
    houses = summary.find_all('li', class_='cassette js-bukkenCassette')

    for house in houses:            
        jenre = house.find_all('span', class_='ui-pct ui-pct--util1 cassettebox-hpct cassettebox-hpctcat')[0].string
        name = house.find_all("a", class_='js-cassetLinkHref')[0].string
        price = house.find_all('dd', class_="infodatabox-details-txt")[0].string
        address = house.find_all('div', class_='infodatabox-box-txt')[0].string
        station = house.find_all('div', class_='infodatabox-box-txt')[1].string
        walk = house.find_all('div', class_='infodatabox-box-txt')[2].text
        area = house.find_all('dd', class_="infodatabox-details-txt")[2].text

        detail = house.find_all('div', class_='infodatabox-box-txt')[4]
        cols = detail.find_all('dd', class_='infodatabox-details-txt')
        for i in range(len(cols)):
            if len(cols) == 2:
                building = detail.find_all('dd', class_='infodatabox-details-txt')[0].string
                floor_plan = detail.find_all('dd', class_='infodatabox-details-txt')[1].string
            elif len(cols) == 3:
                building = detail.find_all('dd', class_='infodatabox-details-txt')[1].text
                floor_plan = detail.find_all('dd', class_='infodatabox-details-txt')[2].string

        monthly = house.find_all('dd', class_="infodatabox-details-txt")[1].string
        age = house.find_all('div', class_='infodatabox-box-txt')[5].string
        linkbox = house.find('div', class_='cassettebox-action')
        linked = linkbox.find('a')
        links = linked.get('href')
        link = 'https://suumo.jp' + links


        link_child = link + 'bukkengaiyo/'
        result_child = requests.get(link_child)
        c_child = result_child.content
        soup_child = BeautifulSoup(c_child, 'html.parser')
        summary_child = soup_child.find_all('tbody',{'class':'vat tal'})

        try:
            kanrihi = summary_child[0].find_all('td')[5].string.strip('\r\n\t')
            shuzenhi = summary_child[0].find_all('td')[6].string.strip('\r\n\t')
            reform = summary_child[0].find_all('td')[16].contents
            total_units = summary_child[1].find_all('td')[2].string.strip('\r\n\t')
            right_form  = summary_child[1].find_all('td')[5].string.strip('\r\n\t')
            right_district = summary_child[1].find_all('td')[6].string.strip('\r\n\t')
            parking = summary_child[1].find_all('td')[7].string.strip('\r\n\t')    
        except:
            pass

        string = [jenre, name, price, address, station, walk, area, building, floor_plan, monthly, age, link, kanrihi, shuzenhi, reform, total_units, right_form, right_district, parking]
        data.append(string)

    time.sleep(1)

df = pd.DataFrame(data, columns=['物件タイプ','物件名','購入金額','住所','最寄駅','バス徒歩','土地面積','建物面積','間取り','月々支払額','築年数','URL','管理費','修繕積立費','リフォーム','総戸数','権利形態','用途地域','駐車場'])
df.to_csv('suumo_scrape.csv', sep=',', encoding='utf-8', header=True, index=False)

自分で試したこと

物件の詳細ページを開いてさらに情報を取り出す行程(link_child = link + ...以降の部分)を加える前は、情報を取り出してCSV形式で保存するところまで問題なく完了できたのですが、件のコードを追加してからは途中までしかスクレイピングが進まず、途方に暮れております。

0

2Answer

実際に動かしてみましたが、いくつが要因がありそうです。
厳密には見ていないので正確じゃない部分があるかもしれません。

find_allを.stringでとると、タグが含まれている場合に、Noneになります。
.textでとるとタグを除去したものが取れるようです。
.stringはすべて.text.strip()にしてしまって問題ないと思います。
(参考)Beautiful Soupで.stringを使うとNoneになってしまう時の解消法

for i in range(len(cols)):の部分ですが、<dd>タグの数が2または3になるのを分岐したいだけと思うので、for文は不要だと思います。

ここまでで一応全部とれるはず。
あとは、print()などでデバッグしてみてください。途中からデータ構造が変わっていて、内容がおかしくなります。try~exceptはとりあえず走らせるために入れていると思いますが、きちんと分岐処理入れれば全部とれるのではないかと思います。

最後にsleepですが、サーバーの負荷軽減が目的なら、link_childで毎回読むのでdata.append(string)するごとに入れたほうがいいのかなと思いました。

あと、関係ないですけど、記事のタグはカンマではなくスペース区切りです。

2Like

Comments

  1. @sakihokusho

    Questioner

    具体的なご指摘ありがとうございます!
    コードに反映させて頂きます。
    ただ、ページがエラーになるのはJavascriptの問題だったようなので、Seleniumをインストールして問題解決を図りたいと思います(インストールエラーで詰まっていますが)。

以前同じような処理を実装した際に同様のエラーが発生した経験がありますが、
エラーが起こっているページの物件情報についてページの構成が異なっていることが原因かと思われます。

ログなどでエラーとなっているページのURLを取得し、実際にブラウザで確認されることをおすすめします。
物件により様々な表示パターンがあるため、最終的には想定外のページ構成の場合にエラーハンドリングができるような実装に変更することになるかと思います。

1Like

Comments

  1. @sakihokusho

    Questioner

    コメントありがとうございます!
    おすすめ頂いた通り、エラーとなっているページのURL先を見たところ、Javascriptが有効化されていない(”ページが表示できません”)となっていたので、Seleniumなどでなんとかする必要がありそうでした。
    やるべき事が見えてきました、ご助言ありがとうございます!

Your answer might help someone💌