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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

1回答

1147閲覧

Swiftを利用して指定のURLから生データをダウンロードできるようにしたい

KeitaSumiya

総合スコア10

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2022/11/10 09:32

前提

指輪型デバイスで取得した心拍や睡眠データを可視化するアプリを作成しようとしています.
同デバイスの開発会社が提供しているAPIではなく, ダウンロード可能なcsv or jsonの生データを元に開発しようと考えています.
ただし, その生データをプログラム上から取得できません.

たとえば,
https://hogehoge1234.com/account/export/sleep/csv (仮のURLです)
というURLにChromeやSafari等のブラウザでアクセスすると,

  1. 同社のユーザアカウントのログイン画面が表示されるので, ID, PWを入力してログイン (初回のみ)
  2. (PC) hogehoge_sleep.csv (約700KB) がダウンロードされる
    (iOS) hogehoge_sleep.csv をどの方法で開くかが表示される

という挙動となります.

そこで, この hogehoge_sleep.csv をiOSアプリなどで自動ダウンロードできるように,

let (data, urlResponse) = try await URLSession.shared.data(from: url)

を実行したのですが, 実際の生データではなく, dataには3592 bytesという文字列が返ってきてしまいました.
仮にこれが文字列ではなく生データだと仮定しても, 本来の約700KBより遥かに少ないため不適です.

データ取得の前にアカウント認証の処理が入ることが原因と考えているのですが,
このような場合に, どう処理していけば良いかがわかりません.

現状, PCの場合は, pythonでブラウザを用いてURLにアクセスすることで生データが自動ダウンロードできるため,
そこからファイル移動させて解析する, という無理やりな手法で仮実装しています.
ただし, スマホで気軽に閲覧できるようにswiftでのアプリ開発を始めたのですが, 上記のデータ取得の時点で躓いている, という状況です.

実現したいこと

  • Swiftを利用して指定のURLから生データをダウンロードできるようにする

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

