【Python】requestsで返るページ内容がブラウザの実際と異なる場合
Pythonのrequestsモジュールを使って軽めにスクレイピングをしようと思ったら、
ブラウザで閲覧する時と異なるHTMLが返ってきている...?
というとき。
僕の場合、以下のようにrequests + BeautifulSoupモジュールを使ってとあるECサイトの商品件数を取ろうと思ったら、実際にブラウザでアクセスした時に見える件数とrequestsで返ってきた件数が異なる、という事象が起きました。
Pythonimport requests
from bs4 import BeautifulSoup
response = requests.get('https://xxxxxxx.com')
soup = BeautifulSoup(response.content, 'lxml')
# 商品の"全XX件"を取得
number_of_item = soup.select_one('.number_of_item').text
print(number_of_item)
# 実際には1210件なのに、1213件と返ってくる...
やっかいな点は、いくら時間を置いても一度目に実行した結果が延々と返ってき続け、いつになっても最新の件数が取れなかったことです。
実際にブラウザで見えているものと同じHTMLが返ってくるように奮闘した結果、「User Agent」を適切に設定することで解決しました。
requestsで返ってくるページ内容が実際と異なる場合の対処法
原因がヘッダーのUser Agentだけとは限りませんが、これで意図した通りに動作するようになるかどうか試してみる価値はあるかと思います。
HTTPリクエストヘッダーにUser Agentを設定する
以下へアクセスすると、自分の環境でのユーザーエージェント情報が出力されるので、コピーします。
あとは以下のように、resquests.get()のheaders引数にUser-Agent情報を辞書で渡すだけ。
Pythonimport requests
from bs4 import BeautifulSoup
user_agent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36'
header = {
'User-Agent': user_agent
}
response = requests.get('https://xxxxxxx.com', headers=header)
soup = BeautifulSoup(response.content, 'lxml')
number_of_item = soup.select_one('.number_of_item').text
print(number_of_item)
# これで実際の件数と同じ件数が返ってくるようになった
これでブラウザから見ている情報どおりに返ってくるようになりました。
fake_useragentモジュールを使ってもダメだった
冒頭で示した例のコードは、リクエストヘッダーにUser Agent情報を設定せず実行していましたが、実際には以下5〜8行目のようにfake_useragentモジュールを使ってフェイクの情報を設定していました。
▼ダメだった例
Pythonimport requests
from bs4 import BeautifulSoup
from fake_useragent import UserAgent
user_agent = UserAgent()
header = {
'User-Agent': user_agent.chrome
}
reponse = requests.get('https://xxxxxxx.com', headers=header)
soup = BeautifulSoup(reponse.content, 'lxml')
number_of_item = soup.select_one('.number_of_item').text
print(number_of_item)
# fake_useragentを使ってもダメだった
これでもダメで、実際のUser Agentを設定することでようやく解決。