質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
スクレイピング

スクレイピングとは、公開されているWebサイトからページ内の情報を抽出する技術です。

JSON

JSON(JavaScript Object Notation)は軽量なデータ記述言語の1つである。構文はJavaScriptをベースとしていますが、JavaScriptに限定されたものではなく、様々なソフトウェアやプログラミング言語間におけるデータの受け渡しが行えるように設計されています。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

1回答

5519閲覧

jsonに関するエラー;JSONDecodeError〜(一部省略しています)

jury_new

総合スコア31

スクレイピング

スクレイピングとは、公開されているWebサイトからページ内の情報を抽出する技術です。

JSON

JSON(JavaScript Object Notation)は軽量なデータ記述言語の1つである。構文はJavaScriptをベースとしていますが、JavaScriptに限定されたものではなく、様々なソフトウェアやプログラミング言語間におけるデータの受け渡しが行えるように設計されています。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

1グッド

0クリップ

投稿2020/04/19 12:55

編集2020/04/19 12:58

前提・実現したいこと

jsonにアクセスし住宅ローン金利の情報をスクレイピングしエラーメッセージを改善したいです。
このWebページのcontent-typeヘッダーがjson形式なのでjsonを今回使用しています。

発生している問題・エラーメッセージ

Traceback (most recent call last): File "N.py", line 35, in <module> print(r.json()['header']) File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/requests/models.py", line 898, in json return complexjson.loads(self.text, **kwargs) File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/json/__init__.py", line 357, in loads return _default_decoder.decode(s) File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/json/decoder.py", line 337, in decode obj, end = self.raw_decode(s, idx=_w(s, 0).end()) File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/json/decoder.py", line 355, in raw_decode raise JSONDecodeError("Expecting value", s, err.value) from None json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0) uematsuyuukinoMacBook-Pro:desktop uematsuyuuki$

該当のソースコード

python3

