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

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

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

POSTはHTTPプロトコルのリクエストメソッドです。ファイルをアップロードしたときや入力フォームが送信されたときなど、クライアントがデータをサーバに送る際に利用されます。

iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Swift

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

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

Q&A

解決済

2回答

4121閲覧

[Swift]WebページのFORMへPOSTし、結果を配列に保存したい

hameji001

総合スコア639

POST

POSTはHTTPプロトコルのリクエストメソッドです。ファイルをアップロードしたときや入力フォームが送信されたときなど、クライアントがデータをサーバに送る際に利用されます。

iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Swift

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

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

0グッド

0クリップ

投稿2019/01/17 17:40

編集2019/01/18 05:27

iPhoneであるサイトにデータを送信し、結果を取得し配列に保存したいです。

対象サイトは
https://licenseif.mhlw.go.jp/search_isei/ の左側の一般向けの方です。

htmlソースコードより、frameを用いていることを理解し、
実際の表示ページは
-> https://licenseif.mhlw.go.jp/search_isei/jsp/top.jsp
POSTされる先は
-> https://licenseif.mhlw.go.jp/search_isei/jsp/search.do
と判明しています。

POSTされる中身も、

  1. syokusyu
  2. seibetsu
  3. name
  4. expireKey/

の4つと理解しました。

そこで下記のようなテストコードを作りました。
storyboardではNavigationControllerにembedし、
右にUIBarButtonを配置し、実行ボタンをつけました。

Swift

1// ViewController.swift 2import UIKit 3import WebKit 4 5class ViewController: UIViewController, WKNavigationDelegate { 6 7 var webView = WKWebView() 8 9 override func viewDidLoad() { 10 super.viewDidLoad() 11 // Do any additional setup after loading the view, typically from a nib. 12 // frame: CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: self.view.frame.size.height) 13 self.webView = WKWebView() 14 15 let url0 = URL(string: "https://licenseif.mhlw.go.jp/search_isei/jsp/top.jsp") 16 let myRequest = URLRequest(url: url0!) 17 webView.load(myRequest) 18 19 self.view.addSubview(self.webView) 20 } 21 22 @IBAction func naviBtnPressed(_ sender: Any) { 23 webView.evaluateJavaScript("document.documentElement.outerHTML.toString()", 24 completionHandler: { (html: Any?, error: Error?) in 25 //print(html as! String) 26 let htmlSource = html as! String 27 let search = "<input type=\"hidden\" name=\"expireKey\" value=\"" 28 if let range = htmlSource.range(of: search) { 29 let start = range.upperBound 30 let key = htmlSource[htmlSource.index(start, offsetBy: 0)..<htmlSource.index(start, offsetBy: 32)] 31 print("key:", key) 32 33 let postData1 = "shokushu=1&seibetu=1&name=佐藤 大輔&expireKey=(key)" 34 35 var request = URLRequest(url: URL(string: "https://licenseif.mhlw.go.jp/search_isei/jsp/search.do")!) 36 request.httpMethod = "POST" 37 request.httpBody = postData1.data(using: .utf8) 38 39 let task = URLSession.shared.dataTask(with: request, completionHandler: { 40 (data, response, error) in 41 42 if error != nil { 43 print(error!) 44 return 45 } 46 47 print("response: (response!)") 48 let phpOutput = String(data: data!, encoding: .utf8)! 49 print("php output: (phpOutput)") 50 }) 51 task.resume() 52 } else { 53 print("文字列は見つかりませんでした。") 54 } 55 }) 56 } 57}

しかし、うまく取得できません。
swiftのコードよりも、htmlのFORMのPOSTがうまくできていなく?感じます。
search.doのコードの中身が見えないので、
そもそもPOSTできないって場合もありえますか?
アドバイス等いただけると嬉しいです。

P.S.関係ないですが、結果の氏名を画像で返してくるあたりいやらしいですよね(^_^;)
取得しずらくしているつもりなのかな?

【追記】

肝心の得られた結果を記載していませんでした。

Swift

