【Python】requestsで返るページ内容がブラウザの実際と異なる場合

- Python -
2020.09.08
Python[パイソン]

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だけとは限りませんが、これで意図した通りに動作するようになるかどうか試してみる価値はあるかと思います。

ヘッダーにUser Agentを設定する

以下へアクセスすると、自分の環境でのユーザーエージェント情報が出力されるので、コピーします。

pythonのrequestsでuser-agent設定

ユーザーエージェント確認サイト - CloudGate

あとは以下のように、resquests.get()のheaders引数にUser-Agent情報を辞書で渡すだけです。

Pythonimport requests
from bs4 import BeautifulSoup

user_agent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 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を設定することでようやく解決しました。

参考PyPI fake-useragent

↑TOP