yuutyoko129
@yuutyoko129

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のスクレイピングコードについてアドバイス下さい

解決したいこと

個人のプログラミング学習に使用します。

Pythonで食べログからお店情報を抽出し、CSVに落とし込むというコードを作成しました。
実行結果は思った通りになったのですが、かなり長ったらしいコードになり、本当にこのコードが最適解なのか?と思いご質問させて頂きました。

「for文で回し、1つずつ辞書に格納する」というフェーズは崩したくありません。(それ以外の知識がないため)
それ以外で、if文のところなどが自己流で作成したので、正しいか不安です。

エラーというより、添削のご依頼に近いかもしれませんが、ご教示頂けますと幸いです。

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

特になし

該当するソースコード

import requests
from bs4 import BeautifulSoup
from time import sleep
from pprint import pprint

import pandas as pd
import re
import time


# 時間計測開始
time_sta = time.perf_counter()

#URlとHTMLデータ取得
url = "https://tabelog.com/hokkaido/C1100/rstLst/{}/?Srt=D&SrtT=rt&sort_mode=1&svd=20230717&svt=1900&svps=2"

d_list = []

for i in range(1,61):
    target_url = url.format(i)

    r = requests.get(target_url)
    soup = BeautifulSoup(r.text,"html.parser")

    sleep(1)

    #ページから店舗一覧取得
    shops = soup.find_all("div",class_="list-rst__wrap js-open-new-window"

    #一つ目の店舗情報を元に、全ての店舗情報を取得 ←気になっている部分
    for shop in shops:    

      if float(shop.find("span",class_="c-rating__val").text) >= 3.5:
            if shop.find("div",class_="list-rst__pr") and shop.find("span",class_="list-rst__holiday-text"):
                name = shop.find("a",class_="list-rst__rst-name-target").text
                acsess = shop.find("div",class_="list-rst__area-genre").text.strip()
                strengths = shop.find("div",class_="list-rst__pr").text.strip()
                evaluation = shop.find("span",class_="c-rating__val").text
                reviews = shop.find("em",class_="list-rst__rvw-count-num").text
                bookmark = shop.find("span",class_="list-rst__save-count-num").text    
                holiday = shop.find("span",class_="list-rst__holiday-text").text
                money = shop.find("span",class_="c-rating-v3__val").text
                row_url = shop.select("a")[0].get("href")

                d = {"店舗名":name,"アクセス/ジャンル":acsess,"アピールポイント":strengths,
                    "評価":evaluation,"口コミ数":reviews,"お気に入り数":bookmark,"定休日":holiday,
                    "予算":money,"URL":row_url}
            
            elif shop.find("div",class_="list-rst__pr"):
                name = shop.find("a",class_="list-rst__rst-name-target").text
                acsess = shop.find("div",class_="list-rst__area-genre").text.strip()
                strengths = shop.find("div",class_="list-rst__pr").text.strip()
                evaluation = shop.find("span",class_="c-rating__val").text
                reviews = shop.find("em",class_="list-rst__rvw-count-num").text
                bookmark = shop.find("span",class_="list-rst__save-count-num").text    
                holiday = "記載なし"
                money = shop.find("span",class_="c-rating-v3__val").text
                row_url = shop.select("a")[0].get("href")

                d = {"店舗名":name,"アクセス/ジャンル":acsess,"アピールポイント":strengths,
                    "評価":evaluation,"口コミ数":reviews,"お気に入り数":bookmark,"定休日":holiday,
                    "予算":money,"URL":row_url}
            
            elif shop.find("span",class_="list-rst__holiday-text"):
                name = shop.find("a",class_="list-rst__rst-name-target").text
                acsess = shop.find("div",class_="list-rst__area-genre").text.strip()
                strengths = "記載なし"
                evaluation = shop.find("span",class_="c-rating__val").text
                reviews = shop.find("em",class_="list-rst__rvw-count-num").text
                bookmark = shop.find("span",class_="list-rst__save-count-num").text    
                holiday = shop.find("span",class_="list-rst__holiday-text").text
                money = shop.find("span",class_="c-rating-v3__val").text
                row_url = shop.select("a")[0].get("href")

                d = {"店舗名":name,"アクセス/ジャンル":acsess,"アピールポイント":strengths,
                    "評価":evaluation,"口コミ数":reviews,"お気に入り数":bookmark,"定休日":holiday,
                    "予算":money,"URL":row_url}
            
            else:
                name = shop.find("a",class_="list-rst__rst-name-target").text
                acsess = shop.find("div",class_="list-rst__area-genre").text.strip()
                strengths = "記載なし"
                evaluation = shop.find("span",class_="c-rating__val").text
                reviews = shop.find("em",class_="list-rst__rvw-count-num").text
                bookmark = shop.find("span",class_="list-rst__save-count-num").text    
                holiday = "記載なし"
                money = shop.find("span",class_="c-rating-v3__val").text
                row_url = shop.select("a")[0].get("href")

                d = {"店舗名":name,"アクセス/ジャンル":acsess,"アピールポイント":strengths,
                    "評価":evaluation,"口コミ数":reviews,"お気に入り数":bookmark,"定休日":holiday,
                    "予算":money,"URL":row_url}

            
            d_list.append(d)

      else:
        continue

#CSVファイルに変換
df = pd.DataFrame(d_list)
df2 = df.applymap(lambda x: re.sub('\n', '', x))
df2.to_csv("食べログ高評価.csv",index=None,encoding="utf-8-sig")


# 時間計測終了
time_end = time.perf_counter()
# 経過時間(秒)
tim = time_end- time_sta

print(tim)

自分で試したこと

全体でif文による条件分岐をせずに表示しようとも考え、
if shop.find("div",class_="list-rst__pr"):
strengths = shop.find("div",class_="list-rst__pr").text.strip()
else:
notype = "記載なし"

のような形にし、辞書内でも"アピールポイント":strengths or notype
のようにしましたが、正しくCSVに出力されませんでした。

0

1Answer

スクレイピングは、サイトの管理者に許可を得ているとか、規約に従って専用の API にアクセスしているとかでなければ、迷惑行為になるかもしれないということは認識してますか?

クローラーを作って某図書館サイトにアクセスしたら業務妨害とかで逮捕された事例もありますので、甘く見ない方がいいと思います。

逮捕までいかなくても、被害が深刻な場合は損害賠償の訴訟を受けるかもしれません。

訴訟までいかなくても、アクセス遮断ならWeb サーバーの設定で可能なので、多分に可能性はあると思います。帯域ごと遮断され、あなたのやったことで多数の利用者が巻き添えを喰らうことになるかもしれません。

0Like

Comments

  1. @yuutyoko129

    Questioner

    知ってます。

    規約やrobot.txtを確認した上で行っていますし、コードの長短や内容によってサーバー負荷がかかるかもしれないと思い、当該質問をさせていただいておりますので、質問の回答になっていない回答はやめていただきたいです。

  2. 問題ないと思ってるようだけど、それはあなたの勝手な思い込みでは?

    アクセスする「食べログ」の管理者に「自作アプリでスクレイピングしていい?」と聞いて、許可をもらってない限り、勝手な思い込みとしか言えないのでは。

    逆の立場で、もしあなたが管理者だったとして、どこの誰だか、何をするか分からない人からそう聞かれて、OK って言わないですよね。

  3. @yuutyoko129

    Questioner

    国が調査のためにスクレイピングを利用しているのはご存じでしょうか?
    その時点でやり方によってはスクレイピングは認められるかと。

    逆に、スクレイピングが一切いけないとすると、なぜスクレイピングという技術が存在し、活用されているか説明していただけますでしょうか?

  4. あなたの言う国がやっているというのは具体的にどうしているのか分かりませんが、何にせよ、他人がやっているからあなたがやってもいいということにはなりません。

    逆に、スクレイピングが一切いけないとすると、

    そんなことは一言も言ってません。

  5. @yuutyoko129

    Questioner

    調べて下さい。

    じゃあ、誰であればスクレイピングしても良いんですか?

  6. 調べて下さい。

    それはスクレイピングしたいと言ってるあなたが調べること。

    じゃあ、誰であればスクレイピングしても良いんですか?

    「サイトの管理者に許可を得ているとか、規約に従って専用の API にアクセスしているとか」と言った通りです。

    今回のあなたの場合は、アクセスする「食べログ」の管理者に「自作アプリでスクレイピングしていい?」と聞いて、許可をもらっていたら良いと思いますよ。

    でも、これも言いましたが、逆の立場で、もしあなたが管理者だったとして、どこの誰だか、何をするか分からない人からそう聞かれて、OK って言わないですよね。そういうことです。

  7. @yuutyoko129

    Questioner

    調べた結果、国がしていると言ったので、それが分からないのであれば調べて下さいということです。

    ということは、国はいちいち許可を取ってスクレイピングしていないようなので、ヤバいですね

  8. 次回からスクレイピングする正当な理由を述べてから質問して下さい。

    私は、前回の回答に目を通してくれなかったのが残念です。

    そして、アレルギー体質の方も

    ここはスクレイピングに対して過剰な反応をする方がいますので、回答すべきか、黙認すべきか、躊躇してます。多くの方が激ムズな法解釈を誤解しているのが残念です。

    日本は諸外国に比べ緩いです。
    該当判例はゼロであると判例データベースからの検索結果が物語っているようにゆるゆるです。

    しかしながら、我が国は放置国家?ではなく、明らかに法治国家です。我が国の法の定め、精神に従った行動のみならず、qiitaの趣旨を理解した行動を取りたいものです。

     次回からスクレイピングする正当な理由を述べてから質問すれば、アレルギー体質者との問答は少なくなるかも?

  9. @yuutyoko129

    Questioner

    前回の回答はしっかり拝見しておりましたが、完全に記載が漏れておりましたね。
    ご指摘ありがとうございます🙇

    アレルギー体質者の方のことも考え、次回からスクレイピング理由を忘れずに記載します!(プログラミングの練習と自分用の情報解析にしか使う予定ありませんが、、)

  10. プログラミングの練習と自分用の情報解析にしか使う

    さて、本題です。

    shops = soup.find_all("div",class_="list-rst__wrap js-open-new-window"
    

    list-rst__wrapjs-open-new-windowのOR定義してませんか?そもそも、OR定義できるの?htmlのtagのclassは半角空白で連結でOR定義できます。

    <div class="list-rst__wrap js-open-new-window">...</div>
    <div class="list-rst__wrap">...</div>
    <div class="js-open-new-window">...</div>
    

    その後のshop.findで必ず、検索できるのでしょうか?先ずはlist-rst__wrap
    のみで検索しては?

  11. @yuutyoko129

    Questioner

    ありがとうございます!

    早速試したところ、list-rst__wrapのみで検索出来ました!
    完全に見落としておりました、、

    あとは、2つ目のif文で回す部分はこの記載以外はないですかね??

  12. BeautifulSoup を利用しているなら、 先ずはjsonに変換しては?どうでしょう

  13. @yuutyoko129

    Questioner

    jsonってJavaScriptの言語ですよね?

    まだPythonしか勉強しておらず、JavaScriptが全く分からないに等しいのですが、Python学習においてjsonの知識は必須でしょうか?

  14. Python学習においてjsonの知識は必須でしょうか?

    必須ではないです。しかし、至る所で遭遇することになります。

    また、知らないと折角取得したデータを効率よく管理できませんよ。pandas,dbで管理する方法もありますが。

    なお、短時間にWebサイトに大量にアクセスをすると迷惑となるので、そういうことがないようにプログラムを実行するときには注意してください。

    上記URLからの引用にご留意下さい。

    とともに、良いサンプルを題材にして勉強することを推奨します。

  15. @yuutyoko129

    Questioner

    なるほどですね!
    色々ありがとうございました!

Your answer might help someone💌