1import requests 2 3url = 'https://www.barclays.co.uk/dss/service/co.uk/mortgages/' + \ 4 'costcalculator/productservice' 5 6session = requests.Session() 7 8session.headers.update({ 9 #there have not formal headers so it is inclued in it 10 'currentState':'default_current_state', 11 'action':'default', 12 'Origin':'https://www.barclays.co.uk', 13 #set referer,user-agent,X-requested-with 14 'Referer':'https://www.barclays.co.uk/mortgages/mortgage-calculator', 15 'User-Agent':'Mozilla/5.0(Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.113 Safari/537.36', 16 'X-Requested-With':'XMLHttpRequest', 17 }) 18estimatedPropertyValue = 500000 19repaymentAmount = 5888 20months = 410 21data = {"header":{"flowId":"0"}, 22 "body": 23 {"wantTo":"BAH", 24 "estimatePropertyValue":estimatedPropertyValue, 25 "borrowAmount":repaymentAmount, 26 "interestOnlyAmount":0, 27 "repaymentAmount":repaymentAmount, 28 "ltv":round(repaymentAmount/estimatedPropertyValue*100), 29 "totalTerm":months, 30 "purchaseType":"Repayment"}} 31 32r = session.post(url,json=data) 33 34#to protect for exceese text that output header 35print(r.json()['header']) 36

試したこと

インターネットで調べたところ、様々なエラー解決方法があることを知り、インデントや隠れ空白文字、全角半角文字、綴りを一通り確認しました。正直なところ、エラーの意味を把握し切れていない部分があります。35行目にExpecting value~
となっていることから引数に問題があるのかと思い、重点的にみていましたが何も改善しておりません。このエラーは引数によるエラーなのでしょうか?それともjson自体に何か問題があるのでしょうか?よろしくお願いいたします。

補足情報(FW/ツールのバージョンなど)

以前別の質問のエラー解決の際なのですがrequestsのバージョンの違いによるエラー(バグ)があったこともあり今回もそのようなことは考えられますでしょうか?僕の憶測ではありますがよろしくお願いいたします。

##ライブラリのバージョン
**requests 2.23.0 **
Package Version


alembic 1.4.2
beautifulsoup4 4.8.2
certifi 2019.11.28
chardet 3.0.4
dataset 1.3.1
docopt 0.6.2
et-xmlfile 1.0.1
idna 2.9
jdcal 1.4.1
Mako 1.1.2
MarkupSafe 1.1.1
openpyxl 2.4.11
pip 20.0.2
python-dateutil 2.8.1
python-editor 1.0.4
records 0.5.3
selenium 3.141.0
setuptools 41.2.0
six 1.14.0
soupsieve 2.0
SQLAlchemy 1.3.15
tablib 1.1.0
urllib3 1.25.8

kotori_a👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

0

あなたがやりたいことを確認させてください。以下の前提として回答します。
(内容)
下記、不動産買入のための借入金の返済プランを計算してくれるページ
Barklays bank mortgage calculator
https://www.barclays.co.uk/mortgages/mortgage-calculator/cost-calculator/#/costresults

このページを手入力ではなく、pythonからパラメータをjsonで直接POSTし、結果をjsonで得たい、
というのがあなたのやりたいことであると推測しました。

1

まず、エラーの内容を確認しましょう。
スタックトレースをたどると

print(r.json()['header'])

のところでエラーが出ていますね?

json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

JSONDecodeErrorは、jsonのパースに失敗したことを意味します。

すなわち、requests.post()の戻り値 r が正しいjsonフォーマットではないということが推測されます。

そこで、requests.post()の戻り値を直接見るために

print(r.json()['header'])

print(r.text)

に変えて実行してみましょう。

すると、

HTML

1<html><head><title>JBWEB0000xx: HTTP Status 400 - </title><style><!--H1 {font-family:Tahoma,Arial,sans-serif

というような、htmlのエラーソースが出てくるはずです。

すなわち、r.json()の段階で、htmlを無理やりjsonデータとしてパースしようとしていたので、JsonDecodeErrorが発生したということがわかります。

2

このHTMLは冒頭がstatus 400となっていますが、
仮に正しいjsonでpostしていたならば、jsonフォーマットでエラーメッセージが返ってくるはず。
たとえば(あなたも試されたかもしれませんが)、ChromeでDevelopers Toolsを開き、calculateボタンを押したときのpostをそのまま開くと

{"header":{"result":"error","systemError":{"errorCode":"DSS_U001","type":"E","severity":"Application","errorMessage":"Technical Error Occurred","validationErrors":[],"contentType":"application/json","channel":"6"}}}

というjsonフォーマットのエラーが返ってきます。

しかし、上記のpythonスクリプトでは、jsonではなく、htmlでエラーが返ってきました。
htmlでエラーが返ってくるということは、postのフォーマット自体が正しくない、ということが推測されます。

ここでpost部分を見ると、

r = session.post(url,json=data)

となっています。

ここが誤りで、requestsでjsonパラメータにデータを渡すときは、辞書ではなく、json文字列を渡さなければなりません。

すなわち、正しくは、

r = session.post(url, json=json.dumps(data))

とします。
または、json文字列ではなく、直接辞書を渡したい場合は、

r = session.post(url, data=data)

というようにdataパラメータに辞書を渡す必要があります。

3

結論から言うと、上記までやっても、正しい計算結果をjsonで得ることはできませんでした。
(cookieを付与してもダメ)
おそらく、postのときに時刻や画面の座標データ等を一緒にサーバーに渡してチェックし、クリックされておらずスクレイピングと判断した場合はエラーを返すようになっているようです。

投稿2020/04/19 15:07

編集2020/04/19 15:23
patapi

総合スコア820

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

jury_new

2020/04/20 00:59

1から丁寧な説明有り難うございます。大変わかりやすい説明でした。 すっきりしました!有り難うございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問