システム
クローリング
2020.07.31
Pythonのbeautiful soupでウェブサービスを瞬時にクローリングするよー
「airbnbで、ある住所の部屋の全ての金額を取得するクローラー作って欲しいんだけど、今日中に作れる?」
と言われた時。
pythonのbeautiful soupなら可能です。
では、早速作ってみましょう。
その前に実行環境は最近はgoogle colaboratoryというものがありますので、
それを使っていきます。
ここのfileから新規作成をしてクラウド上でpythonを動かすことが可能です。
ではpythonでbeautiful soupを使ってクローリングをしていきます。
まずは、importでおあつらえなものを読み込みます。
# BeautifulSoupを読み込む
from bs4 import BeautifulSoup
import requests
import urllib.parse
#スリープをインポート
from time import sleep
#今回のサイトのドメイン
domain = "https://www.airbnb.com"
#今回の地域(ターゲット)
target_area = "東京都新宿区上落合1丁目"
#encode
target_area_enc = urllib.parse.quote(target_area)
target_areaに入力した住所をクローリングするようにしてみました。
airbnbで上落合1丁目あたりのURLはどうなってるのかを調べてみましょう。
URL構造をみると共に、取得する金額の場所も確認。
# WebサイトのURLを指定
target_url = domain+"/s/"+target_area_enc+"/homes?tab_id=all_tab&refinement_paths%5B%5D=%2Fhomes&source=structured_search_input_header&search_type=search_query&display_currency=JPY"
print("クローリング開始URL(住所検索のURL)")
print(target_url)
print(" ")
print(" ")
print(" ")
こんな感じでしょうか。
ああそうだ..ページネーションの最後の数字のHTMLのclassを把握して
何ページあるかを取得して全てのページを回遊しないといけなかったですね。
# Requestsを利用してWebページを取得する
html = requests.get(target_url)
# パーサーの準備
soup = BeautifulSoup(html.text, 'html.parser')
for link in soup.findAll("a"):
if "/rooms/" in link.get("href"):
print(domain + link.get('href'))
print("このページの部屋の金額")
price_arr = soup.find_all("span", class_="_1p7iugi")
for price in price_arr:
print(price.contents[1])
#全部で何ページあるか
two = soup.find(class_="_i66xk8d")
last_page = two.find_previous_sibling().a.string
print("この検索ページは"+last_page+"ページ存在する")
last_page = int(last_page)
これで、金額の取得と、
一番後ろのページネーションの番号を取れたのでその数だけ
ページネーションをクリックしつつ
金額を取得してけばいいかなと思います。
# BeautifulSoupを読み込む
from bs4 import BeautifulSoup
import requests
import urllib.parse
#スリープをインポート
from time import sleep
#今回のサイトのドメイン
domain = "https://www.airbnb.com"
#今回の地域(ターゲット)
target_area = "東京都新宿区上落合1丁目"
#encode
target_area_enc = urllib.parse.quote(target_area)
# WebサイトのURLを指定
target_url = domain+"/s/"+target_area_enc+"/homes?tab_id=all_tab&refinement_paths%5B%5D=%2Fhomes&source=structured_search_input_header&search_type=search_query&display_currency=JPY"
print("クローリング開始URL(住所検索のURL)")
print(target_url)
print(" ")
print(" ")
print(" ")
# Requestsを利用してWebページを取得する
html = requests.get(target_url)
# パーサーの準備
soup = BeautifulSoup(html.text, 'html.parser')
for link in soup.findAll("a"):
if "/rooms/" in link.get("href"):
print(domain + link.get('href'))
print("このページの部屋の金額")
price_arr = soup.find_all("span", class_="_1p7iugi")
for price in price_arr:
print(price.contents[1])
#全部で何ページあるか
two = soup.find(class_="_i66xk8d")
last_page = two.find_previous_sibling().a.string
print("この検索ページは"+last_page+"ページ存在する")
last_page = int(last_page)
if last_page>1:
print("2ページ以上あるときはページングのURLを全部取得する")
#2ページ目のリンク構造の取得
page2linktag_raw = soup.find(attrs={"data-id":"page-2"}).a.get("href")
split = page2linktag_raw.split('&items_offset=')
page2linktag = split[0]
if split[1] in "&query=":
#後半に&query=があるってことはクエリがoffset以降も存在するということなので連結する
last_query_raw=split[1].split('&query=')
last_query="&query="+ last_query_raw[1]
else:
last_query = ""
for i in range(last_page):
page = i + 2
print(" ")
print (str(page) + "ページ目のクローリングURL")
if page > 1:
offset = (page - 1)*20
else:
offset =""
query_offset = "&items_offset=" + str(offset)
pagenation_link = domain + page2linktag + query_offset
print(pagenation_link)
print("↓↓↓↓"+str(page)+"ページ目の部屋↓↓↓↓↓↓")
#ページングのページもパース準備
html2 = requests.get(pagenation_link)
soup2 = BeautifulSoup(html2.text, 'html.parser')
next_page_html = requests.get(pagenation_link)
for next_link in soup2.findAll("a"):
if "/rooms/" in next_link.get("href"):
print(domain + next_link.get('href'))
print(" ")
print(str(page)+"ページ目の金額")
price_arr2 = soup2.find_all("span", class_="_1p7iugi")
for price2 in price_arr2:
print(price2.contents[1])
こんな感じでしょうか。
では、動くか実行してみます。
取れてますね。
同じ容量で全国の市区町村マスタでeachしてあげれば
全国のairbnbの部屋の金額を取得することも可能です。
ただ、それをやろうとすると当然のようにIPブロックされますので
https://my.apify.com/proxy
このようなサービスを利用すると良いです。
また、弊社ではIPを分散することにより、
飲食系では食べログ、ぐるなび、ひとさら、rettyの全ての飲食店情報を、
人材系の20メディア、それぞれ全情報をクローリング仕切ることが可能であることも確認しています。
(※商用利用していません)