1key: 1efe6c8cf197023f1641ddf9c91bf92 2response: Optional(<NSHTTPURLResponse: 0x280f515a0> { URL: https://licenseif.mhlw.go.jp/search_isei/jsp/search.do } { Status Code: 200, Headers { 3 "Cache-Control" = ( 4 "no-cache" 5 ); 6 Connection = ( 7 "Keep-Alive" 8 ); 9 "Content-Language" = ( 10 "ja-JP" 11 ); 12 "Content-Length" = ( 13 3420 14 ); 15 "Content-Type" = ( 16 "text/html;charset=Windows-31J" 17 ); 18 Date = ( 19 "Fri, 18 Jan 2019 05:21:20 GMT" 20 ); 21 Expires = ( 22 "Fri, 18 Jan 2019 05:21:20 GMT" 23 ); 24 "Keep-Alive" = ( 25 "timeout=5, max=100" 26 ); 27 Pragma = ( 28 "no-cache" 29 ); 30 "Set-Cookie" = ( 31 "JSESSIONID=D8EBAB81912A6B31218C7C6A4BE3DA96; Path=/search_isei; HttpOnly", 32 "TS0148a66e=01819adb30e42012537fe353de47362bb469da438beb99be39aef16250f355c70dcc11ba00; Path=/", 33 "TS013eb5f3=01819adb304b861905bd8b996036dbf97689182c6641d41ff8eee0131c0c776fd953ef6a92a65e7b3bd9fa491789ade01730b1c3c1; path=/search_isei" 34 ); 35} }) 36data:Optional(3420 bytes) 37(lldb) 38 39// となり、以下の行にエラーが吐かれます。 40let phpOutput = String(data: data!, encoding: .utf8)! 41Thread 11: Fatal error: Unexpectedly found nil while unwrapping an Optional value

dataに3420 bytesもデータがあるのに、nilが見つかるのは、
encodingが間違っているからですか?
"Content-Type" = ("text/html;charset=Windows-31J")
と返答がくることを考えると、utf8ではなく、
windows-31Jでencodeしなきゃいけないと言うことでしょうか?

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

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

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

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

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

fuzzball

2019/01/18 04:48

氏名の完全一致で検索するのに、結果の氏名が画像であることになにか問題でも?
hameji001

2019/01/18 05:06

いや、結果的に問題はないんですが、 結果も文字列なら、データを配列に一度に登録しやすいなと思ったまでです。
fuzzball

2019/01/18 05:29

>>utf8ではなく、windows-31Jでencodeしなきゃいけないと言うことでしょうか? してみれば分かることでは?
hameji001

2019/01/18 05:37

おっしゃる通りなんですが、 https://ja.stackoverflow.com/questions/32636/swift3%E3%81%A7sjis%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%9Furl%E3%82%A8%E3%83%B3%E3%82%B3%E3%83%BC%E3%83%89%E3%82%92%E3%81%97%E3%81%9F%E3%81%84 上記サイトの extension String.Encoding { static let windows31j = **** } を用いて今も行おうとしていますが、うまく変換の書き方がわからなく、 格闘中で、ヒントをいただけないかと期待して、聞いてしまいました。 すみません。
hameji001

2019/01/18 05:43

と言ってる側から let phpOutput = String(data: data!, encoding: String.Encoding.windows31J)! と書くことで、結果をうまく得ることができました!!!
fuzzball

2019/01/18 07:05

解決したようなのでアレですが、とりあえず確認する程度であれば .shiftJIS でいけるんじゃないかと思いまして、いけたら真面目にwindows-31J対応する、という流れで考えていました。
guest

回答2

0

外部から叩いていいかという問題が一番懸念されますが、そこはクリアされているのでしょうか?
以前図書館のシステムを外部から叩いて結果的に逮捕された方がいらっしゃった気がしたので、お気をつけください。

参考:
岡崎市立中央図書館事件

HTTPはよくわからないですが、少なくともフォームでPOSTする事と同等の処理はしないとダメそうという事は言えるかと思います。

引用:パーセントエンコーディング

HTTPのPOSTメソッドでWebフォームの文字列を送信する場合に、文字列はエンコードして送信される。その際の符号化方法はMIMEのContent-Typeがapplication/x-www-form-urlencodedで指定される。この符号化方法をURLエンコードと言うことがある。

によるとPOSTでも文字列はパーセントエンコードした方が良さそうなのと、
Content-Typeもapplication/x-www-form-urlencodedに指定しないと駄目かなと思われます。

P.S.関係ないですが、結果の氏名を画像で返してくるあたりいやらしいですよね(^_^;)
取得しずらくしているつもりなのかな?

国が作っているシステムであれば、名前を正式名称で正しく表示するために画像化しているという推測もできます(異体字、結合文字を利用者側で正しく表示できるとは限らないため)。

投稿2019/01/18 02:17

takabosoft

総合スコア8356

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

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

hameji001

2019/01/18 05:58

回答ありがとうございます。 takabosoftさんの回答により、なんかと実現にまでたどり着けました。 とはいえ、「そんな氏名の人はいません」と言う結果でしたので、 もしかしたら、最初の送る際のエンコードもwindows31Jで送るべきなのかもしれません。 それはおいおいちょっと試してみます。 アクセスに関しては、 ブラウザから入力して、結果を得るのと同じつもりで、 ユーザーに入力してもらったものからアクセスするつもりですが、 外部から叩いてると判定されてしまいますよね。 定期実行の常駐プログラムにはするつもりはないので、 頻度はユーザーが検索した毎、 毎回違うIPアドレスからにはなりそうですが、、、 厳密にいえば、きっとダメですよね、、、 また考え直します。 とても参考になりましたが、今回はベストアンサーに選ばなくてすみません。
guest

0

自己解決

なんとか、無事に結果を得ることができました。
途中いくつか修正を要しました。

takabosoftさんの指摘の通り、POSTの中身を%エンコードディングにする必要があった。
また、

Swift

1request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")

を追記した。

その他、判明したことはexpireKeyの長さが、アクセス毎に変わることがあるため、
keyの抽出に工夫が必要(開始点はOKだが、終了点を長めにとり、「"」以降を除くようにコードすることが必要。)

他に返答に"Content-Type" = ("text/html;charset=Windows-31J")とあったので、
.utf8でencodeではなく、windows31Jにする必要があった。

最後に、takabosoftさんの指摘通り、
これを実際に使えるかは、外部からアクセスしていいかと言う問題があるので、
再度よく検討します。

ちなみに、POSTの%エンコーディングもWindows-31Jで行う必要がありました。
それによりきちんとした検索結果のソースがデバッグエリアに表示されるようになりました。

投稿2019/01/18 05:51

編集2019/01/18 09:04
hameji001

総合スコア639

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問