start to get data <NSHTTPURLResponse: 0x6000033a1800> { URL: https://hogehoge1234.com/user/sign-in?next=%2Faccount%2Fexport%2Fsleep%2Fcsv } { Status Code: 200, Headers { "Cache-Control" = ( "no-cache, no-store, must-revalidate" ); "Content-Encoding" = ( gzip ); "Content-Type" = ( "text/html" ); Date = ( "Thu, 10 Nov 2022 08:49:02 GMT" ); Etag = ( "略" ); Expires = ( "no-cache" ); "Last-Modified" = ( "Wed, 02 Nov 2022 20:16:59 GMT" ); Pragma = ( 0 ); Server = ( AmazonS3 ); "Strict-Transport-Security" = ( "max-age=31536000; includeSubDomains" ); Vary = ( "Accept-Encoding" ); Via = ( "略" ); "content-security-policy" = ( 略 ); "x-amz-cf-id" = ( "略" ); "x-amz-cf-pop" = ( "SEA73-P2", "SEA73-P3" ); "x-cache" = ( "Miss from cloudfront" ); "x-content-type-options" = ( nosniff ); "x-frame-options" = ( DENY ); } } 3592 bytes end to get data

該当のソースコード

swift

1 func getData(){ 2 print("start to get data") 3 Task { 4 await get() 5 print("end to get data") 6 } 7 } 8 9 private func get() async { 10 guard let url = URL(string: "https://hogehoge1234.com/account/export/sleep/csv") else { 11 print("url error") 12 return 13 } 14 15 do { 16 let (data, urlResponse) = try await URLSession.shared.data(from: url) 17 print(urlResponse) 18 print(data) 19 } catch { 20 print("get error") 21 } 22 }

試したこと

上記のコード以外に,

  • sheetでアプリ内ページとして, 当該ページを開く

ということも試したのですが, この場合, 生データ自体はページ上に表示 (下図) されるのですが, そこからどのようにアプリ内にデータを持っていくべきかで躓いています.
share extensionでアプリの選択肢を表示させるなど, ユーザ操作が必要な方法しかないでしょうか...?
イメージ説明

  • PC+pythonで仮実装した際は
webbrowser.open('https://hogehoge1234.com/account/export/sleep/csv', new=0, autoraise=True)

を実行して, ブラウザで当該ページを開き, (無理やりですが) 自動ダウンロードできていました.

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

  • 開発環境
    • Macbook Air (M1 2020) (16GBメモリ, 2TB SSD)
    • MacOS 12.6
    • XCode 14.1
  • 実機
  • iPhone 8, 12等
    • iOS 16.1

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

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

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

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

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

hoshi-takanori

2022/11/10 10:15

> 実際の生データではなく, dataには3592 bytesという文字列が返ってきてしまいました. print(data) するとバイト数を表示しますが、実際には data には 3592 バイト分のデータが入ってる筈です。とりあえず、let array = [UInt8](data) とかして配列に変換してみるとか…。
KeitaSumiya

2022/11/10 12:12

ありがとうございます!! let array = [UInt8](data) して表示すると, 10進数表示でのasciiコードが出てきたため, 文字列変換してみるとhtmlファイルとなりました. ただし, このファイルには同社のページのhead情報が書き込まれていましたが, 肝心のbodyタグの中身は <body> <div id="root"></div> </body> となっており, 生データに関する内容はなさそうでした...
hoshi-takanori

2022/11/10 12:38

ログインページの HTML でしょうけど、body がそれしかないなら React か何かで書かれてる可能性が高いですね。ログイン処理を解析して何とかできる可能性もありますが、そのサイトの利用規約に触れないか確認が必要かも…。
hoshi-takanori

2022/11/10 13:29

あと、 > let array = [UInt8](data) して表示すると, 10進数表示でのasciiコードが出てきたため, 文字列変換してみるとhtmlファイルとなりました. テキストデータと分かってる場合は、let text = String(data: data, encoding: .utf8) でいけるはず。
KeitaSumiya

2022/11/10 13:56

ありがとうございます!! Reactは触ったことないのでわからないですね... ログイン処理の解析は一般的にどのようにやってらっしゃいますか? 規約確認となると, 実際にやらないほうが良いと思いますが, 具体的にどうすればなんとかできるのかと思いまして. pythonのseleniumを使ったスクレイピングのイメージでしょうか?? それともパケットをみるとか...? >let text = String(data: data, encoding: .utf8) いけました!! "やエスケープがついて\"となっていますが, 問題なく変換できてます, swiftだとこうやってencodeするんですねm(_ _)m
hoshi-takanori

2022/11/11 04:37 編集

ログイン処理の解析、やったことないです。普通に HTML の form でベタに書いてあれば簡単ですが、react だと画面は JavaScript で動的に生成されるし、ログイン処理も AJAX でしょうし、やるとしたらブラウザの開発ツールで通信内容を監視することになりますが、それもいつ変更されるか分かりませんし…。 スマホからのログインが想定されてれば、通常そのための Web API が提供されるので解析する必要はないというか、解析の必要がある時点でそもそも真っ当な方法ではない (個人的な利用ならともかく、アプリとして一般公開するには適切な方法とは言いがたい) ということになります。
KeitaSumiya

2022/11/11 06:33

なるほど...ありがとうございます!! 一応, 元々, データ自体については当該の会社に問い合わせて, 「(本質問で扱っているような) データ出力ができますよ」と教えて頂いたものなので, 不当ではないはずです... ただし, 通信内容の解析等までするのはもちろん相手の想定外だと思います. 私的利用を目的としたアプリ開発なので, ブラウザから普通にダウンロードしていけば先の開発には進めるのですが, もう少しユーザ側の手間を減らした手法がわかれば, 今後別の開発において生かせるだろうなと思い, 本質問をした次第です.
guest

回答1

0

解決する可能性は低いかもしれませんが、
URL に ID とパスワードを含めることができないか
調べてみてはいかがでしょうか?

例えば Basic 認証ならば
http://user:password@www.example.com
でログインしつつアクセスできます。

例えば SmartBrain というサイトでは
http://10000.bz/lms/?action=logon&logon=admin&password=password
でログインしつつアクセスできます。

例えば SuperContainer というサイトでは
http://yourServer.com:8020/SuperContainer/Files/testing?username=bob&amp;password=secret
でログインしつつアクセスできます。

こういった方法で
URL に ID とパスワードを含める方法が用意されていれば
解決できそうな気がします。

投稿2022/11/18 01:34

uni2

総合スコア256

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

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

KeitaSumiya

2022/11/18 14:25

ありがとうございます!! 確かにURLに入れてフォームを埋められれば1つ進みますね. 当該のサイトでいけるかわからないですが, まずは試してみます!! ただ, それができたら更に, formのsubmitをswiftで実装する必要がありますが...
uni2

2022/11/21 03:42

恐らくですが、 URL に ID とパスワードを含めることができた場合は アクセスと同時にログイン処理を行うことができると思われます。 つまり、ログインした状態で csv にアクセスできる可能性が高いのです。 含めることができるならば submit を実装する手間は必要ないかと思われます。 ちなみに、含めることができるならば 「?id=aaa&pass=bbb」 といった内容を後ろに付ける可能性が高そうです。 id 部分は login や username かもしれません。 pass 部分は password や secret かもしれません。 いろいろ試すことをおすすめします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問